diff options
Diffstat (limited to 'calendar/gui')
46 files changed, 4057 insertions, 2578 deletions
diff --git a/calendar/gui/GNOME_Evolution_Calendar.server.in.in b/calendar/gui/GNOME_Evolution_Calendar.server.in.in index 801cada120..09f424f69a 100644 --- a/calendar/gui/GNOME_Evolution_Calendar.server.in.in +++ b/calendar/gui/GNOME_Evolution_Calendar.server.in.in @@ -1,6 +1,6 @@ <oaf_info> -<oaf_server iid="OAFIID:GNOME_Evolution_Calendar_Factory" +<oaf_server iid="OAFIID:GNOME_Evolution_Calendar_Factory_2" type="shlib" location="@COMPONENTDIR@/libevolution-calendar.so"> @@ -15,7 +15,7 @@ <oaf_server iid="OAFIID:GNOME_Evolution_Calendar_iTip_Control" type="factory" - location="OAFIID:GNOME_Evolution_Calendar_Factory"> + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> <oaf_attribute name="repo_ids" type="stringv"> <item value="IDL:Bonobo/Control:1.0"/> @@ -31,26 +31,20 @@ _value="Evolution Calendar scheduling message viewer"/> </oaf_server> -<oaf_server iid="OAFIID:GNOME_Evolution_Calendar_ShellComponent" +<oaf_server iid="OAFIID:GNOME_Evolution_Calendar_Component" type="factory" - location="OAFIID:GNOME_Evolution_Calendar_Factory"> + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:GNOME/Evolution/ShellComponent:1.0"/> + <item value="IDL:GNOME/Evolution/Component:1.0"/> </oaf_attribute> - <oaf_attribute name="name" type="string" - _value="Evolution Calendar and Tasks component"/> - - <oaf_attribute name="evolution:shell_component_icon" type="string" - value="evolution-calendar.png"/> - <oaf_attribute name="evolution:shell_component_launch_order" type="number" - value="3"/> + <oaf_attribute name="name" type="string" _value="Evolution's Calendar component"/> </oaf_server> <oaf_server iid="OAFIID:GNOME_Evolution_Calendar_Control" type="factory" - location="OAFIID:GNOME_Evolution_Calendar_Factory"> + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> <oaf_attribute name="repo_ids" type="stringv"> <item value="IDL:BonoboControl/calendar-control:1.0"/> @@ -68,7 +62,7 @@ <oaf_server iid="OAFIID:GNOME_Evolution_Tasks_Control" type="factory" - location="OAFIID:GNOME_Evolution_Calendar_Factory"> + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> <oaf_attribute name="repo_ids" type="stringv"> <item value="IDL:BonoboControl/tasks-control:1.0"/> @@ -86,7 +80,7 @@ <oaf_server iid="OAFIID:GNOME_Evolution_Calendar_CompEditorFactory" type="factory" - location="OAFIID:GNOME_Evolution_Calendar_Factory"> + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> <oaf_attribute name="repo_ids" type="stringv"> <item value="IDL:GNOME/Evolution/Calendar/CompEditorFactory:1.0"/> @@ -99,7 +93,7 @@ <oaf_server iid="OAFIID:GNOME_Evolution_Calendar_ConfigControl" type="factory" - location="OAFIID:GNOME_Evolution_Calendar_Factory"> + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> <oaf_attribute name="repo_ids" type="stringv"> <item value="IDL:GNOME/Evolution/ConfigControl:1.0"/> diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index 3ee9362b65..19edf95953 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -169,6 +169,8 @@ libevolution_calendar_la_SOURCES = \ itip-utils.c \ itip-utils.h \ main.c \ + migration.c \ + migration.h \ misc.c \ misc.h \ print.c \ @@ -189,7 +191,8 @@ libevolution_calendar_la_LIBADD = \ $(top_builddir)/calendar/gui/dialogs/libcal-dialogs.la \ $(top_builddir)/widgets/e-timezone-dialog/libetimezonedialog.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ - $(top_builddir)/a11y/calendar/libevolution-calendar-a11y.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/a11y/calendar/libevolution-calendar-a11y.la \ $(EVOLUTION_CALENDAR_LIBS) libevolution_calendar_la_LDFLAGS = -avoid-version -module diff --git a/calendar/gui/alarm-notify/alarm-notify.c b/calendar/gui/alarm-notify/alarm-notify.c index 133448e7cd..006533c6bf 100644 --- a/calendar/gui/alarm-notify/alarm-notify.c +++ b/calendar/gui/alarm-notify/alarm-notify.c @@ -31,26 +31,6 @@ -/* A loaded client */ -typedef struct { - /* The actual client */ - CalClient *client; - - /* The URI of the client in gnome-vfs's format. This *is* the key that - * is stored in the uri_client_hash hash table below. - */ - EUri *uri; - - /* Number of times clients have requested this URI to be added to the - * alarm notification system. - */ - int refcount; - - /* the ID of the retry timeout function - */ - int timeout_id; -} LoadedClient; - /* Private part of the AlarmNotify structure */ struct _AlarmNotifyPrivate { /* Mapping from EUri's to LoadedClient structures */ @@ -105,23 +85,7 @@ alarm_notify_init (AlarmNotify *an, AlarmNotifyClass *klass) priv = g_new0 (AlarmNotifyPrivate, 1); an->priv = priv; - priv->uri_client_hash = g_hash_table_new (g_str_hash, g_str_equal); -} - -/* Callback used from g_hash-table_forach(), used to destroy a loade client */ -static void -destroy_loaded_client_cb (gpointer key, gpointer value, gpointer data) -{ - LoadedClient *lc; - char *str_uri; - - str_uri = key; - lc = value; - - g_free (str_uri); - g_object_unref (G_OBJECT (lc->client)); - e_uri_free (lc->uri); - g_free (lc); + priv->uri_client_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } /* Finalize handler for the alarm notify system */ @@ -137,13 +101,9 @@ alarm_notify_finalize (GObject *object) an = ALARM_NOTIFY (object); priv = an->priv; - g_hash_table_foreach (priv->uri_client_hash, destroy_loaded_client_cb, NULL); - g_hash_table_destroy (priv->uri_client_hash); - priv->uri_client_hash = NULL; g_free (priv); - an->priv = NULL; if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); @@ -193,21 +153,15 @@ free_uris (GPtrArray *uris) /* Adds an URI to the list of calendars to load on startup */ static void -add_uri_to_load (EUri *uri) +add_uri_to_load (const char *str_uri) { - char *str_uri; GPtrArray *loaded_uris; int i; - /* Canonicalize the URI */ - str_uri = e_uri_to_string (uri, FALSE); - g_assert (str_uri != NULL); - loaded_uris = get_calendars_to_load (); if (!loaded_uris) { g_message ("add_uri_to_load(): Could not get the list of calendars to load; " "will not add `%s'", str_uri); - g_free (str_uri); return; } @@ -219,12 +173,11 @@ add_uri_to_load (EUri *uri) * calendars. */ if (i != -1) { - g_free (str_uri); free_uris (loaded_uris); return; } - g_ptr_array_add (loaded_uris, str_uri); + g_ptr_array_add (loaded_uris, g_strdup (str_uri)); save_calendars_to_load (loaded_uris); free_uris (loaded_uris); @@ -232,29 +185,22 @@ add_uri_to_load (EUri *uri) /* Removes an URI from the list of calendars to load on startup */ static void -remove_uri_to_load (EUri *uri) +remove_uri_to_load (const char *str_uri) { - char *str_uri; GPtrArray *loaded_uris; char *loaded_uri; int i; - /* Canonicalize the URI */ - str_uri = e_uri_to_string (uri, FALSE); - g_assert (str_uri != NULL); - loaded_uris = get_calendars_to_load (); if (!loaded_uris) { g_message ("remove_uri_to_load(): Could not get the list of calendars to load; " "will not add `%s'", str_uri); - g_free (str_uri); return; } /* Look for the URI in the list of calendars to load */ i = find_uri_index (loaded_uris, str_uri); - g_free (str_uri); /* If we didn't find it, there is no need to remove it */ if (i == -1) { @@ -291,61 +237,19 @@ AlarmNotify_removeCalendar (PortableServer_Servant servant, { AlarmNotify *an; AlarmNotifyPrivate *priv; - LoadedClient *lc; - EUri *uri; - char *orig_str; - gpointer lc_ptr, orig_str_ptr; - gboolean found; - - lc_ptr = NULL; - orig_str_ptr = NULL; + CalClient *client; an = ALARM_NOTIFY (bonobo_object_from_servant (servant)); priv = an->priv; - uri = e_uri_new (str_uri); - if (!uri) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_InvalidURI, - NULL); - return; - } + client = g_hash_table_lookup (priv->uri_client_hash, str_uri); + if (client) { + alarm_queue_remove_client (client); - remove_uri_to_load (uri); - - found = g_hash_table_lookup_extended (priv->uri_client_hash, str_uri, - &orig_str_ptr, - &lc_ptr); - orig_str = orig_str_ptr; - lc = lc_ptr; - - e_uri_free (uri); - - if (!lc) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_NotFound, - NULL); - return; + g_hash_table_remove (priv->uri_client_hash, str_uri); } - g_assert (lc->refcount > 0); - - lc->refcount--; - if (lc->refcount > 0) - return; - - g_hash_table_remove (priv->uri_client_hash, str_uri); - - g_free (orig_str); - g_signal_handlers_disconnect_matched (lc->client, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, lc); - if (lc->timeout_id != -1) - g_source_remove (lc->timeout_id); - alarm_queue_remove_client (lc->client); - g_object_unref (G_OBJECT (lc->client)); - e_uri_free (lc->uri); - g_free (lc); + remove_uri_to_load (str_uri); } @@ -367,40 +271,6 @@ alarm_notify_new (void) return an; } -static gboolean -retry_timeout_cb (gpointer data) -{ - LoadedClient *lc = data; - char *str_uri; - - if (cal_client_get_load_state (lc->client) != CAL_CLIENT_LOAD_LOADED) { - str_uri = e_uri_to_string (lc->uri, FALSE); - cal_client_open_calendar (lc->client, str_uri, FALSE); - - g_free (str_uri); - } - - return FALSE; -} - -static void -cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) -{ - LoadedClient *lc = (LoadedClient *) data; - - if (status == CAL_CLIENT_OPEN_SUCCESS) { - add_uri_to_load (lc->uri); - alarm_queue_add_client (client); - lc->timeout_id = -1; - } - else { - remove_uri_to_load (lc->uri); - - /* we set a timeout of 5 mins before retrying */ - lc->timeout_id = g_timeout_add (300000, (GSourceFunc) retry_timeout_cb, lc); - } -} - /** * alarm_notify_add_calendar: * @an: An alarm notification service. @@ -418,10 +288,7 @@ alarm_notify_add_calendar (AlarmNotify *an, const char *str_uri, gboolean load_a CORBA_Environment *ev) { AlarmNotifyPrivate *priv; - EUri *uri; CalClient *client; - LoadedClient *lc; - gpointer lc_ptr, s_ptr; g_return_if_fail (an != NULL); g_return_if_fail (IS_ALARM_NOTIFY (an)); @@ -430,49 +297,23 @@ alarm_notify_add_calendar (AlarmNotify *an, const char *str_uri, gboolean load_a priv = an->priv; - uri = e_uri_new (str_uri); - if (!uri) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_InvalidURI, - NULL); + /* See if we already know about this uri */ + if (g_hash_table_lookup (priv->uri_client_hash, str_uri)) return; - } - if (g_hash_table_lookup_extended (priv->uri_client_hash, str_uri, &s_ptr, &lc_ptr)) { - lc = lc_ptr; - lc->refcount++; - } else { - client = cal_client_new (); - - if (client) { - /* we only add the URI to load_afterwards if we open it - correctly */ - lc = g_new (LoadedClient, 1); - lc->client = client; - lc->uri = uri; - lc->refcount = 1; - lc->timeout_id = -1; - - - g_signal_connect (G_OBJECT (client), "cal_opened", - G_CALLBACK (cal_opened_cb), - lc); - - if (cal_client_open_calendar (client, str_uri, FALSE)) { - g_hash_table_insert (priv->uri_client_hash, - g_strdup (str_uri), lc); - } else { - g_free (lc); - g_object_unref (G_OBJECT (client)); - client = NULL; - } - } else { - e_uri_free (uri); - - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_BackendContactError, - NULL); - return; + client = cal_client_new (str_uri, CALOBJ_TYPE_EVENT); + + if (client) { + if (cal_client_open (client, FALSE, NULL)) { + add_uri_to_load (str_uri); + + g_hash_table_insert (priv->uri_client_hash, + g_strdup (str_uri), client); } + } else { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_GNOME_Evolution_Calendar_AlarmNotify_BackendContactError, + NULL); + return; } } diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c index cb792e466f..cee17bd97e 100644 --- a/calendar/gui/alarm-notify/alarm-queue.c +++ b/calendar/gui/alarm-notify/alarm-queue.c @@ -227,7 +227,7 @@ remove_queued_alarm (CompQueuedAlarms *cqa, gpointer alarm_id, if (remove_alarm) { cqa->expecting_update = TRUE; cal_client_discard_alarm (cqa->parent_client->client, cqa->alarms->comp, - qa->instance->auid); + qa->instance->auid, NULL); cqa->expecting_update = FALSE; } diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c index c0d1b3c589..77305098bc 100644 --- a/calendar/gui/calendar-commands.c +++ b/calendar/gui/calendar-commands.c @@ -59,6 +59,7 @@ #include "goto.h" #include "print.h" #include "dialogs/cal-prefs-dialog.h" +#include "dialogs/new-calendar.h" #include "itip-utils.h" #include "evolution-shell-component-utils.h" @@ -73,6 +74,68 @@ typedef struct { guint taskpad_focused : 1; } FocusData; +static void +file_new_calendar_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + new_calendar_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gcal)))); +} + +static void +file_new_appointment_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + time_t dtstart, dtend; + ECalView *cal_view; + + gcal = GNOME_CALENDAR (data); + + cal_view = (ECalView *) gnome_calendar_get_current_view_widget (gcal); + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, FALSE); +} + +static void +file_new_event_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + time_t dtstart, dtend; + ECalView *cal_view; + + gcal = GNOME_CALENDAR (data); + + cal_view = (ECalView *) gnome_calendar_get_current_view_widget (gcal); + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, TRUE, FALSE); +} + +static void +file_new_meeting_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + time_t dtstart, dtend; + ECalView *cal_view; + + gcal = GNOME_CALENDAR (data); + + cal_view = (ECalView *) gnome_calendar_get_current_view_widget (gcal); + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, TRUE); +} + +static void +file_new_task_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + gnome_calendar_new_task (gcal); +} + /* Prints the calendar at its current view and time range */ static void print (GnomeCalendar *gcal, gboolean preview) @@ -335,12 +398,10 @@ publish_freebusy_cmd (BonoboUIComponent *uic, gpointer data, const gchar *path) start = time_day_begin_with_zone (start, utc); end = time_add_week_with_zone (start, 6, utc); + /* FIXME Should we aggregate the data? */ client_list = e_cal_model_get_client_list (gnome_calendar_get_calendar_model (gcal)); for (cl = client_list; cl != NULL; cl = cl->next) { - GList *tmp_comp_list; - - tmp_comp_list = cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end); - if (tmp_comp_list) { + if (cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -599,19 +660,42 @@ control_util_show_settings (GnomeCalendar *gcal) * is FALSE, all will be disabled. Otherwise, the currently-selected number of * events will be used. */ -static void -sensitize_calendar_commands (GnomeCalendar *gcal, BonoboControl *control, gboolean enable) +void +calendar_control_sensitize_calendar_commands (BonoboControl *control, GnomeCalendar *gcal, gboolean enable) { BonoboUIComponent *uic; + ECalViewEvent *event; + GList *list; int n_selected; - gboolean read_only, has_recurrences; + GtkWidget *view; + CalClient *cal_client; + gboolean read_only = FALSE, has_recurrences; uic = bonobo_control_get_ui_component (control); g_assert (uic != NULL); - n_selected = enable ? gnome_calendar_get_num_events_selected (gcal) : 0; - read_only = cal_client_is_read_only (e_cal_model_get_default_client (gnome_calendar_get_calendar_model (gcal))); + view = gnome_calendar_get_current_view_widget (gcal); + list = e_cal_view_get_selected_events (E_CAL_VIEW (view)); + + n_selected = enable ? g_list_length (list) : 0; + event = (ECalViewEvent *) list ? list->data : NULL; + if (event) { + cal_client_is_read_only (event->comp_data->client, &read_only, NULL); + } else { + cal_client = e_cal_model_get_default_client (gnome_calendar_get_calendar_model (gcal)); + if (cal_client) + cal_client_is_read_only (cal_client, &read_only, NULL); + else + read_only = TRUE; + } + + bonobo_ui_component_set_prop (uic, "/commands/NewAppointment", "sensitive", + read_only ? "0" : "1", NULL); + bonobo_ui_component_set_prop (uic, "/commands/NewAllDayEvent", "sensitive", + read_only ? "0" : "1", NULL); + bonobo_ui_component_set_prop (uic, "/commands/NewMeeting", "sensitive", + read_only ? "0" : "1", NULL); bonobo_ui_component_set_prop (uic, "/commands/Cut", "sensitive", n_selected == 0 || read_only ? "0" : "1", NULL); @@ -628,19 +712,8 @@ sensitize_calendar_commands (GnomeCalendar *gcal, BonoboControl *control, gboole /* occurrence-related menu items */ has_recurrences = FALSE; if (n_selected > 0 && !read_only) { - ECalViewEvent *event; - GList *list; - GtkWidget *view; - - view = gnome_calendar_get_current_view_widget (gcal); - list = e_cal_view_get_selected_events (E_CAL_VIEW (view)); if (list) { event = (ECalViewEvent *) list->data; - g_list_free (list); - } else - event = NULL; - - if (event) { if (cal_util_component_has_recurrences (event->comp_data->icalcomp)) has_recurrences = TRUE; } @@ -652,6 +725,10 @@ sensitize_calendar_commands (GnomeCalendar *gcal, BonoboControl *control, gboole bonobo_ui_component_set_prop (uic, "/commands/DeleteAllOccurrences", "sensitive", has_recurrences ? "1" : "0", NULL); + + /* free memory */ + if (list) + g_list_free (list); } /* Sensitizes the UI Component menu/toolbar tasks commands based on the number @@ -663,14 +740,21 @@ sensitize_taskpad_commands (GnomeCalendar *gcal, BonoboControl *control, gboolea { BonoboUIComponent *uic; int n_selected; - gboolean read_only; + CalClient *cal_client; + gboolean read_only = TRUE; uic = bonobo_control_get_ui_component (control); g_assert (uic != NULL); n_selected = enable ? gnome_calendar_get_num_tasks_selected (gcal) : 0; - read_only = cal_client_is_read_only (gnome_calendar_get_task_pad_cal_client (gcal)); - + cal_client = gnome_calendar_get_task_pad_cal_client (gcal); + if (cal_client) + cal_client_is_read_only (cal_client, &read_only, NULL); + else + read_only = TRUE; + + bonobo_ui_component_set_prop (uic, "/commands/NewTask", "sensitive", + read_only ? "0" : "1", NULL); bonobo_ui_component_set_prop (uic, "/commands/Cut", "sensitive", n_selected == 0 || read_only ? "0" : "1", NULL); @@ -705,7 +789,7 @@ gcal_calendar_selection_changed_cb (GnomeCalendar *gcal, gpointer data) control = BONOBO_CONTROL (data); - sensitize_calendar_commands (gcal, control, TRUE); + calendar_control_sensitize_calendar_commands (control, gcal, TRUE); } /* Callback used when the selection in the taskpad changes */ @@ -734,13 +818,13 @@ gcal_calendar_focus_change_cb (GnomeCalendar *gcal, gboolean in, gpointer data) if (in) { g_signal_connect (gcal, "calendar_selection_changed", G_CALLBACK (gcal_calendar_selection_changed_cb), control); - sensitize_calendar_commands (gcal, control, TRUE); + calendar_control_sensitize_calendar_commands (control, gcal, TRUE); focus->calendar_focused = TRUE; } else if (focus->calendar_focused) { gtk_signal_disconnect_by_func (GTK_OBJECT (gcal), G_CALLBACK (gcal_calendar_selection_changed_cb), control); - sensitize_calendar_commands (gcal, control, FALSE); + calendar_control_sensitize_calendar_commands (control, gcal, FALSE); focus->calendar_focused = FALSE; } } @@ -779,6 +863,11 @@ gcal_taskpad_focus_change_cb (GnomeCalendar *gcal, gboolean in, gpointer data) static BonoboUIVerb verbs [] = { + BONOBO_UI_VERB ("NewCalendar", file_new_calendar_cb), + BONOBO_UI_VERB ("NewAppointment", file_new_appointment_cb), + BONOBO_UI_VERB ("NewAllDayEvent", file_new_event_cb), + BONOBO_UI_VERB ("NewMeeting", file_new_meeting_cb), + BONOBO_UI_VERB ("NewTask", file_new_task_cb), BONOBO_UI_VERB ("CalendarPrint", file_print_cb), BONOBO_UI_VERB ("CalendarPrintPreview", file_print_preview_cb), @@ -808,11 +897,15 @@ static BonoboUIVerb verbs [] = { static EPixmap pixmaps [] = { - E_PIXMAP ("/Toolbar/DayView", "buttons/dayview.xpm"), - E_PIXMAP ("/Toolbar/WorkWeekView", "buttons/workweekview.xpm"), - E_PIXMAP ("/Toolbar/WeekView", "buttons/weekview.xpm"), - E_PIXMAP ("/Toolbar/MonthView", "buttons/monthview.xpm"), - E_PIXMAP ("/Toolbar/ListView", "buttons/listview.xpm"), + E_PIXMAP ("/commands/NewAppointment", "new_appointment.xpm"), + E_PIXMAP ("/commands/NewAllDayEvent", "new_all_day_event.png"), + E_PIXMAP ("/commands/NewMeeting", "meeting-request-16.png"), + E_PIXMAP ("/commands/NewTask", "new_task-16.png"), + E_PIXMAP ("/Toolbar/DayView", "buttons/dayview.xpm"), + E_PIXMAP ("/Toolbar/WorkWeekView", "buttons/workweekview.xpm"), + E_PIXMAP ("/Toolbar/WeekView", "buttons/weekview.xpm"), + E_PIXMAP ("/Toolbar/MonthView", "buttons/monthview.xpm"), + E_PIXMAP ("/Toolbar/ListView", "buttons/listview.xpm"), E_PIXMAP_END }; @@ -855,7 +948,7 @@ calendar_control_activate (BonoboControl *control, g_signal_connect (gcal, "taskpad_focus_change", G_CALLBACK (gcal_taskpad_focus_change_cb), control); - sensitize_calendar_commands (gcal, control, FALSE); + calendar_control_sensitize_calendar_commands (control, gcal, FALSE); sensitize_taskpad_commands (gcal, control, FALSE); bonobo_ui_component_thaw (uic, NULL); diff --git a/calendar/gui/calendar-commands.h b/calendar/gui/calendar-commands.h index 6f418799d2..3e74074140 100644 --- a/calendar/gui/calendar-commands.h +++ b/calendar/gui/calendar-commands.h @@ -38,6 +38,8 @@ GnomeCalendar *new_calendar (void); void calendar_control_activate (BonoboControl *control, GnomeCalendar *gcal); void calendar_control_deactivate (BonoboControl *control, GnomeCalendar *gcal); +void calendar_control_sensitize_calendar_commands (BonoboControl *control, GnomeCalendar *gcal, gboolean enable); + void calendar_goto_today (GnomeCalendar *gcal); void calendar_set_folder_bar_label (GnomeCalendar *gcal, BonoboControl *control); diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c index 98f0964cc4..3e8782f45b 100644 --- a/calendar/gui/calendar-component.c +++ b/calendar/gui/calendar-component.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* component-factory.c +/* calendar-component.c * - * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc. + * Copyright (C) 2003 Ettore Perazzoli * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -20,752 +20,269 @@ * Author: Ettore Perazzoli <ettore@ximian.com> */ +#ifdef CONFIG_H #include <config.h> +#endif -#include <errno.h> -#include <libgnome/gnome-util.h> -#include <libgnomevfs/gnome-vfs-types.h> -#include <libgnomevfs/gnome-vfs-uri.h> -#include <libgnomevfs/gnome-vfs-ops.h> -#include <libgnomevfs/gnome-vfs-directory.h> -#include <libgnomevfs/gnome-vfs-file-info.h> - -#include <bonobo/bonobo-generic-factory.h> -#include <bonobo/bonobo-context.h> -#include <bonobo/bonobo-exception.h> - -#include "evolution-shell-component.h" -#include "calendar-offline-handler.h" #include "calendar-component.h" -#include "tasks-control.h" #include "control-factory.h" -#include "calendar-config.h" -#include "tasks-control.h" -#include "e-comp-editor-registry.h" -#include "dialogs/comp-editor.h" - - -/* OAFIID for the component. */ -#define COMPONENT_ID "OAFIID:GNOME_Evolution_Calendar_ShellComponent" - -/* Folder type IDs */ -#define FOLDER_CALENDAR "calendar" -#define FOLDER_TASKS "tasks" -#define FOLDER_PUBLIC_CALENDAR "calendar/public" -#define FOLDER_PUBLIC_TASKS "tasks/public" - -/* IDs for user creatable items */ -#define CREATE_EVENT_ID "event" -#define CREATE_ALLDAY_EVENT_ID "allday-event" -#define CREATE_MEETING_ID "meeting" -#define CREATE_TASK_ID "task" - -char *evolution_dir = NULL; -EvolutionShellClient *global_shell_client = NULL; -extern ECompEditorRegistry *comp_editor_registry; - -static const EvolutionShellComponentFolderType folder_types[] = { - { FOLDER_CALENDAR, - "evolution-calendar.png", - N_("Calendar"), - N_("Folder containing appointments and events"), - TRUE, NULL, NULL }, - { FOLDER_PUBLIC_CALENDAR, - "evolution-calendar.png", - N_("Public Calendar"), - N_("Public folder containing appointments and events"), - FALSE, NULL, NULL }, - { FOLDER_TASKS, - "evolution-tasks.png", - N_("Tasks"), - N_("Folder containing to-do items"), - TRUE, NULL, NULL }, - { FOLDER_PUBLIC_TASKS, - "evolution-tasks.png", - N_("Public Tasks"), - N_("Public folder containing to-do items"), - FALSE, NULL, NULL }, - { NULL, NULL } -}; +#include "gnome-cal.h" +#include "migration.h" - - -static inline gboolean -type_is_calendar (const char *type) -{ - return !strcmp (type, FOLDER_CALENDAR) || - !strcmp (type, FOLDER_PUBLIC_CALENDAR); -} +#include "widgets/misc/e-source-selector.h" -static inline gboolean -type_is_tasks (const char *type) -{ - return !strcmp (type, FOLDER_TASKS) || - !strcmp (type, FOLDER_PUBLIC_TASKS); -} +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-i18n.h> +#include <gal/util/e-util.h> -/* EvolutionShellComponent methods and signals. */ +#include <errno.h> -static EvolutionShellComponentResult -create_view (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const char *view_info, - BonoboControl **control_return, - void *closure) -{ - BonoboControl *control; - - if (type_is_calendar (type)) { - control = control_factory_new_control (); - if (!control) - return EVOLUTION_SHELL_COMPONENT_CORBAERROR; - } else if (type_is_tasks (type)) { - control = tasks_control_new (); - if (!control) - return EVOLUTION_SHELL_COMPONENT_CORBAERROR; - } else { - return EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE; - } - bonobo_control_set_property (control, NULL, "folder_uri", TC_CORBA_string, physical_uri, NULL); - if (type_is_calendar (type) && *view_info) - bonobo_control_set_property (control, NULL, "view", TC_CORBA_string, view_info, NULL); +#define PARENT_TYPE bonobo_object_get_type () +static BonoboObjectClass *parent_class = NULL; - *control_return = control; - return EVOLUTION_SHELL_COMPONENT_OK; -} +struct _CalendarComponentPrivate { + char *config_directory; -static void -create_folder (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) -{ - CORBA_Environment ev; - GnomeVFSURI *uri; + GConfClient *gconf_client; + ESourceList *source_list; +}; - CORBA_exception_init (&ev); - if (!type_is_calendar (type) && !type_is_tasks (type)) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - CORBA_exception_free (&ev); - return; - } +/* Utility functions. */ - uri = gnome_vfs_uri_new (physical_uri); - if (uri) { - /* we don't need to do anything */ - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_OK, &ev); - gnome_vfs_uri_unref (uri); - } - else { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - } +static void +load_uri_for_source (ESource *source, BonoboControl *view_control) +{ + GnomeCalendar *gcal; + char *uri = e_source_get_uri (source); - CORBA_exception_free (&ev); + gcal = (GnomeCalendar *) bonobo_control_get_widget (view_control); + gnome_calendar_add_event_uri (gcal, uri); + g_free (uri); } -/* Asks the alarm daemon to stop monitoring the specified URI */ static void -stop_alarms (GnomeVFSURI *uri) +load_uri_for_selection (ESourceSelector *selector, BonoboControl *view_control) { - char *str_uri; - CORBA_Environment ev; - GNOME_Evolution_Calendar_AlarmNotify an; - - /* Activate the alarm notification service */ - - CORBA_exception_init (&ev); - an = bonobo_activation_activate_from_id ("OAFIID:GNOME_Evolution_Calendar_AlarmNotify", 0, NULL, &ev); - - if (BONOBO_EX (&ev)) { - g_message ("stop_alarms(): Could not activate the alarm notification service"); - CORBA_exception_free (&ev); - return; - } - CORBA_exception_free (&ev); - - /* Ask the service to remove the URI from its list of calendars */ - - str_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); - g_assert (str_uri != NULL); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_AlarmNotify_removeCalendar (an, str_uri, &ev); - g_free (str_uri); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_AlarmNotify_InvalidURI)) { - g_message ("stop_alarms(): Invalid URI reported from the alarm notification service"); - } else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_AlarmNotify_NotFound)) { - /* This is OK; the service may not have loaded that calendar */ - } else if (BONOBO_EX (&ev)) { - g_message ("stop_alarms(): Could not issue the removeCalendar request"); - } + GSList *selection, *l; - CORBA_exception_free (&ev); - - /* Get rid of the service */ - - CORBA_exception_init (&ev); - bonobo_object_release_unref (an, &ev); - if (BONOBO_EX (&ev)) - g_message ("stop_alarms(): Could not unref the alarm notification service"); - CORBA_exception_free (&ev); + selection = e_source_selector_get_selection (selector); + for (l = selection; l; l = l->next) { + ESource *selected_source = l->data; + + load_uri_for_source (selected_source, view_control); + } } +/* Callbacks. */ static void -remove_folder (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) +source_selection_changed_callback (ESourceSelector *selector, + BonoboControl *view_control) { - GnomeVFSURI *dir_uri, *data_uri, *backup_uri; - GnomeVFSResult data_result, backup_result; - - /* check type */ - if (!type_is_calendar (type) && !type_is_tasks (type)) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener of " - "an unsupported folder type"); + + load_uri_for_selection (selector, view_control); +} - CORBA_exception_free (&ev); - return; - } +static void +primary_source_selection_changed_callback (ESourceSelector *selector, + BonoboControl *view_control) +{ + ESource *source; + GnomeCalendar *gcal; + ECalModel *model; + CalClient *client; - /* check URI */ - dir_uri = gnome_vfs_uri_new (physical_uri); - if (!dir_uri) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - CORBA_exception_free (&ev); + source = e_source_selector_peek_primary_selection (selector); + if (!source) return; - } - /* Compute the URIs of the appropriate files */ - - if (type_is_calendar (type)) { - data_uri = gnome_vfs_uri_append_file_name (dir_uri, "calendar.ics"); - backup_uri = gnome_vfs_uri_append_file_name (dir_uri, "calendar.ics~"); - } else if (type_is_tasks (type)) { - data_uri = gnome_vfs_uri_append_file_name (dir_uri, "tasks.ics"); - backup_uri = gnome_vfs_uri_append_file_name (dir_uri, "tasks.ics~"); - } else { - g_assert_not_reached (); + /* set the default client on the GnomeCalendar */ + gcal = (GnomeCalendar *) bonobo_control_get_widget (view_control); + if (!GNOME_IS_CALENDAR (gcal)) return; - } - - if (!data_uri || !backup_uri) { - CORBA_Environment ev; - - g_message ("remove_folder(): Could not generate the data/backup URIs"); - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener " - "of an invalid URI"); - - CORBA_exception_free (&ev); - - goto out; - } - - /* Ask the alarm daemon to stop monitoring this URI */ - - stop_alarms (data_uri); - - /* Delete the data and backup files; the shell will take care of the rest */ - - data_result = gnome_vfs_unlink_from_uri (data_uri); - backup_result = gnome_vfs_unlink_from_uri (backup_uri); - - if ((data_result == GNOME_VFS_OK || data_result == GNOME_VFS_ERROR_NOT_FOUND) - && (backup_result == GNOME_VFS_OK || backup_result == GNOME_VFS_ERROR_NOT_FOUND)) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_OK, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener about success"); - - CORBA_exception_free (&ev); - } else { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener about failure"); - - CORBA_exception_free (&ev); - } - out: - - gnome_vfs_uri_unref (dir_uri); - - if (data_uri) - gnome_vfs_uri_unref (data_uri); - - if (backup_uri) - gnome_vfs_uri_unref (backup_uri); + model = gnome_calendar_get_calendar_model (gcal); + client = e_cal_model_get_client_for_uri (model, e_source_get_uri (source)); + if (client) + gnome_calendar_set_default_client (gcal, client); } -static GNOME_Evolution_ShellComponentListener_Result -xfer_file (GnomeVFSURI *base_src_uri, - GnomeVFSURI *base_dest_uri, - const char *file_name, - int remove_source) -{ - GnomeVFSURI *src_uri, *dest_uri; - GnomeVFSHandle *hin, *hout; - GnomeVFSResult result; - GnomeVFSFileInfo file_info; - GnomeVFSFileSize size; - char *buffer; - - src_uri = gnome_vfs_uri_append_file_name (base_src_uri, file_name); - - result = gnome_vfs_open_uri (&hin, src_uri, GNOME_VFS_OPEN_READ); - if (result == GNOME_VFS_ERROR_NOT_FOUND) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_OK; /* No need to xfer anything. */ - } - if (result != GNOME_VFS_OK) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } - - result = gnome_vfs_get_file_info_uri (src_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT); - if (result != GNOME_VFS_OK) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } - - dest_uri = gnome_vfs_uri_append_file_name (base_dest_uri, file_name); - - result = gnome_vfs_create_uri (&hout, dest_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0600); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } +/* GObject methods. */ - /* write source file to destination file */ - buffer = g_malloc (file_info.size); - result = gnome_vfs_read (hin, buffer, file_info.size, &size); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } +static void +impl_dispose (GObject *object) +{ + CalendarComponentPrivate *priv = CALENDAR_COMPONENT (object)->priv; - result = gnome_vfs_write (hout, buffer, file_info.size, &size); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; + if (priv->source_list != NULL) { + g_object_unref (priv->source_list); + priv->source_list = NULL; } - if (remove_source) { - char *text_uri; - - /* Sigh, we have to do this as there is no gnome_vfs_unlink_uri(). :-( */ - - text_uri = gnome_vfs_uri_to_string (src_uri, GNOME_VFS_URI_HIDE_NONE); - result = gnome_vfs_unlink (text_uri); - g_free (text_uri); + if (priv->gconf_client != NULL) { + g_object_unref (priv->gconf_client); + priv->gconf_client = NULL; } - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - - return GNOME_Evolution_ShellComponentListener_OK; + (* G_OBJECT_CLASS (parent_class)->dispose) (object); } static void -xfer_folder (EvolutionShellComponent *shell_component, - const char *source_physical_uri, - const char *destination_physical_uri, - const char *type, - gboolean remove_source, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) +impl_finalize (GObject *object) { - CORBA_Environment ev; - GnomeVFSURI *src_uri; - GnomeVFSURI *dest_uri; - GnomeVFSResult result; - char *filename, *backup_filename; - - CORBA_exception_init (&ev); - - /* check type */ - if (!type_is_calendar (type) && !type_is_tasks (type)) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - CORBA_exception_free (&ev); - return; - } - - /* check URIs */ - src_uri = gnome_vfs_uri_new (source_physical_uri); - dest_uri = gnome_vfs_uri_new (destination_physical_uri); - if (!src_uri || ! dest_uri) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - CORBA_exception_free (&ev); - return; - } - - if (type_is_calendar (type)) { - filename = "calendar.ics"; - backup_filename = "calendar.ics~"; - } else if (type_is_tasks (type)) { - filename = "tasks.ics"; - backup_filename = "tasks.ics~"; - } else { - g_assert_not_reached (); - return; - } - - result = xfer_file (src_uri, dest_uri, filename, remove_source); - if (result == GNOME_Evolution_ShellComponentListener_OK) - result = xfer_file (src_uri, dest_uri, backup_filename, remove_source); - - GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); + CalendarComponentPrivate *priv = CALENDAR_COMPONENT (object)->priv; - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); + g_free (priv->config_directory); + g_free (priv); - CORBA_exception_free (&ev); + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } -static gboolean -request_quit (EvolutionShellComponent *shell_component, void *closure) -{ - return e_comp_editor_registry_close_all (comp_editor_registry); -} -static void -owner_set_cb (EvolutionShellComponent *shell_component, - EvolutionShellClient *shell_client, - const char *evolution_homedir, - gpointer user_data) -{ - if (evolution_dir) - g_free (evolution_dir); - evolution_dir = g_strdup (evolution_homedir); - global_shell_client = shell_client; -} +/* Evolution::Component CORBA methods. */ static void -owner_unset_cb (EvolutionShellComponent *shell_component, - gpointer user_data) +impl_createControls (PortableServer_Servant servant, + Bonobo_Control *corba_sidebar_control, + Bonobo_Control *corba_view_control, + CORBA_Environment *ev) { - global_shell_client = NULL; -} + CalendarComponent *calendar_component = CALENDAR_COMPONENT (bonobo_object_from_servant (servant)); + GtkWidget *selector; + GtkWidget *selector_scrolled_window; + BonoboControl *sidebar_control; + BonoboControl *view_control; -/* Computes the final URI for a calendar component */ -static char * -get_data_uri (const char *uri, CalComponentVType vtype) -{ - if (uri) { - if (*uri != '/' && strncmp (uri, "file:", 5) != 0) - return g_strdup (uri); - - if (vtype == CAL_COMPONENT_EVENT) - return cal_util_expand_uri ((char *) uri, FALSE); - else if (vtype == CAL_COMPONENT_TODO) - return cal_util_expand_uri ((char *) uri, TRUE); - else - g_assert_not_reached (); - } else { - if (vtype == CAL_COMPONENT_EVENT) - return g_concat_dir_and_file (g_get_home_dir (), - "evolution/local/Calendar/calendar.ics"); - else if (vtype == CAL_COMPONENT_TODO) - return g_concat_dir_and_file (g_get_home_dir (), - "evolution/local/Tasks/tasks.ics"); - else - g_assert_not_reached (); - } + selector = e_source_selector_new (calendar_component->priv->source_list); + gtk_widget_show (selector); - return NULL; -} + selector_scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (selector_scrolled_window), selector); + gtk_widget_show (selector_scrolled_window); -/* Creates a calendar component at a specified URI. If the URI is NULL then it - * uses the default folder for that type of component. - */ -static void -create_component (const char *uri, GNOME_Evolution_Calendar_CompEditorFactory_CompEditorMode type) -{ - char *real_uri; - CORBA_Environment ev; - GNOME_Evolution_Calendar_CompEditorFactory factory; - CalComponentVType vtype; - - switch (type) { - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT: - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT: - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING: - vtype = CAL_COMPONENT_EVENT; - break; - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO: - vtype = CAL_COMPONENT_TODO; - break; - default: - g_assert_not_reached (); - return; - } + sidebar_control = bonobo_control_new (selector_scrolled_window); - real_uri = get_data_uri (uri, vtype); + view_control = control_factory_new_control (); - /* Get the factory */ + g_signal_connect_object (selector, "selection_changed", + G_CALLBACK (source_selection_changed_callback), + G_OBJECT (view_control), 0); + g_signal_connect_object (selector, "primary_selection_changed", + G_CALLBACK (primary_source_selection_changed_callback), + G_OBJECT (view_control), 0); - CORBA_exception_init (&ev); - factory = bonobo_activation_activate_from_id ("OAFIID:GNOME_Evolution_Calendar_CompEditorFactory", - 0, NULL, &ev); + load_uri_for_selection (E_SOURCE_SELECTOR (selector), view_control); - if (BONOBO_EX (&ev)) { - g_message ("create_component(): Could not activate the component editor factory"); - CORBA_exception_free (&ev); - g_free (real_uri); - return; - } - CORBA_exception_free (&ev); + *corba_sidebar_control = CORBA_Object_duplicate (BONOBO_OBJREF (sidebar_control), ev); + *corba_view_control = CORBA_Object_duplicate (BONOBO_OBJREF (view_control), ev); +} - /* Create the item */ - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_CompEditorFactory_editNew (factory, real_uri, type, &ev); +/* Initialization. */ - if (BONOBO_EX (&ev)) - g_message ("create_component(): Exception while creating the component"); +static void +calendar_component_class_init (CalendarComponentClass *class) +{ + POA_GNOME_Evolution_Component__epv *epv = &class->epv; + GObjectClass *object_class = G_OBJECT_CLASS (class); - CORBA_exception_free (&ev); - g_free (real_uri); + parent_class = g_type_class_peek_parent (class); - /* Get rid of the factory */ + epv->createControls = impl_createControls; - CORBA_exception_init (&ev); - bonobo_object_release_unref (factory, &ev); - if (BONOBO_EX (&ev)) - g_message ("create_component(): Could not unref the calendar component factory"); + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; - CORBA_exception_free (&ev); + epv->createControls = impl_createControls; } -/* Callback used when we must create a user-creatable item */ static void -sc_user_create_new_item_cb (EvolutionShellComponent *shell_component, - const char *id, - const char *parent_folder_physical_uri, - const char *parent_folder_type) +calendar_component_init (CalendarComponent *component) { - char *tmp_uri; - - if (strcmp (id, CREATE_EVENT_ID) == 0) { - if (type_is_calendar (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT); - else { - tmp_uri = calendar_config_default_calendar_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT); - g_free (tmp_uri); - } - } else if (strcmp (id, CREATE_ALLDAY_EVENT_ID) == 0) { - if (type_is_calendar (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT); - else { - tmp_uri = calendar_config_default_calendar_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT); - g_free (tmp_uri); - } - } else if (strcmp (id, CREATE_MEETING_ID) == 0) { - if (type_is_calendar (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING); - else { - tmp_uri = calendar_config_default_calendar_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING); - g_free (tmp_uri); + CalendarComponentPrivate *priv; + GSList *groups; + + priv = g_new0 (CalendarComponentPrivate, 1); + + priv->config_directory = g_build_filename (g_get_home_dir (), + ".evolution", "calendar", "config", + NULL); + + /* EPFIXME: Should use a custom one instead? Also we should add + * calendar_component_peek_gconf_client(). */ + priv->gconf_client = gconf_client_get_default (); + + priv->source_list = e_source_list_new_for_gconf (priv->gconf_client, + "/apps/evolution/calendar/sources"); + + /* create default calendars if there are no groups */ + groups = e_source_list_peek_groups (priv->source_list); + if (!groups) { + ESourceGroup *group; + ESource *source; + char *base_uri, *new_dir; + + /* create the source group */ + base_uri = g_build_filename (g_get_home_dir (), + "/.evolution/calendar/local/OnThisComputer/", + NULL); + group = e_source_group_new (_("On This Computer"), base_uri); + e_source_list_add_group (priv->source_list, group, -1); + + /* migrate calendars from older setup */ + if (!migrate_old_calendars (group)) { + /* create default calendars */ + new_dir = g_build_filename (base_uri, "Personal/", NULL); + if (!e_mkdir_hier (new_dir, 0700)) { + source = e_source_new (_("Personal"), "Personal"); + e_source_group_add_source (group, source, -1); + } + g_free (new_dir); + + new_dir = g_build_filename (base_uri, "Work/", NULL); + if (!e_mkdir_hier (new_dir, 0700)) { + source = e_source_new (_("Work"), "Work"); + e_source_group_add_source (group, source, -1); + } + g_free (new_dir); } - } else if (strcmp (id, CREATE_TASK_ID) == 0) { - if (type_is_tasks (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO); - else { - tmp_uri = calendar_config_default_tasks_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO); - g_free (tmp_uri); - } - } else - g_assert_not_reached (); -} - -/* The factory function. */ - -static void -add_creatable_item (EvolutionShellComponent *shell_component, - const char *id, - const char *description, - const char *menu_description, - const char *tooltip, - const char *folder_type, - char menu_shortcut, - const char *icon_name) -{ - char *icon_path; - GdkPixbuf *icon; - - if (icon_name == NULL) { - icon_path = NULL; - icon = NULL; - } else { - icon_path = g_concat_dir_and_file (EVOLUTION_IMAGESDIR, icon_name); - icon = gdk_pixbuf_new_from_file (icon_path, NULL); + g_free (base_uri); } - evolution_shell_component_add_user_creatable_item (shell_component, - id, - description, - menu_description, - tooltip, - folder_type, - menu_shortcut, - icon); - - if (icon != NULL) - gdk_pixbuf_unref (icon); - g_free (icon_path); + component->priv = priv; } -static BonoboObject * -create_object (void) -{ - EvolutionShellComponent *shell_component; - CalendarOfflineHandler *offline_handler; - - shell_component = evolution_shell_component_new (folder_types, - NULL, - create_view, - create_folder, - remove_folder, - xfer_folder, - NULL, /* populate_folder_context_menu_fn */ - NULL, /* unpopulate_folder_context_menu_fn */ - NULL, /* get_dnd_selection_fn */ - request_quit, - NULL /* closure */); - - /* Offline handler */ - offline_handler = calendar_offline_handler_new (); - bonobo_object_add_interface (BONOBO_OBJECT (shell_component), - BONOBO_OBJECT (offline_handler)); - - g_signal_connect (shell_component, "owner_set", G_CALLBACK (owner_set_cb), NULL); - g_signal_connect (shell_component, "owner_unset", G_CALLBACK (owner_unset_cb), NULL); - - /* User creatable items */ - add_creatable_item (shell_component, CREATE_EVENT_ID, - _("New appointment"), _("_Appointment"), - _("Create a new appointment"), - FOLDER_CALENDAR, 'a', "new_appointment.xpm"); +/* Public API. */ - add_creatable_item (shell_component, CREATE_MEETING_ID, - _("New meeting"), _("M_eeting"), - _("Create a new meeting request"), - FOLDER_CALENDAR, 'e', "meeting-request-16.png"); - - add_creatable_item (shell_component, CREATE_TASK_ID, - _("New task"), _("_Task"), - _("Create a new task"), - FOLDER_TASKS, 't', "new_task-16.png"); +CalendarComponent * +calendar_component_peek (void) +{ + static CalendarComponent *component = NULL; - add_creatable_item (shell_component, CREATE_ALLDAY_EVENT_ID, - _("New All Day Appointment"), _("All _Day Appointment"), - _("Create a new all-day appointment"), - FOLDER_CALENDAR, 'd', "new_all_day_event.png"); + if (component == NULL) { + component = g_object_new (calendar_component_get_type (), NULL); - g_signal_connect (shell_component, "user_create_new_item", - G_CALLBACK (sc_user_create_new_item_cb), NULL); + if (e_mkdir_hier (calendar_component_peek_config_directory (component), 0777) != 0) { + g_warning ("Cannot create directory %s: %s", + calendar_component_peek_config_directory (component), + g_strerror (errno)); + g_object_unref (component); + component = NULL; + } + } - return BONOBO_OBJECT (shell_component); + return component; } - -BonoboObject * -calendar_component_get_object (void) +const char * +calendar_component_peek_config_directory (CalendarComponent *component) { - static BonoboObject *object = NULL; + return component->priv->config_directory; +} - if (object != NULL) { - bonobo_object_ref (BONOBO_OBJECT (object)); - } else { - object = create_object (); - g_object_add_weak_pointer (G_OBJECT (object), (void *) &object); - } - return object; -} +BONOBO_TYPE_FUNC_FULL (CalendarComponent, GNOME_Evolution_Component, PARENT_TYPE, calendar_component) diff --git a/calendar/gui/calendar-component.h b/calendar/gui/calendar-component.h index 2d94920adc..96630add5f 100644 --- a/calendar/gui/calendar-component.h +++ b/calendar/gui/calendar-component.h @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* component-factory.h +/* calendar-component.h * - * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc. + * Copyright (C) 2003 Ettore Perazzoli * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -20,13 +20,47 @@ * Author: Ettore Perazzoli <ettore@ximian.com> */ -#ifndef _COMPONENT_FACTORY_H_ -#define _COMPONENT_FACTORY_H_ +#ifndef _CALENDAR_COMPONENT_H_ +#define _CALENDAR_COMPONENT_H_ + #include <bonobo/bonobo-object.h> -extern char *evolution_dir; +#include "Evolution.h" +#include "e-util/e-source-list.h" + + +#define CALENDAR_TYPE_COMPONENT (calendar_component_get_type ()) +#define CALENDAR_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALENDAR_TYPE_COMPONENT, CalendarComponent)) +#define CALENDAR_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALENDAR_TYPE_COMPONENT, CalendarComponentClass)) +#define CALENDAR_IS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALENDAR_TYPE_COMPONENT)) +#define CALENDAR_IS_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), CALENDAR_TYPE_COMPONENT)) + + +typedef struct _CalendarComponent CalendarComponent; +typedef struct _CalendarComponentPrivate CalendarComponentPrivate; +typedef struct _CalendarComponentClass CalendarComponentClass; + +struct _CalendarComponent { + BonoboObject parent; + + CalendarComponentPrivate *priv; +}; + +struct _CalendarComponentClass { + BonoboObjectClass parent_class; + + POA_GNOME_Evolution_Component__epv epv; +}; + + +GType calendar_component_get_type (void); + +CalendarComponent *calendar_component_peek (void); + +const char *calendar_component_peek_config_directory (CalendarComponent *component); + +ESourceList *calendar_component_peek_source_list (CalendarComponent *component); -BonoboObject *calendar_component_get_object (void); -#endif /* _COMPONENT_FACTORY_H_ */ +#endif /* _CALENDAR_COMPONENT_H_ */ diff --git a/calendar/gui/calendar-offline-handler.c b/calendar/gui/calendar-offline-handler.c index 458f951d9a..ff30299746 100644 --- a/calendar/gui/calendar-offline-handler.c +++ b/calendar/gui/calendar-offline-handler.c @@ -29,6 +29,7 @@ #include <gtk/gtkmain.h> #include <gtk/gtksignal.h> #include <bonobo/bonobo-exception.h> +#include <bonobo/bonobo-i18n.h> #include <gal/util/e-util.h> #include "e-util/e-url.h" #include <cal-client/cal-client.h> @@ -180,13 +181,16 @@ backend_go_offline (gpointer data, gpointer user_data) char *uri = data; CalClient *client; gboolean success; + GError *error = NULL; - client = cal_client_new (); + client = cal_client_new (uri, CALOBJ_TYPE_ANY); g_signal_connect (client, "cal_opened", G_CALLBACK (backend_cal_opened_offline), offline_handler); - success = cal_client_open_calendar (client, uri, TRUE); + success = cal_client_open (client, TRUE, &error); if (!success) { + g_warning (_("backend_go_offline(): %s"), error->message); update_offline (offline_handler); g_object_unref (client); + g_error_free (error); return; } } @@ -198,13 +202,16 @@ backend_go_online (gpointer data, gpointer user_data) char *uri = data; CalClient *client; gboolean success; + GError *error = NULL; - client = cal_client_new (); + client = cal_client_new (uri, CALOBJ_TYPE_ANY); g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (backend_cal_opened_online), offline_handler); - success = cal_client_open_calendar (client, uri, TRUE); + success = cal_client_open (client, TRUE, &error); if (!success) { + g_warning (_("backend_go_online(): %s"), error->message); g_object_unref (G_OBJECT (client)); + g_error_free (error); return; } } @@ -319,7 +326,8 @@ calendar_offline_handler_init (CalendarOfflineHandler *offline_handler) priv = g_new (CalendarOfflineHandlerPrivate, 1); offline_handler->priv = priv; - priv->client = cal_client_new (); + /* FIXME: what URI to use? */ + priv->client = cal_client_new ("", CALOBJ_TYPE_ANY); priv->listener_interface = CORBA_OBJECT_NIL; priv->is_offline = FALSE; } diff --git a/calendar/gui/comp-editor-factory.c b/calendar/gui/comp-editor-factory.c index f76e0d4f03..7b7dcb4c87 100644 --- a/calendar/gui/comp-editor-factory.c +++ b/calendar/gui/comp-editor-factory.c @@ -241,39 +241,26 @@ edit_existing (OpenClient *oc, const char *uid) { CalComponent *comp; icalcomponent *icalcomp; - CalClientGetStatus status; CompEditor *editor; CalComponentVType vtype; g_assert (oc->open); /* Get the object */ + if (!cal_client_get_object (oc->client, uid, NULL, &icalcomp, NULL)) { + /* FIXME Better error handling */ + g_warning (G_STRLOC ": Syntax error while getting component `%s'", uid); - status = cal_client_get_object (oc->client, uid, &icalcomp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - g_object_unref (comp); - icalcomponent_free (icalcomp); - return; - } - break; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object disappeared from the server */ - return; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("edit_exiting(): Syntax error while getting component `%s'", uid); return; - - default: - g_assert_not_reached (); + } + + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); return; } - + /* Create the appropriate type of editor */ vtype = cal_component_get_vtype (comp); @@ -405,13 +392,15 @@ resolve_pending_requests (OpenClient *oc) factory = oc->factory; priv = factory->priv; - g_assert (oc->pending != NULL); + if (!oc->pending) + return; /* Set the default timezone in the backend. */ location = calendar_config_get_timezone (); zone = icaltimezone_get_builtin_timezone (location); if (zone) - cal_client_set_default_timezone (oc->client, zone); + /* FIXME Error handling? */ + cal_client_set_default_timezone (oc->client, zone, NULL); for (l = oc->pending; l; l = l->next) { Request *request; @@ -501,10 +490,11 @@ open_client (CompEditorFactory *factory, const char *uristr) CompEditorFactoryPrivate *priv; CalClient *client; OpenClient *oc; + GError *error = NULL; priv = factory->priv; - client = cal_client_new (); + client = cal_client_new (uristr, CALOBJ_TYPE_ANY); if (!client) return NULL; @@ -522,10 +512,12 @@ open_client (CompEditorFactory *factory, const char *uristr) g_hash_table_insert (priv->uri_client_hash, oc->uri, oc); - if (!cal_client_open_calendar (oc->client, uristr, FALSE)) { + if (!cal_client_open (oc->client, FALSE, &error)) { + g_warning (_("open_client(): %s"), error->message); g_free (oc->uri); g_object_unref (oc->client); g_free (oc); + g_error_free (error); return NULL; } diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c index 28bc66bd54..aceff667c2 100644 --- a/calendar/gui/comp-util.c +++ b/calendar/gui/comp-util.c @@ -95,7 +95,6 @@ cal_comp_util_compare_event_timezones (CalComponent *comp, CalClient *client, icaltimezone *zone) { - CalClientGetStatus status; CalComponentDateTime start_datetime, end_datetime; const char *tzid; gboolean retval = FALSE; @@ -143,10 +142,8 @@ cal_comp_util_compare_event_timezones (CalComponent *comp, /* If the TZIDs differ, we have to compare the UTC offsets of the start and end times, using their own timezones and the given timezone. */ - status = cal_client_get_timezone (client, - start_datetime.tzid, - &start_zone); - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (client, start_datetime.tzid, + &start_zone, NULL)) goto out; if (start_datetime.value) { @@ -160,10 +157,8 @@ cal_comp_util_compare_event_timezones (CalComponent *comp, goto out; } - status = cal_client_get_timezone (client, - end_datetime.tzid, - &end_zone); - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (client, end_datetime.tzid, + &end_zone, NULL)) goto out; if (end_datetime.value) { @@ -210,8 +205,8 @@ gboolean cal_comp_is_on_server (CalComponent *comp, CalClient *client) { const char *uid; - CalClientGetStatus status; icalcomponent *icalcomp; + GError *error = NULL; g_return_val_if_fail (comp != NULL, FALSE); g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE); @@ -226,24 +221,15 @@ cal_comp_is_on_server (CalComponent *comp, CalClient *client) */ cal_component_get_uid (comp, &uid); - status = cal_client_get_object (client, uid, &icalcomp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: + if (cal_client_get_object (client, uid, NULL, &icalcomp, &error)) { icalcomponent_free (icalcomp); - return TRUE; - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("confirm_delete_empty_appointment(): Syntax error when getting " - "object `%s'", - uid); return TRUE; + } - case CAL_CLIENT_GET_NOT_FOUND: - return FALSE; - - default: - g_assert_not_reached (); + if (error) { + g_warning ("cal_comp_is_on_server(): %s", error->message); + g_error_free (error); } return FALSE; @@ -268,7 +254,7 @@ cal_comp_event_new_with_defaults (CalClient *client) icalproperty *icalprop; CalAlarmTrigger trigger; - if (cal_client_get_default_object (client, CALOBJ_TYPE_EVENT, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_default_object (client, &icalcomp, NULL)) return NULL; comp = cal_component_new (); @@ -334,8 +320,16 @@ cal_comp_task_new_with_defaults (CalClient *client) CalComponent *comp; icalcomponent *icalcomp; - if (cal_client_get_default_object (client, CALOBJ_TYPE_TODO, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_default_object (client, &icalcomp, NULL)) + return NULL; + + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return NULL; + } comp = cal_component_new (); if (!cal_component_set_icalcomponent (comp, icalcomp)) { diff --git a/calendar/gui/control-factory.c b/calendar/gui/control-factory.c index 191a8d85ea..7adc5e83df 100644 --- a/calendar/gui/control-factory.c +++ b/calendar/gui/control-factory.c @@ -69,8 +69,11 @@ get_prop (BonoboPropertyBag *bag, CORBA_Environment *ev, gpointer user_data) { - GnomeCalendar *gcal = user_data; + GnomeCalendar *gcal; const char *uri; + BonoboControl *control = user_data; + + gcal = (GnomeCalendar *) bonobo_control_get_widget (control); switch (arg_id) { @@ -96,6 +99,7 @@ get_prop (BonoboPropertyBag *bag, case GNOME_CAL_LIST_VIEW: BONOBO_ARG_SET_STRING (arg, "list"); break; + default: } break; @@ -104,7 +108,6 @@ get_prop (BonoboPropertyBag *bag, } } - static void set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, @@ -112,14 +115,19 @@ set_prop (BonoboPropertyBag *bag, CORBA_Environment *ev, gpointer user_data) { - GnomeCalendar *gcal = user_data; + GnomeCalendar *gcal; char *string; GnomeCalendarViewType view; + BonoboControl *control = user_data; + + gcal = (GnomeCalendar *) bonobo_control_get_widget (control); switch (arg_id) { case PROPERTY_CALENDAR_URI_IDX: string = BONOBO_ARG_GET_STRING (arg); - if (!gnome_calendar_open (gcal, string)) { + if (gnome_calendar_add_event_uri (gcal, string)) { + calendar_control_sensitize_calendar_commands (control, gcal, TRUE); + } else { char *msg; msg = g_strdup_printf (_("Could not open the folder in '%s'"), string); @@ -161,7 +169,7 @@ calendar_properties_init (GnomeCalendar *gcal, BonoboControl *control) { BonoboPropertyBag *pbag; - pbag = bonobo_property_bag_new (get_prop, set_prop, gcal); + pbag = bonobo_property_bag_new (get_prop, set_prop, control); bonobo_property_bag_add (pbag, PROPERTY_CALENDAR_URI, diff --git a/calendar/gui/control-factory.h b/calendar/gui/control-factory.h index f599f7b3b8..bab1611c03 100644 --- a/calendar/gui/control-factory.h +++ b/calendar/gui/control-factory.h @@ -23,6 +23,8 @@ #ifndef _CONTROL_FACTORY_H_ #define _CONTROL_FACTORY_H_ +#include <bonobo/bonobo-control.h> + BonoboControl *control_factory_new_control (void); #endif /* _CONTROL_FACTORY_H_ */ diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am index 2466ffaa14..84424f8cc0 100644 --- a/calendar/gui/dialogs/Makefile.am +++ b/calendar/gui/dialogs/Makefile.am @@ -61,6 +61,8 @@ libcal_dialogs_la_SOURCES = \ event-page.h \ meeting-page.c \ meeting-page.h \ + new-calendar.c \ + new-calendar.h \ recurrence-page.c \ recurrence-page.h \ recur-comp.c \ @@ -85,6 +87,7 @@ glade_DATA = \ e-delegate-dialog.glade \ event-page.glade \ meeting-page.glade \ + new-calendar.glade \ recurrence-page.glade \ schedule-page.glade \ task-details-page.glade \ diff --git a/calendar/gui/dialogs/alarm-options.c b/calendar/gui/dialogs/alarm-options.c index ef13b78b13..b105dc3c23 100644 --- a/calendar/gui/dialogs/alarm-options.c +++ b/calendar/gui/dialogs/alarm-options.c @@ -39,7 +39,7 @@ #include <bonobo/bonobo-widget.h> #include <libgnomeui/gnome-file-entry.h> #include <glade/glade.h> -#include <ebook/e-destination.h> +#include <addressbook/util/eab-destination.h> #include "Evolution-Addressbook-SelectNames.h" #include "e-util/e-dialog-widgets.h" #include "alarm-options.h" @@ -307,7 +307,7 @@ alarm_to_malarm_widgets (Dialog *dialog, CalComponentAlarm *alarm) CalComponentText description; GtkTextBuffer *text_buffer; GSList *attendee_list, *l; - EDestination **destv; + EABDestination **destv; int len, i; /* Recipients */ @@ -315,22 +315,22 @@ alarm_to_malarm_widgets (Dialog *dialog, CalComponentAlarm *alarm) len = g_slist_length (attendee_list); if (len <= 0) { - destv = g_new0 (EDestination *, 2); - destv[0] = e_destination_new (); - e_destination_set_email (destv[0], dialog->email); + destv = g_new0 (EABDestination *, 2); + destv[0] = eab_destination_new (); + eab_destination_set_email (destv[0], dialog->email); destv[1] = NULL; len = 1; } else { - destv = g_new0 (EDestination *, len + 1); + destv = g_new0 (EABDestination *, len + 1); for (l = attendee_list, i = 0; l != NULL; l = l->next, i++) { CalComponentAttendee *a = l->data; - EDestination *dest; + EABDestination *dest; - dest = e_destination_new (); + dest = eab_destination_new (); if (a->cn != NULL && *a->cn) - e_destination_set_name (dest, a->cn); + eab_destination_set_name (dest, a->cn); if (a->value != NULL && *a->value) - e_destination_set_email (dest, a->value); + eab_destination_set_email (dest, a->value); destv[i] = dest; } @@ -338,7 +338,7 @@ alarm_to_malarm_widgets (Dialog *dialog, CalComponentAlarm *alarm) } bonobo_widget_set_property (BONOBO_WIDGET (dialog->malarm_addresses), - "destinations", e_destination_exportv (destv), NULL); + "destinations", eab_destination_exportv (destv), NULL); for (i = 0; i < len; i++) g_object_unref (GTK_OBJECT (destv[i])); @@ -617,7 +617,7 @@ malarm_widgets_to_alarm (Dialog *dialog, CalComponentAlarm *alarm) char *str; CalComponentText description; GSList *attendee_list = NULL; - EDestination **destv; + EABDestination **destv; GtkTextBuffer *text_buffer; GtkTextIter text_iter_start, text_iter_end; icalcomponent *icalcomp; @@ -627,18 +627,18 @@ malarm_widgets_to_alarm (Dialog *dialog, CalComponentAlarm *alarm) /* Attendees */ bonobo_widget_get_property (BONOBO_WIDGET (dialog->malarm_addresses), "destinations", TC_CORBA_string, &str, NULL); - destv = e_destination_importv (str); + destv = eab_destination_importv (str); g_free (str); for (i = 0; destv[i] != NULL; i++) { - EDestination *dest; + EABDestination *dest; CalComponentAttendee *a; dest = destv[i]; a = g_new0 (CalComponentAttendee, 1); - a->value = e_destination_get_email (dest); - a->cn = e_destination_get_name (dest); + a->value = eab_destination_get_email (dest); + a->cn = eab_destination_get_name (dest); attendee_list = g_slist_append (attendee_list, a); } @@ -646,7 +646,7 @@ malarm_widgets_to_alarm (Dialog *dialog, CalComponentAlarm *alarm) cal_component_alarm_set_attendee_list (alarm, attendee_list); cal_component_free_attendee_list (attendee_list); - e_destination_freev (destv); + eab_destination_freev (destv); /* Description */ text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->dalarm_description)); diff --git a/calendar/gui/e-cal-model-calendar.c b/calendar/gui/e-cal-model-calendar.c index 82de4e6d5a..593d342e70 100644 --- a/calendar/gui/e-cal-model-calendar.c +++ b/calendar/gui/e-cal-model-calendar.c @@ -129,7 +129,7 @@ get_dtend (ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_end), - &zone); + &zone, NULL); comp_data->dtend->zone = zone; } @@ -308,8 +308,12 @@ ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value) break; } - if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) - g_message ("ecmc_set_value_at(): Could not update the object!"); + /* FIXME ask about mod type */ + if (!cal_client_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) { + g_warning (G_STRLOC ": Could not modify the object!"); + + /* FIXME Show error dialog */ + } } static gboolean diff --git a/calendar/gui/e-cal-model-tasks.c b/calendar/gui/e-cal-model-tasks.c index 6bca52586c..76e2e140f3 100644 --- a/calendar/gui/e-cal-model-tasks.c +++ b/calendar/gui/e-cal-model-tasks.c @@ -223,7 +223,7 @@ get_completed (ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_completed), - &zone); + &zone, NULL); comp_data->completed->zone = zone; } @@ -253,7 +253,7 @@ get_due (ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_due), - &zone); + &zone, NULL); comp_data->due->zone = zone; } @@ -399,7 +399,7 @@ get_due_status (ECalModelTasks *model, ECalModelComponent *comp_data) /* Get the current time in the same timezone as the DUE date.*/ status = cal_client_get_timezone (comp_data->client, icaltime_get_tzid (due_tt), - &zone); + &zone, NULL); if (status != CAL_CLIENT_GET_SUCCESS) return E_CAL_MODEL_TASKS_DUE_FUTURE; @@ -756,8 +756,12 @@ ecmt_set_value_at (ETableModel *etm, int col, int row, const void *value) break; } - if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) - g_message ("ecmt_set_value_at(): Could not update the object!"); + /* FIXME ask about mod type */ + if (!cal_client_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) { + g_warning (G_STRLOC ": Could not modify the object!"); + + /* FIXME Show error dialog */ + } } static gboolean diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c index 1c231f9c72..c8b706c66e 100644 --- a/calendar/gui/e-cal-model.c +++ b/calendar/gui/e-cal-model.c @@ -41,6 +41,9 @@ struct _ECalModelPrivate { /* The list of clients we are managing. Each element is of type ECalModelClient */ GList *clients; + /* The default client in the list */ + CalClient *default_client; + /* Array for storing the objects. Each element is of type ECalModelComponent */ GPtrArray *objects; @@ -352,7 +355,7 @@ get_dtstart (ECalModel *model, ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_start), - &zone); + &zone, NULL); comp_data->dtstart->zone = zone; } @@ -609,8 +612,12 @@ ecm_set_value_at (ETableModel *etm, int col, int row, const void *value) break; } - if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) - g_message ("ecm_set_value_at(): Could not update the object!"); + /* FIXME ask about mod type */ + if (!cal_client_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) { + g_warning (G_STRLOC ": Could not modify the object!"); + + /* FIXME Show error dialog */ + } } static gboolean @@ -673,7 +680,10 @@ ecm_append_row (ETableModel *etm, ETableModel *source, int row) model_class->fill_component_from_model (model, &comp_data, source_model, row); } - if (cal_client_update_objects (comp_data.client, comp_data.icalcomp) != CAL_CLIENT_RESULT_SUCCESS) { + + if (!cal_client_create_object (comp_data.client, comp_data.icalcomp, NULL, NULL)) { + g_warning (G_STRLOC ": Could not create the object!"); + /* FIXME: show error dialog */ } @@ -987,46 +997,53 @@ CalClient * e_cal_model_get_default_client (ECalModel *model) { ECalModelPrivate *priv; - GList *l; - gchar *default_uri = NULL; - EConfigListener *db; ECalModelClient *client_data; + g_return_val_if_fail (model != NULL, NULL); g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); - + priv = model->priv; + /* we always return a valid CalClient, since we rely on it in many places */ + if (priv->default_client) + return priv->default_client; + if (!priv->clients) return NULL; - db = e_config_listener_new (); + client_data = (ECalModelClient *) priv->clients->data; - /* look at the configuration and return the real default calendar if we've got it loaded */ - if (priv->kind == ICAL_VEVENT_COMPONENT) - default_uri = e_config_listener_get_string (db, "/apps/evolution/shell/default_folders/calendar_uri"); - else if (priv->kind == ICAL_VTODO_COMPONENT) - default_uri = e_config_listener_get_string (db, "/apps/evolution/shell/default_folders/tasks_uri"); + return client_data ? client_data->client : NULL; +} - g_object_unref (db); +void +e_cal_model_set_default_client (ECalModel *model, CalClient *client) +{ + ECalModelPrivate *priv; + GList *l; + gboolean found = FALSE; + + g_return_if_fail (model != NULL); + g_return_if_fail (E_IS_CAL_MODEL (model)); + g_return_if_fail (client != NULL); + g_return_if_fail (IS_CAL_CLIENT (client)); - if (!default_uri) { - client_data = (ECalModelClient *) priv->clients->data; - return client_data->client; - } + priv = model->priv; + /* See if we already know about the client */ for (l = priv->clients; l != NULL; l = l->next) { - client_data = (ECalModelClient *) l->data; + ECalModelClient *client_data = l->data; - if (!strcmp (default_uri, cal_client_get_uri (client_data->client))) { - g_free (default_uri); - return client_data->client; - } + if (client == client_data->client) + found = TRUE; } - g_free (default_uri); - - client_data = (ECalModelClient *) priv->clients->data; - return client_data->client; + /* If its not found, add it */ + if (!found) + e_cal_model_add_client (model, client); + + /* Store the default client */ + priv->default_client = client; } /** @@ -1048,6 +1065,29 @@ e_cal_model_get_client_list (ECalModel *model) return list; } +/** + * e_cal_model_get_client_for_uri + * @model: A calendar model. + * @uri: Uri for the client to get. + */ +CalClient * +e_cal_model_get_client_for_uri (ECalModel *model, const char *uri) +{ + GList *l; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + g_return_val_if_fail (uri != NULL, NULL); + + for (l = model->priv->clients; l != NULL; l = l->next) { + ECalModelClient *client_data = (ECalModelClient *) l->data; + + if (!strcmp (uri, cal_client_get_uri (client_data->client))) + return client_data->client; + } + + return NULL; +} + static ECalModelComponent * search_by_uid_and_client (ECalModelPrivate *priv, CalClient *client, const char *uid) { @@ -1084,124 +1124,119 @@ get_position_in_array (GPtrArray *objects, gpointer item) } static void -query_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, - int n_scanned, int total, - gpointer user_data) +query_objects_added_cb (CalQuery *query, GList *objects, gpointer user_data) { - ECalModelPrivate *priv; - icalcomponent *new_icalcomp; - CalClientGetStatus status; - ECalModelComponent *comp_data; - gint pos; ECalModel *model = (ECalModel *) user_data; - - g_return_if_fail (E_IS_CAL_MODEL (model)); - + ECalModelPrivate *priv; + GList *l; + int start_row; + priv = model->priv; e_table_model_pre_change (E_TABLE_MODEL (model)); - comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), uid); - status = cal_client_get_object (cal_query_get_client (query), uid, &new_icalcomp); - switch (status) { - case CAL_CLIENT_GET_SUCCESS : - if (comp_data) { - if (comp_data->icalcomp) - icalcomponent_free (comp_data->icalcomp); - if (comp_data->dtstart) { - g_free (comp_data->dtstart); - comp_data->dtstart = NULL; - } - if (comp_data->dtend) { - g_free (comp_data->dtend); - comp_data->dtend = NULL; - } - if (comp_data->due) { - g_free (comp_data->due); - comp_data->due = NULL; - } - if (comp_data->completed) { - g_free (comp_data->completed); - comp_data->completed = NULL; - } + start_row = priv->objects->len ? priv->objects->len - 1 : 0; + + for (l = objects; l; l = l->next) { + ECalModelComponent *comp_data; - comp_data->icalcomp = new_icalcomp; + comp_data = g_new0 (ECalModelComponent, 1); + comp_data->client = cal_query_get_client (query); + comp_data->icalcomp = icalcomponent_new_clone (l->data); - e_table_model_row_changed (E_TABLE_MODEL (model), get_position_in_array (priv->objects, comp_data)); - } else { - comp_data = g_new0 (ECalModelComponent, 1); - comp_data->client = cal_query_get_client (query); - comp_data->icalcomp = new_icalcomp; + g_ptr_array_add (priv->objects, comp_data); + } - g_ptr_array_add (priv->objects, comp_data); - e_table_model_row_inserted (E_TABLE_MODEL (model), priv->objects->len - 1); - } - break; - case CAL_CLIENT_GET_NOT_FOUND : - case CAL_CLIENT_GET_SYNTAX_ERROR : - if (comp_data) { - /* Nothing; the object may have been removed from the server. We just - notify that the old object was deleted. - */ - pos = get_position_in_array (priv->objects, comp_data); + e_table_model_rows_inserted (E_TABLE_MODEL (model), start_row, priv->objects->len - start_row); +} - g_ptr_array_remove (priv->objects, comp_data); - free_comp_data (comp_data); +static void +query_objects_modified_cb (CalQuery *query, GList *objects, gpointer user_data) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) user_data; + GList *l; + + priv = model->priv; - e_table_model_row_deleted (E_TABLE_MODEL (model), pos); - } else - e_table_model_no_change (E_TABLE_MODEL (model)); - break; - default : - g_assert_not_reached (); + for (l = objects; l; l = l->next) { + ECalModelComponent *comp_data; + + e_table_model_pre_change (E_TABLE_MODEL (model)); + + comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), icalcomponent_get_uid (l->data)); + g_assert (comp_data); + + if (comp_data->icalcomp) + icalcomponent_free (comp_data->icalcomp); + if (comp_data->dtstart) { + g_free (comp_data->dtstart); + comp_data->dtstart = NULL; + } + if (comp_data->dtend) { + g_free (comp_data->dtend); + comp_data->dtend = NULL; + } + if (comp_data->due) { + g_free (comp_data->due); + comp_data->due = NULL; + } + if (comp_data->completed) { + g_free (comp_data->completed); + comp_data->completed = NULL; + } + + comp_data->icalcomp = icalcomponent_new_clone (l->data); + + e_table_model_row_changed (E_TABLE_MODEL (model), get_position_in_array (priv->objects, comp_data)); } } static void -query_obj_removed_cb (CalQuery *query, const char *uid, gpointer user_data) +query_objects_removed_cb (CalQuery *query, GList *uids, gpointer user_data) { - ECalModelComponent *comp_data; ECalModelPrivate *priv; ECalModel *model = (ECalModel *) user_data; - - g_return_if_fail (E_IS_CAL_MODEL (model)); - + GList *l; + priv = model->priv; - e_table_model_pre_change (E_TABLE_MODEL (model)); - - comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), uid); - if (comp_data) { - gint pos = get_position_in_array (priv->objects, comp_data); + for (l = uids; l; l = l->next) { + ECalModelComponent *comp_data; + int pos; + e_table_model_pre_change (E_TABLE_MODEL (model)); + + comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), l->data); + g_assert (comp_data); + + pos = get_position_in_array (priv->objects, comp_data); + g_ptr_array_remove (priv->objects, comp_data); free_comp_data (comp_data); - + e_table_model_row_deleted (E_TABLE_MODEL (model), pos); - } else - e_table_model_no_change (E_TABLE_MODEL (model)); + } } static void -query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer user_data) +query_progress_cb (CalQuery *query, const char *message, int percent, gpointer user_data) { ECalModel *model = (ECalModel *) user_data; g_return_if_fail (E_IS_CAL_MODEL (model)); - if (status != CAL_QUERY_DONE_SUCCESS) - g_warning ("query done: %s\n", error_str); + /* FIXME Update status bar */ } static void -query_eval_error_cb (CalQuery *query, const char *error_str, gpointer user_data) +query_done_cb (CalQuery *query, ECalendarStatus status, gpointer user_data) { - ECalModel *model = (ECalModel *) user_data; + ECalModel *model = (ECalModel *) user_data; g_return_if_fail (E_IS_CAL_MODEL (model)); - g_warning ("eval error: %s\n", error_str); + /* FIXME Clear status bar */ } /* Builds a complete query sexp for the calendar model by adding the predicates @@ -1248,24 +1283,28 @@ update_query_for_client (ECalModel *model, ECalModelClient *client_data) g_signal_handlers_disconnect_matched (client_data->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); g_object_unref (client_data->query); + client_data->query = NULL; } /* prepare the query */ g_assert (priv->sexp != NULL); real_sexp = adjust_query_sexp (model, priv->sexp); - client_data->query = cal_client_get_query (client_data->client, real_sexp); - g_free (real_sexp); + if (!cal_client_get_query (client_data->client, real_sexp, &client_data->query, NULL)) { + g_warning (G_STRLOC ": Unable to get query"); + g_free (real_sexp); - if (!client_data->query) { - g_message ("update_query_for_client(): Could not create the query"); return; - } + } + g_free (real_sexp); - g_signal_connect (client_data->query, "obj_updated", G_CALLBACK (query_obj_updated_cb), model); - g_signal_connect (client_data->query, "obj_removed", G_CALLBACK (query_obj_removed_cb), model); + g_signal_connect (client_data->query, "objects_added", G_CALLBACK (query_objects_added_cb), model); + g_signal_connect (client_data->query, "objects_modified", G_CALLBACK (query_objects_modified_cb), model); + g_signal_connect (client_data->query, "objects_removed", G_CALLBACK (query_objects_removed_cb), model); + g_signal_connect (client_data->query, "query_progress", G_CALLBACK (query_progress_cb), model); g_signal_connect (client_data->query, "query_done", G_CALLBACK (query_done_cb), model); - g_signal_connect (client_data->query, "eval_error", G_CALLBACK (query_eval_error_cb), model); + + cal_query_start (client_data->query); } static void @@ -1465,9 +1504,22 @@ e_cal_model_create_component_with_defaults (ECalModel *model) return NULL; } + if (!comp) + return icalcomponent_new (priv->kind); + icalcomp = icalcomponent_new_clone (cal_component_get_icalcomponent (comp)); g_object_unref (comp); + /* make sure the component has an UID */ + if (!icalcomponent_get_uid (icalcomp)) { + char *uid; + + uid = cal_component_gen_uid (); + icalcomponent_set_uid (icalcomp, uid); + + g_free (uid); + } + return icalcomp; } diff --git a/calendar/gui/e-cal-model.h b/calendar/gui/e-cal-model.h index ec8ab36c44..9c673ca439 100644 --- a/calendar/gui/e-cal-model.h +++ b/calendar/gui/e-cal-model.h @@ -88,7 +88,9 @@ void e_cal_model_set_default_category (ECalModel *model, const gc void e_cal_model_set_use_24_hour_format (ECalModel *model, gboolean use24); CalClient *e_cal_model_get_default_client (ECalModel *model); +void e_cal_model_set_default_client (ECalModel *model, CalClient *client); GList *e_cal_model_get_client_list (ECalModel *model); +CalClient *e_cal_model_get_client_for_uri (ECalModel *model, const char *uri); void e_cal_model_add_client (ECalModel *model, CalClient *client); void e_cal_model_remove_client (ECalModel *model, CalClient *client); void e_cal_model_remove_all_clients (ECalModel *model); diff --git a/calendar/gui/e-cal-view.c b/calendar/gui/e-cal-view.c index 381dca2542..869c8001a3 100644 --- a/calendar/gui/e-cal-view.c +++ b/calendar/gui/e-cal-view.c @@ -37,9 +37,11 @@ #include "comp-util.h" #include "e-cal-model-calendar.h" #include "e-cal-view.h" +#include "e-comp-editor-registry.h" #include "itip-utils.h" #include "dialogs/delete-comp.h" #include "dialogs/delete-error.h" +#include "dialogs/event-editor.h" #include "dialogs/send-comp.h" #include "dialogs/cancel-comp.h" #include "dialogs/recur-comp.h" @@ -70,15 +72,28 @@ struct _ECalViewPrivate { /* The timezone. */ icaltimezone *zone; + + /* The default category */ + char *default_category; }; static void e_cal_view_class_init (ECalViewClass *klass); static void e_cal_view_init (ECalView *cal_view, ECalViewClass *klass); +static void e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void e_cal_view_destroy (GtkObject *object); static GObjectClass *parent_class = NULL; static GdkAtom clipboard_atom = GDK_NONE; +extern ECompEditorRegistry *comp_editor_registry; + +/* Property IDs */ +enum props { + PROP_0, + PROP_MODEL, +}; +/* FIXME Why are we emitting these event signals here? Can't the model just be listened to? */ /* Signal IDs */ enum { SELECTION_CHANGED, @@ -91,12 +106,71 @@ enum { static guint e_cal_view_signals[LAST_SIGNAL] = { 0 }; static void +e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + e_cal_view_set_model (cal_view, E_CAL_MODEL (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + g_value_set_object (value, e_cal_view_get_model (cal_view)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void e_cal_view_class_init (ECalViewClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); + /* Method override */ + gobject_class->set_property = e_cal_view_set_property; + gobject_class->get_property = e_cal_view_get_property; + object_class->destroy = e_cal_view_destroy; + + klass->selection_changed = NULL; + klass->event_changed = NULL; + klass->event_added = NULL; + + klass->get_selected_events = NULL; + klass->get_selected_time_range = NULL; + klass->set_selected_time_range = NULL; + klass->get_visible_time_range = NULL; + klass->update_query = NULL; + + g_object_class_install_property (gobject_class, PROP_MODEL, + g_param_spec_object ("model", NULL, NULL, E_TYPE_CAL_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT)); + /* Create class' signals */ e_cal_view_signals[SELECTION_CHANGED] = g_signal_new ("selection_changed", @@ -135,19 +209,6 @@ e_cal_view_class_init (ECalViewClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); - /* Method override */ - object_class->destroy = e_cal_view_destroy; - - klass->selection_changed = NULL; - klass->event_changed = NULL; - klass->event_added = NULL; - - klass->get_selected_events = NULL; - klass->get_selected_time_range = NULL; - klass->set_selected_time_range = NULL; - klass->get_visible_time_range = NULL; - klass->update_query = NULL; - /* clipboard atom */ if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); @@ -208,6 +269,45 @@ selection_clear_event (GtkWidget *invisible, } static void +selection_received_add_event (ECalView *cal_view, CalClient *client, time_t selected_time_start, + icaltimezone *default_zone, icalcomponent *icalcomp) +{ + CalComponent *comp; + struct icaltimetype itime; + time_t tt_start, tt_end; + struct icaldurationtype ic_dur; + char *uid; + + tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); + tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); + ic_dur = icaldurationtype_from_int (tt_end - tt_start); + itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); + + icalcomponent_set_dtstart (icalcomp, itime); + itime = icaltime_add (itime, ic_dur); + icalcomponent_set_dtend (icalcomp, itime); + + /* FIXME The new uid stuff can go away once we actually set it in the backend */ + uid = cal_component_gen_uid (); + comp = cal_component_new (); + cal_component_set_icalcomponent ( + comp, icalcomponent_new_clone (icalcomp)); + cal_component_set_uid (comp, uid); + + /* FIXME Error handling */ + cal_client_create_object (client, cal_component_get_icalcomponent (comp), NULL, NULL); + if (itip_organizer_is_user (comp, client) && + send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), + client, comp, TRUE)) { + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + client, NULL); + } + + free (uid); + g_object_unref (comp); +} + +static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, guint time, @@ -216,12 +316,7 @@ selection_received (GtkWidget *invisible, char *comp_str, *default_tzid; icalcomponent *icalcomp; icalcomponent_kind kind; - CalComponent *comp; time_t selected_time_start, selected_time_end; - struct icaltimetype itime; - time_t tt_start, tt_end; - struct icaldurationtype ic_dur; - char *uid; icaltimezone *default_zone; CalClient *client; @@ -238,21 +333,21 @@ selection_received (GtkWidget *invisible, return; default_tzid = calendar_config_get_timezone (); + client = e_cal_model_get_default_client (cal_view->priv->model); - cal_client_get_timezone (client, default_tzid, &default_zone); + /* FIXME Error checking */ + cal_client_get_timezone (client, default_tzid, &default_zone, NULL); /* check the type of the component */ + /* FIXME An error dialog if we return? */ kind = icalcomponent_isa (icalcomp); - if (kind != ICAL_VCALENDAR_COMPONENT && - kind != ICAL_VEVENT_COMPONENT && - kind != ICAL_VTODO_COMPONENT && - kind != ICAL_VJOURNAL_COMPONENT) { + if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT) return; - } e_cal_view_set_status_message (cal_view, _("Updating objects")); e_cal_view_get_selected_time_range (cal_view, &selected_time_start, &selected_time_end); + /* FIXME Timezone handling */ if (kind == ICAL_VCALENDAR_COMPONENT) { icalcomponent_kind child_kind; icalcomponent *subcomp; @@ -260,69 +355,27 @@ selection_received (GtkWidget *invisible, subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); while (subcomp) { child_kind = icalcomponent_isa (subcomp); - if (child_kind == ICAL_VEVENT_COMPONENT || - child_kind == ICAL_VTODO_COMPONENT || - child_kind == ICAL_VJOURNAL_COMPONENT) { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (subcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (subcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, - FALSE, default_zone); - - icalcomponent_set_dtstart (subcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (subcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (subcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + if (child_kind == ICAL_VEVENT_COMPONENT) + selection_received_add_event (cal_view, client, selected_time_start, + default_zone, subcomp); + else if (child_kind == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + + zone = icaltimezone_new (); + icaltimezone_set_component (zone, subcomp); + cal_client_add_timezone (client, zone, NULL); + + icaltimezone_free (zone, 1); } + subcomp = icalcomponent_get_next_component ( icalcomp, ICAL_ANY_COMPONENT); } icalcomponent_free (icalcomp); - } - else { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); - - icalcomponent_set_dtstart (icalcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (icalcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (icalcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + } else { + selection_received_add_event (cal_view, client, selected_time_start, default_zone, icalcomp); } e_cal_view_set_status_message (cal_view, NULL); @@ -334,6 +387,14 @@ e_cal_view_init (ECalView *cal_view, ECalViewClass *klass) cal_view->priv = g_new0 (ECalViewPrivate, 1); cal_view->priv->model = (ECalModel *) e_cal_model_calendar_new (); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_changed", + G_CALLBACK (model_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_row_changed", + G_CALLBACK (model_row_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_inserted", + G_CALLBACK (model_rows_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_deleted", + G_CALLBACK (model_rows_changed_cb), cal_view); /* Set up the invisible widget for the clipboard selections */ cal_view->priv->invisible = gtk_invisible_new (); @@ -380,6 +441,11 @@ e_cal_view_destroy (GtkObject *object) cal_view->priv->clipboard_selection = NULL; } + if (cal_view->priv->default_category) { + g_free (cal_view->priv->default_category); + cal_view->priv->default_category = NULL; + } + g_free (cal_view->priv); cal_view->priv = NULL; } @@ -460,11 +526,35 @@ e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone) old_zone, cal_view->priv->zone); } +const char * +e_cal_view_get_default_category (ECalView *cal_view) +{ + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); + return (const char *) cal_view->priv->default_category; +} + +/** + * e_cal_view_set_default_category + * @cal_view: A calendar view. + * @category: Default category name or NULL for no category. + * + * Sets the default category that will be used when creating new calendar + * components from the given calendar view. + */ void -e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +e_cal_view_set_default_category (ECalView *cal_view, const char *category) { - extern EvolutionShellClient *global_shell_client; /* ugly */ + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + if (cal_view->priv->default_category) + g_free (cal_view->priv->default_category); + + cal_view->priv->default_category = g_strdup (category); +} +void +e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +{ g_return_if_fail (E_IS_CAL_VIEW (cal_view)); if (!message || !*message) { @@ -473,14 +563,19 @@ e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) cal_view->priv->activity = NULL; } } else if (!cal_view->priv->activity) { +#if 0 int display; +#endif char *client_id = g_strdup_printf ("%p", cal_view); if (progress_icon[0] == NULL) progress_icon[0] = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" EVOLUTION_CALENDAR_PROGRESS_IMAGE, NULL); + +#if 0 cal_view->priv->activity = evolution_activity_client_new ( global_shell_client, client_id, progress_icon, message, TRUE, &display); +#endif g_free (client_id); } else @@ -564,9 +659,9 @@ e_cal_view_cut_clipboard (ECalView *cal_view) e_cal_view_copy_clipboard (cal_view); for (l = selected; l != NULL; l = l->next) { CalComponent *comp; - ECalViewEvent *event = (ECalViewEvent *) l->data; - + GError *error = NULL; + if (!event) continue; @@ -580,9 +675,11 @@ e_cal_view_cut_clipboard (ECalView *cal_view) event->comp_data->client, NULL); cal_component_get_uid (comp, &uid); - delete_error_dialog (cal_client_remove_object (event->comp_data->client, uid), - CAL_COMPONENT_EVENT); + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); + g_object_unref (comp); } @@ -657,7 +754,8 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) if (delete_component_dialog (comp, FALSE, 1, vtype, GTK_WIDGET (cal_view))) { const char *uid; - + GError *error = NULL; + if (itip_organizer_is_user (comp, event->comp_data->client) && cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), event->comp_data->client, @@ -670,9 +768,10 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) g_object_unref (comp); return; } - - delete_error_dialog ( - cal_client_remove_object (event->comp_data->client, uid), CAL_COMPONENT_EVENT); + + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); } g_object_unref (comp); @@ -719,35 +818,21 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) { ECalViewEvent *event; GList *selected; - + const char *uid; + GError *error = NULL; + selected = e_cal_view_get_selected_events (cal_view); if (!selected) return; event = (ECalViewEvent *) selected->data; - if (cal_util_component_is_instance (event->comp_data->icalcomp)) { - const char *uid; - - uid = icalcomponent_get_uid (event->comp_data->icalcomp); - delete_error_dialog ( - cal_client_remove_object_with_mod (event->comp_data->client, uid, CALOBJ_MOD_THIS), - CAL_COMPONENT_EVENT); - } else { - CalComponent *comp; + uid = icalcomponent_get_uid (event->comp_data->icalcomp); + /* FIXME: use 'rid' argument */ + cal_client_remove_object_with_mod (event->comp_data->client, uid, NULL, CALOBJ_MOD_THIS, &error); - /* we must duplicate the CalComponent, or we won't know it has changed - when we get the "update_event" signal */ - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, cal_view->priv->zone); - - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_cal_view_delete_selected_occurrence(): Could not update the object!"); - - g_object_unref (comp); - } + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); /* free memory */ g_list_free (selected); @@ -756,11 +841,9 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) static void on_new_appointment (GtkWidget *widget, gpointer user_data) { - time_t dtstart, dtend; ECalView *cal_view = (ECalView *) user_data; - e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, FALSE); + e_cal_view_new_appointment (cal_view); } static void @@ -770,7 +853,7 @@ on_new_event (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, TRUE, FALSE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, TRUE, FALSE); } static void @@ -780,7 +863,7 @@ on_new_meeting (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, TRUE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, TRUE); } static void @@ -817,8 +900,8 @@ on_edit_appointment (GtkWidget *widget, gpointer user_data) ECalViewEvent *event = (ECalViewEvent *) selected->data; if (event) - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, - event->comp_data->icalcomp, FALSE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, + event->comp_data->icalcomp, FALSE); g_list_free (selected); } @@ -834,7 +917,7 @@ on_print (GtkWidget *widget, gpointer user_data) cal_view = E_CAL_VIEW (user_data); - gnome_calendar_get_current_time_range (cal_view->priv->calendar, &start, NULL); + e_cal_view_get_visible_time_range (cal_view, &start, NULL); view_type = gnome_calendar_get_view (cal_view->priv->calendar); switch (view_type) { @@ -930,7 +1013,7 @@ on_meeting (GtkWidget *widget, gpointer user_data) selected = e_cal_view_get_selected_events (cal_view); if (selected) { ECalViewEvent *event = (ECalViewEvent *) selected->data; - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, event->comp_data->icalcomp, TRUE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, event->comp_data->icalcomp, TRUE); g_list_free (selected); } @@ -962,7 +1045,7 @@ on_publish (GtkWidget *widget, gpointer user_data) ECalView *cal_view; icaltimezone *utc; time_t start = time (NULL), end; - GList *comp_list, *client_list, *cl; + GList *comp_list = NULL, *client_list, *cl; cal_view = E_CAL_VIEW (user_data); @@ -972,8 +1055,7 @@ on_publish (GtkWidget *widget, gpointer user_data) client_list = e_cal_model_get_client_list (cal_view->priv->model); for (cl = client_list; cl != NULL; cl = cl->next) { - comp_list = cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end); - if (comp_list) { + if (cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -1041,14 +1123,6 @@ on_paste (GtkWidget *widget, gpointer user_data) e_cal_view_paste_clipboard (cal_view); } -static void -on_unrecur_appointment (GtkWidget *widget, gpointer user_data) -{ - ECalView *cal_view = E_CAL_VIEW (user_data); - - gnome_calendar_unrecur_selection (cal_view->priv->calendar); -} - enum { /* * This is used to "flag" events that can not be editted @@ -1142,7 +1216,6 @@ static EPopupMenu child_items [] = { E_POPUP_SEPARATOR, E_POPUP_ITEM (N_("_Delete"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_EDITABLE | MASK_SINGLE | MASK_EDITING), - E_POPUP_ITEM (N_("Make this Occurrence _Movable"), GTK_SIGNAL_FUNC (on_unrecur_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE | MASK_INSTANCE), E_POPUP_ITEM (N_("Delete this _Occurrence"), GTK_SIGNAL_FUNC (on_delete_occurrence), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), E_POPUP_ITEM (N_("Delete _All Occurrences"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), @@ -1209,21 +1282,18 @@ setup_popup_icons (EPopupMenu *context_menu) GtkMenu * e_cal_view_create_popup_menu (ECalView *cal_view) { - gboolean being_edited, have_selection; GList *selected; EPopupMenu *context_menu; guint32 disable_mask = 0, hide_mask = 0; GtkMenu *popup; CalClient *client = NULL; - + gboolean read_only = TRUE; + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); /* get the selection */ - being_edited = FALSE; selected = e_cal_view_get_selected_events (cal_view); - have_selection = GTK_WIDGET_HAS_FOCUS (cal_view) && selected != NULL; - if (selected == NULL) { cal_view->priv->view_menu = gnome_calendar_setup_view_popup (cal_view->priv->calendar); main_items[9].submenu = cal_view->priv->view_menu; @@ -1260,15 +1330,158 @@ e_cal_view_create_popup_menu (ECalView *cal_view) client = event->comp_data->client; } - if (cal_client_is_read_only (client)) + cal_client_is_read_only (client, &read_only, NULL); + if (read_only) disable_mask |= MASK_EDITABLE; - if (being_edited) - disable_mask |= MASK_EDITING; - setup_popup_icons (context_menu); popup = e_popup_menu_create (context_menu, disable_mask, hide_mask, cal_view); g_signal_connect (popup, "selection-done", G_CALLBACK (free_view_popup), cal_view); return popup; } + +/** + * e_cal_view_new_appointment_for + * @cal_view: A calendar view. + * @dtstart: A Unix time_t that marks the beginning of the appointment. + * @dtend: A Unix time_t that marks the end of the appointment. + * @all_day: If TRUE, the dtstart and dtend are expanded to cover + * the entire day, and the event is set to TRANSPARENT. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an event editor dialog for a new appointment. + */ +void +e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, time_t dtend, + gboolean all_day, + gboolean meeting) +{ + ECalViewPrivate *priv; + struct icaltimetype itt; + CalComponentDateTime dt; + CalComponent *comp; + icalcomponent *icalcomp; + CalComponentTransparency transparency; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + priv = cal_view->priv; + + dt.value = &itt; + if (all_day) + dt.tzid = NULL; + else + dt.tzid = icaltimezone_get_tzid (priv->zone); + + icalcomp = e_cal_model_create_component_with_defaults (priv->model); + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + /* DTSTART, DTEND */ + itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); + if (all_day) { + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtstart (comp, &dt); + + itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); + if (all_day) { + /* We round it up to the end of the day, unless it is + already set to midnight */ + if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { + icaltime_adjust (&itt, 1, 0, 0, 0); + } + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtend (comp, &dt); + + /* TRANSPARENCY */ + transparency = all_day ? CAL_COMPONENT_TRANSP_TRANSPARENT + : CAL_COMPONENT_TRANSP_OPAQUE; + cal_component_set_transparency (comp, transparency); + + /* CATEGORY */ + cal_component_set_categories (comp, priv->default_category); + + /* edit the object */ + cal_component_commit_sequence (comp); + + e_cal_view_edit_appointment (cal_view, + e_cal_model_get_default_client (priv->model), + icalcomp, meeting); + + g_object_unref (comp); +} + +/** + * e_cal_view_new_appointment + * @cal_view: A calendar view. + * + * Opens an event editor dialog for a new appointment. The appointment's + * start and end times are set to the currently selected time range in + * the calendar view. + */ +void +e_cal_view_new_appointment (ECalView *cal_view) +{ + time_t dtstart, dtend; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, FALSE); +} + +/** + * e_cal_view_edit_appointment + * @cal_view: A calendar view. + * @client: Calendar client. + * @icalcomp: The object to be edited. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an editor window to allow the user to edit the selected + * object. + */ +void +e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting) +{ + ECalViewPrivate *priv; + CompEditor *ce; + const char *uid; + CalComponent *comp; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + g_return_if_fail (IS_CAL_CLIENT (client)); + g_return_if_fail (icalcomp != NULL); + + priv = cal_view->priv; + + uid = icalcomponent_get_uid (icalcomp); + + ce = e_comp_editor_registry_find (comp_editor_registry, uid); + if (!ce) { + EventEditor *ee; + + ee = event_editor_new (client); + ce = COMP_EDITOR (ee); + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); + comp_editor_edit_comp (ce, comp); + if (meeting) + event_editor_show_meeting (ee); + + e_comp_editor_registry_add (comp_editor_registry, ce, FALSE); + + g_object_unref (comp); + } + + comp_editor_focus (ce); +} diff --git a/calendar/gui/e-cal-view.h b/calendar/gui/e-cal-view.h index ea7c11a00d..9a09a5236a 100644 --- a/calendar/gui/e-cal-view.h +++ b/calendar/gui/e-cal-view.h @@ -96,6 +96,8 @@ ECalModel *e_cal_view_get_model (ECalView *cal_view); void e_cal_view_set_model (ECalView *cal_view, ECalModel *model); icaltimezone *e_cal_view_get_timezone (ECalView *cal_view); void e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone); +const char *e_cal_view_get_default_category (ECalView *cal_view); +void e_cal_view_set_default_category (ECalView *cal_view, const char *category); void e_cal_view_set_status_message (ECalView *cal_view, const gchar *message); @@ -114,6 +116,17 @@ void e_cal_view_delete_selected_occurrence (ECalView *cal_view); GtkMenu *e_cal_view_create_popup_menu (ECalView *cal_view); +void e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, + time_t dtend, + gboolean all_day, + gboolean meeting); +void e_cal_view_new_appointment (ECalView *cal_view); +void e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting); + G_END_DECLS #endif diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index 5b3f98f373..fdea4d33bb 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -725,10 +725,12 @@ delete_selected_components (ECalendarTable *cal_table) for (l = objs; l; l = l->next) { ECalModelComponent *comp_data = (ECalModelComponent *) l->data; - - delete_error_dialog (cal_client_remove_object (comp_data->client, - icalcomponent_get_uid (comp_data->icalcomp)), - CAL_COMPONENT_TODO); + GError *error = NULL; + + cal_client_remove_object (comp_data->client, + icalcomponent_get_uid (comp_data->icalcomp), &error); + delete_error_dialog (error, CAL_COMPONENT_TODO); + g_clear_error (&error); } e_calendar_table_set_status_message (cal_table, NULL); @@ -1052,7 +1054,8 @@ e_calendar_table_show_popup_menu (ETable *table, GtkMenu *gtk_menu; icalproperty *prop; ECalModelComponent *comp_data; - + gboolean read_only = TRUE; + n_selected = e_table_selected_count (table); if (n_selected <= 0) return TRUE; @@ -1071,7 +1074,8 @@ e_calendar_table_show_popup_menu (ETable *table, } else hide_mask = MASK_SINGLE; - if (cal_client_is_read_only (comp_data->client)) + cal_client_is_read_only (comp_data->client, &read_only, NULL); + if (!read_only) disable_mask |= MASK_EDITABLE; if (cal_client_get_static_capability (comp_data->client, CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT)) @@ -1315,6 +1319,7 @@ selection_received (GtkWidget *invisible, icalcomponent *icalcomp; char *uid; CalComponent *comp; + CalClient *client; icalcomponent_kind kind; g_return_if_fail (E_IS_CALENDAR_TABLE (cal_table)); @@ -1338,6 +1343,8 @@ selection_received (GtkWidget *invisible, return; } + client = e_cal_model_get_default_client (cal_table->model); + e_calendar_table_set_status_message (cal_table, _("Updating objects")); if (kind == ICAL_VCALENDAR_COMPONENT) { @@ -1360,11 +1367,12 @@ selection_received (GtkWidget *invisible, cal_component_set_icalcomponent ( tmp_comp, icalcomponent_new_clone (subcomp)); cal_component_set_uid (tmp_comp, uid); - - cal_client_update_object ( - e_cal_model_get_default_client (cal_table->model), - tmp_comp); free (uid); + + /* FIXME should we convert start/due/complete times? */ + /* FIXME Error handling */ + cal_client_create_object (client, cal_component_get_icalcomponent (tmp_comp), NULL, NULL); + g_object_unref (tmp_comp); } subcomp = icalcomponent_get_next_component ( @@ -1378,9 +1386,8 @@ selection_received (GtkWidget *invisible, cal_component_set_uid (comp, (const char *) uid); free (uid); - cal_client_update_object ( - e_cal_model_get_default_client (cal_table->model), - comp); + cal_client_create_object (client, cal_component_get_icalcomponent (comp), NULL, NULL); + g_object_unref (comp); } @@ -1433,8 +1440,6 @@ static GdkPixbuf *progress_icon[2] = { NULL, NULL }; void e_calendar_table_set_status_message (ECalendarTable *cal_table, const gchar *message) { - extern EvolutionShellClient *global_shell_client; /* ugly */ - g_return_if_fail (E_IS_CALENDAR_TABLE (cal_table)); if (!message || !*message) { @@ -1448,9 +1453,12 @@ e_calendar_table_set_status_message (ECalendarTable *cal_table, const gchar *mes if (progress_icon[0] == NULL) progress_icon[0] = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" EVOLUTION_TASKS_PROGRESS_IMAGE, NULL); + +#if 0 /* EPFIXME */ cal_table->activity = evolution_activity_client_new ( global_shell_client, client_id, progress_icon, message, TRUE, &display); +#endif g_free (client_id); } else diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 381dca2542..869c8001a3 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -37,9 +37,11 @@ #include "comp-util.h" #include "e-cal-model-calendar.h" #include "e-cal-view.h" +#include "e-comp-editor-registry.h" #include "itip-utils.h" #include "dialogs/delete-comp.h" #include "dialogs/delete-error.h" +#include "dialogs/event-editor.h" #include "dialogs/send-comp.h" #include "dialogs/cancel-comp.h" #include "dialogs/recur-comp.h" @@ -70,15 +72,28 @@ struct _ECalViewPrivate { /* The timezone. */ icaltimezone *zone; + + /* The default category */ + char *default_category; }; static void e_cal_view_class_init (ECalViewClass *klass); static void e_cal_view_init (ECalView *cal_view, ECalViewClass *klass); +static void e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void e_cal_view_destroy (GtkObject *object); static GObjectClass *parent_class = NULL; static GdkAtom clipboard_atom = GDK_NONE; +extern ECompEditorRegistry *comp_editor_registry; + +/* Property IDs */ +enum props { + PROP_0, + PROP_MODEL, +}; +/* FIXME Why are we emitting these event signals here? Can't the model just be listened to? */ /* Signal IDs */ enum { SELECTION_CHANGED, @@ -91,12 +106,71 @@ enum { static guint e_cal_view_signals[LAST_SIGNAL] = { 0 }; static void +e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + e_cal_view_set_model (cal_view, E_CAL_MODEL (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + g_value_set_object (value, e_cal_view_get_model (cal_view)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void e_cal_view_class_init (ECalViewClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); + /* Method override */ + gobject_class->set_property = e_cal_view_set_property; + gobject_class->get_property = e_cal_view_get_property; + object_class->destroy = e_cal_view_destroy; + + klass->selection_changed = NULL; + klass->event_changed = NULL; + klass->event_added = NULL; + + klass->get_selected_events = NULL; + klass->get_selected_time_range = NULL; + klass->set_selected_time_range = NULL; + klass->get_visible_time_range = NULL; + klass->update_query = NULL; + + g_object_class_install_property (gobject_class, PROP_MODEL, + g_param_spec_object ("model", NULL, NULL, E_TYPE_CAL_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT)); + /* Create class' signals */ e_cal_view_signals[SELECTION_CHANGED] = g_signal_new ("selection_changed", @@ -135,19 +209,6 @@ e_cal_view_class_init (ECalViewClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); - /* Method override */ - object_class->destroy = e_cal_view_destroy; - - klass->selection_changed = NULL; - klass->event_changed = NULL; - klass->event_added = NULL; - - klass->get_selected_events = NULL; - klass->get_selected_time_range = NULL; - klass->set_selected_time_range = NULL; - klass->get_visible_time_range = NULL; - klass->update_query = NULL; - /* clipboard atom */ if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); @@ -208,6 +269,45 @@ selection_clear_event (GtkWidget *invisible, } static void +selection_received_add_event (ECalView *cal_view, CalClient *client, time_t selected_time_start, + icaltimezone *default_zone, icalcomponent *icalcomp) +{ + CalComponent *comp; + struct icaltimetype itime; + time_t tt_start, tt_end; + struct icaldurationtype ic_dur; + char *uid; + + tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); + tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); + ic_dur = icaldurationtype_from_int (tt_end - tt_start); + itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); + + icalcomponent_set_dtstart (icalcomp, itime); + itime = icaltime_add (itime, ic_dur); + icalcomponent_set_dtend (icalcomp, itime); + + /* FIXME The new uid stuff can go away once we actually set it in the backend */ + uid = cal_component_gen_uid (); + comp = cal_component_new (); + cal_component_set_icalcomponent ( + comp, icalcomponent_new_clone (icalcomp)); + cal_component_set_uid (comp, uid); + + /* FIXME Error handling */ + cal_client_create_object (client, cal_component_get_icalcomponent (comp), NULL, NULL); + if (itip_organizer_is_user (comp, client) && + send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), + client, comp, TRUE)) { + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + client, NULL); + } + + free (uid); + g_object_unref (comp); +} + +static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, guint time, @@ -216,12 +316,7 @@ selection_received (GtkWidget *invisible, char *comp_str, *default_tzid; icalcomponent *icalcomp; icalcomponent_kind kind; - CalComponent *comp; time_t selected_time_start, selected_time_end; - struct icaltimetype itime; - time_t tt_start, tt_end; - struct icaldurationtype ic_dur; - char *uid; icaltimezone *default_zone; CalClient *client; @@ -238,21 +333,21 @@ selection_received (GtkWidget *invisible, return; default_tzid = calendar_config_get_timezone (); + client = e_cal_model_get_default_client (cal_view->priv->model); - cal_client_get_timezone (client, default_tzid, &default_zone); + /* FIXME Error checking */ + cal_client_get_timezone (client, default_tzid, &default_zone, NULL); /* check the type of the component */ + /* FIXME An error dialog if we return? */ kind = icalcomponent_isa (icalcomp); - if (kind != ICAL_VCALENDAR_COMPONENT && - kind != ICAL_VEVENT_COMPONENT && - kind != ICAL_VTODO_COMPONENT && - kind != ICAL_VJOURNAL_COMPONENT) { + if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT) return; - } e_cal_view_set_status_message (cal_view, _("Updating objects")); e_cal_view_get_selected_time_range (cal_view, &selected_time_start, &selected_time_end); + /* FIXME Timezone handling */ if (kind == ICAL_VCALENDAR_COMPONENT) { icalcomponent_kind child_kind; icalcomponent *subcomp; @@ -260,69 +355,27 @@ selection_received (GtkWidget *invisible, subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); while (subcomp) { child_kind = icalcomponent_isa (subcomp); - if (child_kind == ICAL_VEVENT_COMPONENT || - child_kind == ICAL_VTODO_COMPONENT || - child_kind == ICAL_VJOURNAL_COMPONENT) { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (subcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (subcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, - FALSE, default_zone); - - icalcomponent_set_dtstart (subcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (subcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (subcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + if (child_kind == ICAL_VEVENT_COMPONENT) + selection_received_add_event (cal_view, client, selected_time_start, + default_zone, subcomp); + else if (child_kind == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + + zone = icaltimezone_new (); + icaltimezone_set_component (zone, subcomp); + cal_client_add_timezone (client, zone, NULL); + + icaltimezone_free (zone, 1); } + subcomp = icalcomponent_get_next_component ( icalcomp, ICAL_ANY_COMPONENT); } icalcomponent_free (icalcomp); - } - else { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); - - icalcomponent_set_dtstart (icalcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (icalcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (icalcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + } else { + selection_received_add_event (cal_view, client, selected_time_start, default_zone, icalcomp); } e_cal_view_set_status_message (cal_view, NULL); @@ -334,6 +387,14 @@ e_cal_view_init (ECalView *cal_view, ECalViewClass *klass) cal_view->priv = g_new0 (ECalViewPrivate, 1); cal_view->priv->model = (ECalModel *) e_cal_model_calendar_new (); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_changed", + G_CALLBACK (model_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_row_changed", + G_CALLBACK (model_row_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_inserted", + G_CALLBACK (model_rows_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_deleted", + G_CALLBACK (model_rows_changed_cb), cal_view); /* Set up the invisible widget for the clipboard selections */ cal_view->priv->invisible = gtk_invisible_new (); @@ -380,6 +441,11 @@ e_cal_view_destroy (GtkObject *object) cal_view->priv->clipboard_selection = NULL; } + if (cal_view->priv->default_category) { + g_free (cal_view->priv->default_category); + cal_view->priv->default_category = NULL; + } + g_free (cal_view->priv); cal_view->priv = NULL; } @@ -460,11 +526,35 @@ e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone) old_zone, cal_view->priv->zone); } +const char * +e_cal_view_get_default_category (ECalView *cal_view) +{ + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); + return (const char *) cal_view->priv->default_category; +} + +/** + * e_cal_view_set_default_category + * @cal_view: A calendar view. + * @category: Default category name or NULL for no category. + * + * Sets the default category that will be used when creating new calendar + * components from the given calendar view. + */ void -e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +e_cal_view_set_default_category (ECalView *cal_view, const char *category) { - extern EvolutionShellClient *global_shell_client; /* ugly */ + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + if (cal_view->priv->default_category) + g_free (cal_view->priv->default_category); + + cal_view->priv->default_category = g_strdup (category); +} +void +e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +{ g_return_if_fail (E_IS_CAL_VIEW (cal_view)); if (!message || !*message) { @@ -473,14 +563,19 @@ e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) cal_view->priv->activity = NULL; } } else if (!cal_view->priv->activity) { +#if 0 int display; +#endif char *client_id = g_strdup_printf ("%p", cal_view); if (progress_icon[0] == NULL) progress_icon[0] = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" EVOLUTION_CALENDAR_PROGRESS_IMAGE, NULL); + +#if 0 cal_view->priv->activity = evolution_activity_client_new ( global_shell_client, client_id, progress_icon, message, TRUE, &display); +#endif g_free (client_id); } else @@ -564,9 +659,9 @@ e_cal_view_cut_clipboard (ECalView *cal_view) e_cal_view_copy_clipboard (cal_view); for (l = selected; l != NULL; l = l->next) { CalComponent *comp; - ECalViewEvent *event = (ECalViewEvent *) l->data; - + GError *error = NULL; + if (!event) continue; @@ -580,9 +675,11 @@ e_cal_view_cut_clipboard (ECalView *cal_view) event->comp_data->client, NULL); cal_component_get_uid (comp, &uid); - delete_error_dialog (cal_client_remove_object (event->comp_data->client, uid), - CAL_COMPONENT_EVENT); + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); + g_object_unref (comp); } @@ -657,7 +754,8 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) if (delete_component_dialog (comp, FALSE, 1, vtype, GTK_WIDGET (cal_view))) { const char *uid; - + GError *error = NULL; + if (itip_organizer_is_user (comp, event->comp_data->client) && cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), event->comp_data->client, @@ -670,9 +768,10 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) g_object_unref (comp); return; } - - delete_error_dialog ( - cal_client_remove_object (event->comp_data->client, uid), CAL_COMPONENT_EVENT); + + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); } g_object_unref (comp); @@ -719,35 +818,21 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) { ECalViewEvent *event; GList *selected; - + const char *uid; + GError *error = NULL; + selected = e_cal_view_get_selected_events (cal_view); if (!selected) return; event = (ECalViewEvent *) selected->data; - if (cal_util_component_is_instance (event->comp_data->icalcomp)) { - const char *uid; - - uid = icalcomponent_get_uid (event->comp_data->icalcomp); - delete_error_dialog ( - cal_client_remove_object_with_mod (event->comp_data->client, uid, CALOBJ_MOD_THIS), - CAL_COMPONENT_EVENT); - } else { - CalComponent *comp; + uid = icalcomponent_get_uid (event->comp_data->icalcomp); + /* FIXME: use 'rid' argument */ + cal_client_remove_object_with_mod (event->comp_data->client, uid, NULL, CALOBJ_MOD_THIS, &error); - /* we must duplicate the CalComponent, or we won't know it has changed - when we get the "update_event" signal */ - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, cal_view->priv->zone); - - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_cal_view_delete_selected_occurrence(): Could not update the object!"); - - g_object_unref (comp); - } + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); /* free memory */ g_list_free (selected); @@ -756,11 +841,9 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) static void on_new_appointment (GtkWidget *widget, gpointer user_data) { - time_t dtstart, dtend; ECalView *cal_view = (ECalView *) user_data; - e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, FALSE); + e_cal_view_new_appointment (cal_view); } static void @@ -770,7 +853,7 @@ on_new_event (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, TRUE, FALSE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, TRUE, FALSE); } static void @@ -780,7 +863,7 @@ on_new_meeting (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, TRUE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, TRUE); } static void @@ -817,8 +900,8 @@ on_edit_appointment (GtkWidget *widget, gpointer user_data) ECalViewEvent *event = (ECalViewEvent *) selected->data; if (event) - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, - event->comp_data->icalcomp, FALSE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, + event->comp_data->icalcomp, FALSE); g_list_free (selected); } @@ -834,7 +917,7 @@ on_print (GtkWidget *widget, gpointer user_data) cal_view = E_CAL_VIEW (user_data); - gnome_calendar_get_current_time_range (cal_view->priv->calendar, &start, NULL); + e_cal_view_get_visible_time_range (cal_view, &start, NULL); view_type = gnome_calendar_get_view (cal_view->priv->calendar); switch (view_type) { @@ -930,7 +1013,7 @@ on_meeting (GtkWidget *widget, gpointer user_data) selected = e_cal_view_get_selected_events (cal_view); if (selected) { ECalViewEvent *event = (ECalViewEvent *) selected->data; - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, event->comp_data->icalcomp, TRUE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, event->comp_data->icalcomp, TRUE); g_list_free (selected); } @@ -962,7 +1045,7 @@ on_publish (GtkWidget *widget, gpointer user_data) ECalView *cal_view; icaltimezone *utc; time_t start = time (NULL), end; - GList *comp_list, *client_list, *cl; + GList *comp_list = NULL, *client_list, *cl; cal_view = E_CAL_VIEW (user_data); @@ -972,8 +1055,7 @@ on_publish (GtkWidget *widget, gpointer user_data) client_list = e_cal_model_get_client_list (cal_view->priv->model); for (cl = client_list; cl != NULL; cl = cl->next) { - comp_list = cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end); - if (comp_list) { + if (cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -1041,14 +1123,6 @@ on_paste (GtkWidget *widget, gpointer user_data) e_cal_view_paste_clipboard (cal_view); } -static void -on_unrecur_appointment (GtkWidget *widget, gpointer user_data) -{ - ECalView *cal_view = E_CAL_VIEW (user_data); - - gnome_calendar_unrecur_selection (cal_view->priv->calendar); -} - enum { /* * This is used to "flag" events that can not be editted @@ -1142,7 +1216,6 @@ static EPopupMenu child_items [] = { E_POPUP_SEPARATOR, E_POPUP_ITEM (N_("_Delete"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_EDITABLE | MASK_SINGLE | MASK_EDITING), - E_POPUP_ITEM (N_("Make this Occurrence _Movable"), GTK_SIGNAL_FUNC (on_unrecur_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE | MASK_INSTANCE), E_POPUP_ITEM (N_("Delete this _Occurrence"), GTK_SIGNAL_FUNC (on_delete_occurrence), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), E_POPUP_ITEM (N_("Delete _All Occurrences"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), @@ -1209,21 +1282,18 @@ setup_popup_icons (EPopupMenu *context_menu) GtkMenu * e_cal_view_create_popup_menu (ECalView *cal_view) { - gboolean being_edited, have_selection; GList *selected; EPopupMenu *context_menu; guint32 disable_mask = 0, hide_mask = 0; GtkMenu *popup; CalClient *client = NULL; - + gboolean read_only = TRUE; + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); /* get the selection */ - being_edited = FALSE; selected = e_cal_view_get_selected_events (cal_view); - have_selection = GTK_WIDGET_HAS_FOCUS (cal_view) && selected != NULL; - if (selected == NULL) { cal_view->priv->view_menu = gnome_calendar_setup_view_popup (cal_view->priv->calendar); main_items[9].submenu = cal_view->priv->view_menu; @@ -1260,15 +1330,158 @@ e_cal_view_create_popup_menu (ECalView *cal_view) client = event->comp_data->client; } - if (cal_client_is_read_only (client)) + cal_client_is_read_only (client, &read_only, NULL); + if (read_only) disable_mask |= MASK_EDITABLE; - if (being_edited) - disable_mask |= MASK_EDITING; - setup_popup_icons (context_menu); popup = e_popup_menu_create (context_menu, disable_mask, hide_mask, cal_view); g_signal_connect (popup, "selection-done", G_CALLBACK (free_view_popup), cal_view); return popup; } + +/** + * e_cal_view_new_appointment_for + * @cal_view: A calendar view. + * @dtstart: A Unix time_t that marks the beginning of the appointment. + * @dtend: A Unix time_t that marks the end of the appointment. + * @all_day: If TRUE, the dtstart and dtend are expanded to cover + * the entire day, and the event is set to TRANSPARENT. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an event editor dialog for a new appointment. + */ +void +e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, time_t dtend, + gboolean all_day, + gboolean meeting) +{ + ECalViewPrivate *priv; + struct icaltimetype itt; + CalComponentDateTime dt; + CalComponent *comp; + icalcomponent *icalcomp; + CalComponentTransparency transparency; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + priv = cal_view->priv; + + dt.value = &itt; + if (all_day) + dt.tzid = NULL; + else + dt.tzid = icaltimezone_get_tzid (priv->zone); + + icalcomp = e_cal_model_create_component_with_defaults (priv->model); + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + /* DTSTART, DTEND */ + itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); + if (all_day) { + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtstart (comp, &dt); + + itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); + if (all_day) { + /* We round it up to the end of the day, unless it is + already set to midnight */ + if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { + icaltime_adjust (&itt, 1, 0, 0, 0); + } + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtend (comp, &dt); + + /* TRANSPARENCY */ + transparency = all_day ? CAL_COMPONENT_TRANSP_TRANSPARENT + : CAL_COMPONENT_TRANSP_OPAQUE; + cal_component_set_transparency (comp, transparency); + + /* CATEGORY */ + cal_component_set_categories (comp, priv->default_category); + + /* edit the object */ + cal_component_commit_sequence (comp); + + e_cal_view_edit_appointment (cal_view, + e_cal_model_get_default_client (priv->model), + icalcomp, meeting); + + g_object_unref (comp); +} + +/** + * e_cal_view_new_appointment + * @cal_view: A calendar view. + * + * Opens an event editor dialog for a new appointment. The appointment's + * start and end times are set to the currently selected time range in + * the calendar view. + */ +void +e_cal_view_new_appointment (ECalView *cal_view) +{ + time_t dtstart, dtend; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, FALSE); +} + +/** + * e_cal_view_edit_appointment + * @cal_view: A calendar view. + * @client: Calendar client. + * @icalcomp: The object to be edited. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an editor window to allow the user to edit the selected + * object. + */ +void +e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting) +{ + ECalViewPrivate *priv; + CompEditor *ce; + const char *uid; + CalComponent *comp; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + g_return_if_fail (IS_CAL_CLIENT (client)); + g_return_if_fail (icalcomp != NULL); + + priv = cal_view->priv; + + uid = icalcomponent_get_uid (icalcomp); + + ce = e_comp_editor_registry_find (comp_editor_registry, uid); + if (!ce) { + EventEditor *ee; + + ee = event_editor_new (client); + ce = COMP_EDITOR (ee); + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); + comp_editor_edit_comp (ce, comp); + if (meeting) + event_editor_show_meeting (ee); + + e_comp_editor_registry_add (comp_editor_registry, ce, FALSE); + + g_object_unref (comp); + } + + comp_editor_focus (ce); +} diff --git a/calendar/gui/e-calendar-view.h b/calendar/gui/e-calendar-view.h index ea7c11a00d..9a09a5236a 100644 --- a/calendar/gui/e-calendar-view.h +++ b/calendar/gui/e-calendar-view.h @@ -96,6 +96,8 @@ ECalModel *e_cal_view_get_model (ECalView *cal_view); void e_cal_view_set_model (ECalView *cal_view, ECalModel *model); icaltimezone *e_cal_view_get_timezone (ECalView *cal_view); void e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone); +const char *e_cal_view_get_default_category (ECalView *cal_view); +void e_cal_view_set_default_category (ECalView *cal_view, const char *category); void e_cal_view_set_status_message (ECalView *cal_view, const gchar *message); @@ -114,6 +116,17 @@ void e_cal_view_delete_selected_occurrence (ECalView *cal_view); GtkMenu *e_cal_view_create_popup_menu (ECalView *cal_view); +void e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, + time_t dtend, + gboolean all_day, + gboolean meeting); +void e_cal_view_new_appointment (ECalView *cal_view); +void e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting); + G_END_DECLS #endif diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index a2a4f09d56..b4ec9faea0 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -65,6 +65,7 @@ #include "calendar-commands.h" #include "calendar-config.h" #include "goto.h" +#include "e-cal-model-calendar.h" #include "e-day-view-time-item.h" #include "e-day-view-top-item.h" #include "e-day-view-layout.h" @@ -592,8 +593,6 @@ e_day_view_init (EDayView *day_view) day_view->auto_scroll_timeout_id = 0; - day_view->default_category = NULL; - day_view->large_font_desc = NULL; /* String to use in 12-hour time format for times in the morning. */ @@ -850,8 +849,11 @@ GtkWidget * e_day_view_new (void) { GtkWidget *day_view; + ECalModel *model; + + model = E_CAL_MODEL (e_cal_model_calendar_new ()); - day_view = GTK_WIDGET (g_object_new (e_day_view_get_type (), NULL)); + day_view = GTK_WIDGET (g_object_new (e_day_view_get_type (), "model", model, NULL)); return day_view; } @@ -881,12 +883,6 @@ e_day_view_destroy (GtkObject *object) day_view->large_font_desc = NULL; } - if (day_view->default_category) { - g_free (day_view->default_category); - day_view->default_category = NULL; - } - - if (day_view->normal_cursor) { gdk_cursor_unref (day_view->normal_cursor); day_view->normal_cursor = NULL; @@ -1429,26 +1425,6 @@ e_day_view_focus_out (GtkWidget *widget, GdkEventFocus *event) return FALSE; } -/** - * e_day_view_set_default_category: - * @day_view: A day view. - * @category: Default category name or NULL for no category. - * - * Sets the default category that will be used when creating new calendar - * components from the day view. - **/ -void -e_day_view_set_default_category (EDayView *day_view, const char *category) -{ - g_return_if_fail (day_view != NULL); - g_return_if_fail (E_IS_DAY_VIEW (day_view)); - - if (day_view->default_category) - g_free (day_view->default_category); - - day_view->default_category = g_strdup (category); -} - static gboolean e_day_view_update_event_cb (EDayView *day_view, gint day, @@ -1794,6 +1770,9 @@ e_day_view_find_event_from_uid (EDayView *day_view, gint day, event_num; const char *u; + if (!uid) + return FALSE; + for (day = 0; day < day_view->days_shown; day++) { for (event_num = 0; event_num < day_view->events[day]->len; event_num++) { @@ -2048,7 +2027,6 @@ e_day_view_find_work_week_start (EDayView *day_view, return icaltime_as_timet_with_zone (tt, e_cal_view_get_timezone (E_CAL_VIEW (day_view))); } - /* Returns the selected time range. */ static void e_day_view_get_selected_time_range (ECalView *cal_view, time_t *start_time, time_t *end_time) @@ -2123,6 +2101,8 @@ e_day_view_recalc_day_starts (EDayView *day_view, day_view->lower = start_time; day_view->upper = day_view->day_starts[day_view->days_shown]; + + e_day_view_update_query (day_view); } @@ -2588,9 +2568,9 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget, time_t dtstart, dtend; e_day_view_get_selected_time_range ((ECalView *) day_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (e_cal_view_get_calendar (E_CAL_VIEW (day_view)), - dtstart, dtend, - TRUE, FALSE); + e_cal_view_new_appointment_for (E_CAL_VIEW (day_view), + dtstart, dtend, + TRUE, FALSE); return TRUE; } @@ -2709,9 +2689,9 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, time_t dtstart, dtend; e_day_view_get_selected_time_range ((ECalView *) day_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (e_cal_view_get_calendar (E_CAL_VIEW (day_view)), - dtstart, dtend, - FALSE, FALSE); + e_cal_view_new_appointment_for (E_CAL_VIEW (day_view), + dtstart, dtend, + FALSE, FALSE); return TRUE; } @@ -3101,7 +3081,6 @@ e_day_view_on_event_double_click (EDayView *day_view, gint event_num) { EDayViewEvent *event; - GnomeCalendar *calendar; if (day == -1) event = &g_array_index (day_view->long_events, EDayViewEvent, @@ -3112,11 +3091,9 @@ e_day_view_on_event_double_click (EDayView *day_view, e_day_view_stop_editing_event (day_view); - calendar = e_cal_view_get_calendar (E_CAL_VIEW (day_view)); - if (calendar) - gnome_calendar_edit_object (calendar, event->comp_data->client, event->comp_data->icalcomp, FALSE); - else - g_warning ("Calendar not set"); + e_cal_view_edit_appointment (E_CAL_VIEW (day_view), + event->comp_data->client, + event->comp_data->icalcomp, FALSE); } static void @@ -3207,7 +3184,6 @@ process_component (EDayView *day_view, ECalModelComponent *comp_data) EDayViewEvent, event_num); if (!cal_util_component_has_recurrences (comp_data->icalcomp) - && !cal_component_has_recurrences (event->comp_data->icalcomp) && cal_util_event_dates_match (event->comp_data->icalcomp, comp_data->icalcomp)) { #if 0 g_print ("updated object's dates unchanged\n"); @@ -3228,17 +3204,18 @@ process_component (EDayView *day_view, ECalModelComponent *comp_data) NULL); } - /* Add the occurrences of the event. */ + /* Add the occurrences of the event */ comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp)); + add_event_data.day_view = day_view; add_event_data.comp_data = comp_data; cal_recur_generate_instances (comp, day_view->lower, day_view->upper, e_day_view_add_event, &add_event_data, - cal_client_resolve_tzid_cb, - comp_data->client, + cal_client_resolve_tzid_cb, comp_data->client, e_cal_view_get_timezone (E_CAL_VIEW (day_view))); + g_object_unref (comp); e_day_view_queue_layout (day_view); @@ -3258,8 +3235,6 @@ e_day_view_update_query (ECalView *cal_view) e_day_view_free_events (day_view); e_day_view_queue_layout (day_view); - e_cal_view_set_status_message (E_CAL_VIEW (day_view), _("Searching")); - rows = e_table_model_row_count (E_TABLE_MODEL (e_cal_view_get_model (E_CAL_VIEW (day_view)))); for (r = 0; r < rows; r++) { ECalModelComponent *comp_data; @@ -3268,8 +3243,6 @@ e_day_view_update_query (ECalView *cal_view) g_assert (comp_data != NULL); process_component (day_view, comp_data); } - - e_cal_view_set_status_message (E_CAL_VIEW (day_view), NULL); } static void @@ -3282,67 +3255,6 @@ e_day_view_on_event_right_click (EDayView *day_view, day, event_num); } -void -e_day_view_unrecur_appointment (EDayView *day_view) -{ - EDayViewEvent *event; - CalComponent *comp, *new_comp; - CalComponentDateTime date; - struct icaltimetype itt; - - event = e_day_view_get_popup_menu_event (day_view); - if (event == NULL) - return; - - date.value = &itt; - date.tzid = NULL; - - /* For the recurring object, we add an exception to get rid of the - instance. */ - - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - - /* For the unrecurred instance we duplicate the original object, - create a new uid for it, get rid of the recurrence rules, and set - the start & end times to the instances times. */ - new_comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_component_set_uid (new_comp, cal_component_gen_uid ()); - cal_component_set_rdate_list (new_comp, NULL); - cal_component_set_rrule_list (new_comp, NULL); - cal_component_set_exdate_list (new_comp, NULL); - cal_component_set_exrule_list (new_comp, NULL); - - date.value = &itt; - date.tzid = icaltimezone_get_tzid (e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - - *date.value = icaltime_from_timet_with_zone (event->start, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - cal_component_set_dtstart (new_comp, &date); - *date.value = icaltime_from_timet_with_zone (event->end, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - cal_component_set_dtend (new_comp, &date); - - - /* Now update both CalComponents. Note that we do this last since at - * present the updates happen synchronously so our event may disappear. - */ - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_day_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (comp); - - if (cal_client_update_object (event->comp_data->client, new_comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_day_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (new_comp); -} - - static EDayViewEvent* e_day_view_get_popup_menu_event (EDayView *day_view) { @@ -3841,7 +3753,9 @@ e_day_view_finish_long_event_resize (EDayView *day_view) struct icaltimetype itt; time_t dt; CalClient *client; - + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; + event_num = day_view->resize_event_num; event = &g_array_index (day_view->long_events, EDayViewEvent, event_num); @@ -3870,31 +3784,26 @@ e_day_view_finish_long_event_resize (EDayView *day_view) e_cal_view_get_timezone (E_CAL_VIEW (day_view))); cal_component_set_dtend (comp, &date); } - - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_resize(): Could not update the object!"); - } - } else { + + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { gtk_widget_queue_draw (day_view->top_canvas); - } - } else if (cal_client_update_object (client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, TRUE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_long_event_resize(): Could not update the object!"); - } - + goto out; + } + } + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { + if (itip_organizer_is_user (comp, client) && + send_component_dialog (toplevel, client, comp, TRUE)) { + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); + } else { + g_message (G_STRLOC ": Could not update the object!"); + } + } + + out: gnome_canvas_item_hide (day_view->resize_long_event_rect_item); day_view->resize_drag_pos = E_CAL_VIEW_POS_NONE; @@ -3915,6 +3824,8 @@ e_day_view_finish_resize (EDayView *day_view) struct icaltimetype itt; time_t dt; CalClient *client; + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; day = day_view->resize_event_day; event_num = day_view->resize_event_num; @@ -3957,29 +3868,26 @@ e_day_view_finish_resize (EDayView *day_view) day_view->resize_drag_pos = E_CAL_VIEW_POS_NONE; - if (cal_component_is_instance (comp)) { - CalObjModType mod; + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + gtk_widget_queue_draw (day_view->top_canvas); + goto out; + } + } + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_resize(): Could not update the object!"); - } - } else { - gtk_widget_queue_draw (day_view->main_canvas); - } - } else if (cal_client_update_object (client, comp) == CAL_CLIENT_RESULT_SUCCESS) { + cal_component_commit_sequence (comp); + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), client, comp, FALSE)) + send_component_dialog (toplevel, client, comp, TRUE)) { itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_resize(): Could not update the object!"); - } - + } else { + g_message (G_STRLOC ": Could not update the object!"); + } + } + + out: g_object_unref (comp); } @@ -4774,6 +4682,8 @@ e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event) /* Add a new event covering the selected range */ icalcomp = e_cal_model_create_component_with_defaults (e_cal_view_get_model (E_CAL_VIEW (day_view))); + if (!icalcomp) + return FALSE; uid = icalcomponent_get_uid (icalcomp); comp = cal_component_new (); @@ -4801,7 +4711,8 @@ e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event) cal_component_set_dtstart (comp, &start_dt); cal_component_set_dtend (comp, &end_dt); - cal_component_set_categories (comp, day_view->default_category); + cal_component_set_categories ( + comp, e_cal_view_get_default_category (E_CAL_VIEW (day_view))); /* We add the event locally and start editing it. We don't send it to the server until the user finishes editing it. */ @@ -5777,7 +5688,8 @@ e_day_view_on_editing_stopped (EDayView *day_view, gchar *text = NULL; CalComponentText summary; CalComponent *comp; - + gboolean on_server; + /* Note: the item we are passed here isn't reliable, so we just stop the edit of whatever item was being edited. We also receive this event twice for some reason. */ @@ -5822,8 +5734,9 @@ e_day_view_on_editing_stopped (EDayView *day_view, comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - if (string_is_empty (text) && - !cal_comp_is_on_server (comp, event->comp_data->client)) { + on_server = cal_comp_is_on_server (comp, event->comp_data->client); + + if (string_is_empty (text) && !on_server) { const char *uid; cal_component_get_uid (comp, &uid); @@ -5845,34 +5758,34 @@ e_day_view_on_editing_stopped (EDayView *day_view, e_day_view_update_event_label (day_view, day, event_num); } else if (summary.value || !string_is_empty (text)) { + icalcomponent *icalcomp = cal_component_get_icalcomponent (comp); + summary.value = text; summary.altrep = NULL; cal_component_set_summary (comp, &summary); - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (event->comp_data->client, comp, mod) - == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_day_view_on_editing_stopped(): Could not update the object!"); + if (!on_server) { + if (!cal_client_create_object (event->comp_data->client, icalcomp, NULL, NULL)) + g_message (G_STRLOC ": Could not create the object!"); + } else { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + goto out; } } - } else if (cal_client_update_object (event->comp_data->client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_day_view_on_editing_stopped(): Could not update the object!"); + + /* FIXME When sending here, what exactly should we send? */ + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + if (cal_client_modify_object (event->comp_data->client, icalcomp, mod, NULL)) { + if (itip_organizer_is_user (comp, event->comp_data->client) + && send_component_dialog (toplevel, event->comp_data->client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + event->comp_data->client, NULL); + } } + } out: @@ -6881,7 +6794,10 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget, x, y, &day, NULL); if (pos != E_CAL_VIEW_POS_OUTSIDE) { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; const char *uid; + num_days = 1; start_offset = 0; end_offset = 0; @@ -6972,33 +6888,20 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget, if (event->canvas_item) gnome_canvas_item_show (event->canvas_item); - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } else { - g_message ("e_day_view_on_top_canvas_drag_data_received(): Could " - "not update the object!"); - } - } - } else if (cal_client_update_object (client, comp) - == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } else { - g_message ("e_day_view_on_top_canvas_drag_data_received(): Could " - "not update the object!"); + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) + return; } + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { + if (itip_organizer_is_user (comp, client) + && send_component_dialog (toplevel, client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + client, NULL); + } + g_object_unref (comp); return; @@ -7044,7 +6947,10 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget, x, y, &day, &row, NULL); if (pos != E_CAL_VIEW_POS_OUTSIDE) { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; const char *uid; + num_rows = 1; start_offset = 0; end_offset = 0; @@ -7109,30 +7015,20 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget, if (event->canvas_item) gnome_canvas_item_show (event->canvas_item); - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } else { - g_message ("e_day_view_on_top_canvas_drag_data_received(): Could " - "not update the object!"); - } + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + g_object_unref (comp); + return; } - } else if (cal_client_update_object (client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + } + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { + if (itip_organizer_is_user (comp, client) + && send_component_dialog (toplevel, client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_on_main_canvas_drag_data_received(): " - "Could not update the object!"); } g_object_unref (comp); diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index 1c39fd5844..decd281127 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -453,9 +453,6 @@ struct _EDayView gint am_string_width; gint pm_string_width; - /* The default category for new events */ - char *default_category; - /* The activity client used to show messages on the status bar. */ EvolutionActivityClient *activity; }; @@ -472,9 +469,6 @@ GtkWidget* e_day_view_new (void); void e_day_view_set_query (EDayView *day_view, const char *sexp); -void e_day_view_set_default_category (EDayView *day_view, - const char *category); - /* Whether we are displaying a work-week, in which case the display always starts on the first day of the working week. */ gboolean e_day_view_get_work_week_view (EDayView *day_view); @@ -528,7 +522,6 @@ void e_day_view_set_week_start_day (EDayView *day_view, gint week_start_day); void e_day_view_delete_occurrence (EDayView *day_view); -void e_day_view_unrecur_appointment (EDayView *day_view); /* Returns the number of selected events (0 or 1 at present). */ gint e_day_view_get_num_events_selected (EDayView *day_view); diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c index 8b39b82b8c..d5e24c8936 100644 --- a/calendar/gui/e-itip-control.c +++ b/calendar/gui/e-itip-control.c @@ -94,8 +94,6 @@ struct _EItipControlPrivate { #define HTML_BODY_END "</body>" #define HTML_FOOTER "</html>" -extern EvolutionShellClient *global_shell_client; - /* We intentionally use "calendar" instead of "calendar / *" here. We * don't want public calendars. */ @@ -132,63 +130,26 @@ class_init (EItipControlClass *klass) object_class->finalize = finalize; } - -/* Calendar Server routines */ -static void -start_calendar_server_cb (CalClient *cal_client, - CalClientOpenStatus status, - gpointer data) -{ - int *success = data; - int orig = *success; - - if (status == CAL_CLIENT_OPEN_SUCCESS) - *success = 1; - else - *success = 0; - - if (orig != -1) - gtk_main_quit (); /* end the sub event loop */ -} - static CalClient * start_calendar_server (EItipControl *itip, char *uri) { CalClient *client; - int success = -1; - - client = cal_client_new (); - - g_signal_connect (client, "cal_opened", G_CALLBACK (start_calendar_server_cb), &success); - - if (!cal_client_open_calendar (client, uri, TRUE)) - goto error; - - /* run a sub event loop to turn cal-client's async load - notification into a synchronous call */ - if (success == -1 && !itip->priv->destroyed) { - success = 0; - - gtk_signal_connect (GTK_OBJECT (itip), "destroy", - gtk_main_quit, NULL); - - gtk_main (); - - gtk_signal_disconnect_by_func (GTK_OBJECT (itip), - gtk_main_quit, NULL); - } + GError *error = NULL; - if (success == 1) - return client; + client = cal_client_new (uri, CALOBJ_TYPE_EVENT); -error: - g_object_unref (client); + if (!cal_client_open (client, TRUE, &error)) { + g_warning (_("start_calendar_server(): %s"), error->message); + g_error_free (error); + g_object_unref (client); + return NULL; + } - return NULL; + return client; } static gboolean -start_default_server_async (EItipControl *itip, CalClient *client, gboolean tasks) +start_default_server (EItipControl *itip, CalClient *client, gboolean tasks) { if (tasks) return cal_client_open_default_tasks (client, FALSE); @@ -196,6 +157,7 @@ start_default_server_async (EItipControl *itip, CalClient *client, gboolean task return cal_client_open_default_calendar (client, FALSE); } +#if 0 /* EPFIXME, rewrite this */ static GPtrArray * get_servers (EItipControl *itip, EvolutionShellClient *shell_client, const char *possible_types[], gboolean tasks) { @@ -263,6 +225,7 @@ get_servers (EItipControl *itip, EvolutionShellClient *shell_client, const char return servers; } +#endif static CalClient * find_server (GPtrArray *servers, CalComponent *comp) @@ -274,11 +237,9 @@ find_server (GPtrArray *servers, CalComponent *comp) for (i = 0; i < servers->len; i++) { CalClient *client; icalcomponent *icalcomp; - CalClientGetStatus status; client = g_ptr_array_index (servers, i); - status = cal_client_get_object (client, uid, &icalcomp); - if (status == CAL_CLIENT_GET_SUCCESS) { + if (cal_client_get_object (client, uid, NULL, &icalcomp, NULL)) { icalcomponent_free (icalcomp); g_object_ref (client); @@ -540,8 +501,7 @@ find_attendee (icalcomponent *ical_comp, const char *address) for (prop = icalcomponent_get_first_property (ical_comp, ICAL_ATTENDEE_PROPERTY); prop != NULL; - prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY)) - { + prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY)) { icalvalue *value; const char *attendee; char *text; @@ -762,6 +722,7 @@ write_recurrence_piece (EItipControl *itip, CalComponent *comp, } else if (!icaltime_is_null_time (r->until)) { CalComponentDateTime dt; + /* FIXME This should get the tzid id, not the whole zone */ dt.value = &r->until; dt.tzid = r->until.zone; @@ -1220,7 +1181,7 @@ get_real_item (EItipControl *itip) CalComponent *comp; icalcomponent *icalcomp; CalComponentVType type; - CalClientGetStatus status = CAL_CLIENT_GET_NOT_FOUND; + gboolean found = FALSE; const char *uid; priv = itip->priv; @@ -1231,17 +1192,17 @@ get_real_item (EItipControl *itip) switch (type) { case CAL_COMPONENT_EVENT: if (priv->event_client != NULL) - status = cal_client_get_object (priv->event_client, uid, &icalcomp); + found = cal_client_get_object (priv->event_client, uid, NULL, &icalcomp, NULL); break; case CAL_COMPONENT_TODO: if (priv->task_client != NULL) - status = cal_client_get_object (priv->task_client, uid, &icalcomp); + found = cal_client_get_object (priv->task_client, uid, NULL, &icalcomp, NULL); break; default: - status = CAL_CLIENT_GET_NOT_FOUND; + found = FALSE; } - if (status != CAL_CLIENT_GET_SUCCESS) + if (!found) return NULL; comp = cal_component_new (); @@ -1568,13 +1529,18 @@ show_current (EItipControl *itip) switch (type) { case CAL_COMPONENT_EVENT: - if (!priv->event_clients) - priv->event_clients = get_servers (itip, global_shell_client, calendar_types, FALSE); + if (!priv->event_clients) { + priv->event_clients = g_ptr_array_new (); + /* EPFIXME */ + /* priv->event_clients = get_servers (itip, global_shell_client, calendar_types, FALSE); */ + } show_current_event (itip); break; case CAL_COMPONENT_TODO: - if (!priv->task_clients) - priv->task_clients = get_servers (itip, global_shell_client, tasks_types, TRUE); + if (!priv->task_clients) { + /* EPFIXME */ + /* priv->task_clients = get_servers (itip, global_shell_client, tasks_types, TRUE); */ + } show_current_todo (itip); break; case CAL_COMPONENT_FREEBUSY: @@ -1853,7 +1819,6 @@ update_item (EItipControl *itip) CalClient *client; CalComponentVType type; GtkWidget *dialog; - CalClientResult result; priv = itip->priv; @@ -1881,32 +1846,18 @@ update_item (EItipControl *itip) icalcomponent_add_component (priv->top_level, clone); icalcomponent_set_method (priv->top_level, priv->method); - result = cal_client_update_objects (client, priv->top_level); - switch (result) { - case CAL_CLIENT_RESULT_INVALID_OBJECT : - dialog = gnome_warning_dialog (_("Object is invalid and cannot be updated\n")); - break; - case CAL_CLIENT_RESULT_CORBA_ERROR : - dialog = gnome_warning_dialog (_("There was an error on the CORBA system\n")); - break; - case CAL_CLIENT_RESULT_NOT_FOUND : - dialog = gnome_warning_dialog (_("Object could not be found\n")); - break; - case CAL_CLIENT_RESULT_PERMISSION_DENIED : - dialog = gnome_warning_dialog (_("You do not have the right permissions to update the calendar\n")); - break; - case CAL_CLIENT_RESULT_SUCCESS : - dialog = gnome_ok_dialog (_("Update complete\n")); - break; - default : + /* FIXME Better error dialog */ + if (!cal_client_receive_objects (client, priv->top_level, NULL)) { dialog = gnome_warning_dialog (_("Calendar file could not be updated!\n")); - break; + } else { + dialog = gnome_ok_dialog (_("Update complete\n")); } gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); icalcomponent_remove_component (priv->top_level, clone); } +#if 0 static void update_attendee_status (EItipControl *itip) { @@ -1936,7 +1887,7 @@ update_attendee_status (EItipControl *itip) /* Obtain our version */ cal_component_get_uid (priv->comp, &uid); - status = cal_client_get_object (client, uid, &icalcomp); + status = cal_client_get_object (client, uid, NULL, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { GSList *attendees; @@ -2010,6 +1961,7 @@ update_attendee_status (EItipControl *itip) g_object_unref (comp); gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); } +#endif static void remove_item (EItipControl *itip) @@ -2019,7 +1971,7 @@ remove_item (EItipControl *itip) CalComponentVType type; const char *uid; GtkWidget *dialog; - CalClientResult result; + GError *error = NULL; priv = itip->priv; @@ -2033,13 +1985,15 @@ remove_item (EItipControl *itip) return; cal_component_get_uid (priv->comp, &uid); - result = cal_client_remove_object (client, uid); - if (result == CAL_CLIENT_RESULT_SUCCESS || result == CAL_CLIENT_RESULT_NOT_FOUND) { + cal_client_remove_object (client, uid, &error); + if (!error || error->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) { dialog = gnome_ok_dialog (_("Removal Complete")); gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); } else { - delete_error_dialog (result, type); - } + delete_error_dialog (error, type); + } + + g_clear_error (&error); } static void @@ -2081,7 +2035,7 @@ send_freebusy (EItipControl *itip) CalComponentDateTime datetime; time_t start, end; GtkWidget *dialog; - GList *comp_list; + GList *comp_list = NULL; icaltimezone *zone; priv = itip->priv; @@ -2106,9 +2060,7 @@ send_freebusy (EItipControl *itip) end = icaltime_as_timet_with_zone (*datetime.value, zone); cal_component_free_datetime (&datetime); - comp_list = cal_client_get_free_busy (priv->event_client, NULL, start, end); - - if (comp_list) { + if (cal_client_get_free_busy (priv->event_client, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -2210,6 +2162,7 @@ default_server_started_cb (CalClient *client, CalClientOpenStatus status, gpoint vtype = cal_component_get_vtype (priv->comp); switch (vtype) { +#if 0 /* EPFIXME */ case CAL_COMPONENT_EVENT: button = evolution_folder_selector_button_new ( global_shell_client, _("Select Calendar Folder"), @@ -2222,6 +2175,7 @@ default_server_started_cb (CalClient *client, CalClientOpenStatus status, gpoint calendar_config_default_tasks_folder (), tasks_types); break; +#endif default: button = NULL; } @@ -2251,29 +2205,30 @@ object_requested_cb (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) context = g_new0 (ObjectRequestContext, 1); context->itip = itip; context->eb = eb; - context->client = cal_client_new (); - - g_object_ref (itip); - g_signal_connect (context->client, "cal_opened", - G_CALLBACK (default_server_started_cb), context); + /* FIXME: use the default URIs */ switch (vtype) { case CAL_COMPONENT_EVENT: - success = start_default_server_async (itip, context->client, FALSE); + context->client = cal_client_new ("", CALOBJ_TYPE_EVENT); + success = start_default_server (itip, context->client, FALSE); break; case CAL_COMPONENT_TODO: - success = start_default_server_async (itip, context->client, TRUE); + context->client = cal_client_new ("", CALOBJ_TYPE_TODO); + success = start_default_server (itip, context->client, TRUE); break; default: - success = FALSE; + g_free (context); + return FALSE; } if (!success) { - g_object_unref (itip); g_object_unref (context->client); g_free (context); + return FALSE; } + g_object_ref (itip); + return TRUE; } @@ -2330,7 +2285,8 @@ ok_clicked_cb (GtkHTML *html, const gchar *method, const gchar *url, const gchar send_freebusy (itip); break; case 'R': - update_attendee_status (itip); + /* FIXME Make sure this does the right thing in the backend */ + update_item (itip); break; case 'S': send_item (itip); diff --git a/calendar/gui/e-meeting-list-view.c b/calendar/gui/e-meeting-list-view.c index 7d3a4ce6c6..64463fdcb6 100644 --- a/calendar/gui/e-meeting-list-view.c +++ b/calendar/gui/e-meeting-list-view.c @@ -35,11 +35,7 @@ #include <libgnome/gnome-util.h> #include <libgnomevfs/gnome-vfs.h> #include <ebook/e-book.h> -#include <ebook/e-book-util.h> -#include <ebook/e-card-types.h> -#include <ebook/e-card-cursor.h> -#include <ebook/e-card.h> -#include <ebook/e-card-simple.h> +#include <ebook/e-vcard.h> #include <cal-util/cal-component.h> #include <cal-util/cal-util.h> #include <cal-util/timeutil.h> @@ -47,6 +43,7 @@ #include "calendar-config.h" #include "e-meeting-list-view.h" #include <misc/e-cell-renderer-combo.h> +#include <addressbook/util/eab-destination.h> #include "e-select-names-renderer.h" #define SELECT_NAMES_OAFID "OAFIID:GNOME_Evolution_Addressbook_SelectNames" @@ -56,8 +53,6 @@ struct _EMeetingListViewPrivate EMeetingStore *store; EBook *ebook; - gboolean book_loaded; - gboolean book_load_wait; GNOME_Evolution_Addressbook_SelectNames corba_select_names; }; @@ -78,26 +73,17 @@ static icalparameter_role roles[] = {ICAL_ROLE_CHAIR, static GtkTreeViewClass *parent_class = NULL; static void -book_open_cb (EBook *book, EBookStatus status, gpointer data) -{ - EMeetingListView *view = E_MEETING_LIST_VIEW (data); - - if (status == E_BOOK_STATUS_SUCCESS) - view->priv->book_loaded = TRUE; - else - g_warning ("Book not loaded"); - - if (view->priv->book_load_wait) { - view->priv->book_load_wait = FALSE; - gtk_main_quit (); - } -} - -static void start_addressbook_server (EMeetingListView *view) { + GError *error = NULL; + view->priv->ebook = e_book_new (); - e_book_load_default_book (view->priv->ebook, book_open_cb, view); + if (!e_book_load_local_addressbook (view->priv->ebook, &error)) { + g_warning ("start_addressbook_server(): %s", error->message); + g_error_free (error); + + return; + } } static void @@ -319,49 +305,41 @@ e_meeting_list_view_column_set_visible (EMeetingListView *view, const gchar *col } static void -process_section (EMeetingListView *view, GNOME_Evolution_Addressbook_SimpleCardList *cards, icalparameter_role role) +process_section (EMeetingListView *view, EABDestination **cards, icalparameter_role role) { EMeetingListViewPrivate *priv; int i; priv = view->priv; - for (i = 0; i < cards->_length; i++) { - const char *name, *attendee = NULL, *attr; - GNOME_Evolution_Addressbook_SimpleCard card; - CORBA_Environment ev; + for (i = 0; i < G_N_ELEMENTS (cards); i++) { + const char *name, *attendee = NULL; + char *attr = NULL; - card = cards->_buffer[i]; - - CORBA_exception_init (&ev); - - /* Get the CN */ - name = GNOME_Evolution_Addressbook_SimpleCard_get (card, GNOME_Evolution_Addressbook_SimpleCard_FullName, &ev); - if (BONOBO_EX (&ev)) { - CORBA_exception_free (&ev); - continue; - } + name = eab_destination_get_name (cards[i]); /* Get the field as attendee from the backend */ - attr = cal_client_get_ldap_attribute (e_meeting_store_get_cal_client (priv->store)); - if (attr) { + if (cal_client_get_ldap_attribute (e_meeting_store_get_cal_client (priv->store), + &attr, NULL)) { /* FIXME this should be more general */ - if (!g_ascii_strcasecmp (attr, "icscalendar")) - attendee = GNOME_Evolution_Addressbook_SimpleCard_get (card, GNOME_Evolution_Addressbook_SimpleCard_Icscalendar, &ev); + if (!g_ascii_strcasecmp (attr, "icscalendar")) { + EContact *contact; + + /* FIXME: this does not work, have to use first + eab_destination_use_contact() */ + contact = eab_destination_get_contact (cards[i]); + if (contact) { + attendee = e_contact_get (contact, E_CONTACT_FREEBUSY_URL); + if (!attendee) + attendee = e_contact_get (contact, E_CONTACT_CALENDAR_URI); + } + } } - CORBA_exception_init (&ev); - /* If we couldn't get the attendee prior, get the email address as the default */ if (attendee == NULL || *attendee == '\0') { - attendee = GNOME_Evolution_Addressbook_SimpleCard_get (card, GNOME_Evolution_Addressbook_SimpleCard_Email, &ev); - if (BONOBO_EX (&ev)) { - CORBA_exception_free (&ev); - continue; - } + attendee = eab_destination_get_email (cards[i]); } - CORBA_exception_free (&ev); - if (attendee == NULL || *attendee == '\0') continue; @@ -381,22 +359,21 @@ static void select_names_ok_cb (BonoboListener *listener, const char *event_name, const CORBA_any *arg, CORBA_Environment *ev, gpointer data) { EMeetingListView *view = E_MEETING_LIST_VIEW (data); - BonoboArg *card_arg; int i; for (i = 0; sections[i] != NULL; i++) { + EABDestination **destv; + char *string = NULL; Bonobo_Control corba_control = GNOME_Evolution_Addressbook_SelectNames_getEntryBySection (view->priv->corba_select_names, sections[i], ev); GtkWidget *control_widget = bonobo_widget_new_control_from_objref (corba_control, CORBA_OBJECT_NIL); - BonoboControlFrame *control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_widget)); - Bonobo_PropertyBag pb = bonobo_control_frame_get_control_property_bag (control_frame, NULL); - card_arg = bonobo_property_bag_client_get_value_any (pb, "simple_card_list", NULL); - if (card_arg != NULL) { - GNOME_Evolution_Addressbook_SimpleCardList cards; - cards = BONOBO_ARG_GET_GENERAL (card_arg, TC_GNOME_Evolution_Addressbook_SimpleCardList, - GNOME_Evolution_Addressbook_SimpleCardList, NULL); - process_section (view, &cards, roles[i]); - bonobo_arg_release (card_arg); + + bonobo_widget_get_property (BONOBO_WIDGET (control_widget), "destinations", + TC_CORBA_string, &string, NULL); + destv = eab_destination_importv (string); + if (destv) { + process_section (view, destv, roles[i]); + g_free (destv); } } } diff --git a/calendar/gui/e-meeting-model.c b/calendar/gui/e-meeting-model.c new file mode 100644 index 0000000000..4742116cf2 --- /dev/null +++ b/calendar/gui/e-meeting-model.c @@ -0,0 +1,1780 @@ +/* -*- Mod:e C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* itip-model.c + * + * Copyright (C) 2001 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: JP Rosevear + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-widget.h> +#include <bonobo/bonobo-exception.h> +#include <libgnome/gnome-i18n.h> +#include <libgnome/gnome-util.h> +#include <libgnomevfs/gnome-vfs.h> +#include <gal/e-table/e-table-without.h> +#include <gal/e-table/e-cell-text.h> +#include <gal/e-table/e-cell-popup.h> +#include <gal/e-table/e-cell-combo.h> +#include <addressbook/util/eab-destination.h> +#include <ebook/e-book.h> +#include <ebook/e-book-async.h> +#include <ebook/e-contact.h> +#include <cal-util/cal-component.h> +#include <cal-util/cal-util.h> +#include <cal-util/timeutil.h> +#include "Evolution-Addressbook-SelectNames.h" +#include "calendar-config.h" +#include "itip-utils.h" +#include "e-meeting-utils.h" +#include "e-meeting-attendee.h" +#include "e-meeting-model.h" + +#define SELECT_NAMES_OAFID "OAFIID:GNOME_Evolution_Addressbook_SelectNames" + +struct _EMeetingModelPrivate +{ + GPtrArray *attendees; + + GList *tables; + + CalClient *client; + icaltimezone *zone; + + EBook *ebook; + gboolean book_loaded; + gboolean book_load_wait; + + GPtrArray *refresh_queue; + GHashTable *refresh_data; + guint refresh_idle_id; + + /* For invite others dialogs */ + GNOME_Evolution_Addressbook_SelectNames corba_select_names; +}; + +#define BUF_SIZE 1024 + +static char *sections[] = {N_("Chair Persons"), + N_("Required Participants"), + N_("Optional Participants"), + N_("Resources"), + NULL}; +static icalparameter_role roles[] = {ICAL_ROLE_CHAIR, + ICAL_ROLE_REQPARTICIPANT, + ICAL_ROLE_OPTPARTICIPANT, + ICAL_ROLE_NONPARTICIPANT, + ICAL_ROLE_NONE}; + +typedef struct _EMeetingModelQueueData EMeetingModelQueueData; +struct _EMeetingModelQueueData { + EMeetingModel *im; + EMeetingAttendee *ia; + + gboolean refreshing; + + EMeetingTime start; + EMeetingTime end; + + char buffer[BUF_SIZE]; + GString *string; + + GPtrArray *call_backs; + GPtrArray *data; +}; + + +static void class_init (EMeetingModelClass *klass); +static void init (EMeetingModel *model); +static void finalize (GObject *obj); + +static void refresh_queue_add (EMeetingModel *im, int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data); +static void refresh_queue_remove (EMeetingModel *im, + EMeetingAttendee *ia); +static gboolean refresh_busy_periods (gpointer data); + +static void attendee_changed_cb (EMeetingAttendee *ia, gpointer data); +static void select_names_ok_cb (BonoboListener *listener, + const char *event_name, + const CORBA_any *arg, + CORBA_Environment *ev, + gpointer data); + +static void table_destroy_state_cb (ETableScrolled *etable, gpointer data); +static void table_destroy_list_cb (ETableScrolled *etable, gpointer data); + +static ETableModelClass *parent_class = NULL; + +E_MAKE_TYPE (e_meeting_model, "EMeetingModel", EMeetingModel, + class_init, init, E_TABLE_MODEL_TYPE); + +static void +book_open_cb (EBook *book, EBookStatus status, gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + + priv = im->priv; + + priv->ebook = book; + + if (status == E_BOOK_ERROR_OK) + priv->book_loaded = TRUE; + else + g_warning ("Book not loaded"); + + if (priv->book_load_wait) { + priv->book_load_wait = FALSE; + gtk_main_quit (); + } +} + +static void +start_addressbook_server (EMeetingModel *im) +{ + e_book_async_get_default_addressbook (book_open_cb, im); +} + +static EMeetingAttendee * +find_match (EMeetingModel *im, const char *address, int *pos) +{ + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + const gchar *ia_address; + int i; + + priv = im->priv; + + if (address == NULL) + return NULL; + + /* Make sure we can add the new delegatee person */ + for (i = 0; i < priv->attendees->len; i++) { + ia = g_ptr_array_index (priv->attendees, i); + + ia_address = e_meeting_attendee_get_address (ia); + if (ia_address != NULL && !g_strcasecmp (itip_strip_mailto (ia_address), itip_strip_mailto (address))) { + if (pos != NULL) + *pos = i; + return ia; + } + } + + return NULL; +} + +static icalparameter_cutype +text_to_type (const char *type) +{ + if (!g_strcasecmp (type, _("Individual"))) + return ICAL_CUTYPE_INDIVIDUAL; + else if (!g_strcasecmp (type, _("Group"))) + return ICAL_CUTYPE_GROUP; + else if (!g_strcasecmp (type, _("Resource"))) + return ICAL_CUTYPE_RESOURCE; + else if (!g_strcasecmp (type, _("Room"))) + return ICAL_CUTYPE_ROOM; + else + return ICAL_CUTYPE_NONE; +} + +static char * +type_to_text (icalparameter_cutype type) +{ + switch (type) { + case ICAL_CUTYPE_INDIVIDUAL: + return _("Individual"); + case ICAL_CUTYPE_GROUP: + return _("Group"); + case ICAL_CUTYPE_RESOURCE: + return _("Resource"); + case ICAL_CUTYPE_ROOM: + return _("Room"); + default: + return _("Unknown"); + } + + return NULL; + +} + +static icalparameter_role +text_to_role (const char *role) +{ + if (!g_strcasecmp (role, _("Chair"))) + return ICAL_ROLE_CHAIR; + else if (!g_strcasecmp (role, _("Required Participant"))) + return ICAL_ROLE_REQPARTICIPANT; + else if (!g_strcasecmp (role, _("Optional Participant"))) + return ICAL_ROLE_OPTPARTICIPANT; + else if (!g_strcasecmp (role, _("Non-Participant"))) + return ICAL_ROLE_NONPARTICIPANT; + else + return ICAL_ROLE_NONE; +} + +static char * +role_to_text (icalparameter_role role) +{ + switch (role) { + case ICAL_ROLE_CHAIR: + return _("Chair"); + case ICAL_ROLE_REQPARTICIPANT: + return _("Required Participant"); + case ICAL_ROLE_OPTPARTICIPANT: + return _("Optional Participant"); + case ICAL_ROLE_NONPARTICIPANT: + return _("Non-Participant"); + default: + return _("Unknown"); + } + + return NULL; +} + +static gboolean +text_to_boolean (const char *role) +{ + if (!g_strcasecmp (role, _("Yes"))) + return TRUE; + else + return FALSE; +} + +static char * +boolean_to_text (gboolean b) +{ + if (b) + return _("Yes"); + else + return _("No"); +} + +static icalparameter_partstat +text_to_partstat (const char *partstat) +{ + if (!g_strcasecmp (partstat, _("Needs Action"))) + return ICAL_PARTSTAT_NEEDSACTION; + else if (!g_strcasecmp (partstat, _("Accepted"))) + return ICAL_PARTSTAT_ACCEPTED; + else if (!g_strcasecmp (partstat, _("Declined"))) + return ICAL_PARTSTAT_DECLINED; + else if (!g_strcasecmp (partstat, _("Tentative"))) + return ICAL_PARTSTAT_TENTATIVE; + else if (!g_strcasecmp (partstat, _("Delegated"))) + return ICAL_PARTSTAT_DELEGATED; + else if (!g_strcasecmp (partstat, _("Completed"))) + return ICAL_PARTSTAT_COMPLETED; + else if (!g_strcasecmp (partstat, _("In Process"))) + return ICAL_PARTSTAT_INPROCESS; + else + return ICAL_PARTSTAT_NONE; +} + +static char * +partstat_to_text (icalparameter_partstat partstat) +{ + switch (partstat) { + case ICAL_PARTSTAT_NEEDSACTION: + return _("Needs Action"); + case ICAL_PARTSTAT_ACCEPTED: + return _("Accepted"); + case ICAL_PARTSTAT_DECLINED: + return _("Declined"); + case ICAL_PARTSTAT_TENTATIVE: + return _("Tentative"); + case ICAL_PARTSTAT_DELEGATED: + return _("Delegated"); + case ICAL_PARTSTAT_COMPLETED: + return _("Completed"); + case ICAL_PARTSTAT_INPROCESS: + return _("In Process"); + case ICAL_PARTSTAT_NONE: + default: + return _("Unknown"); + } + + return NULL; +} + +static int +column_count (ETableModel *etm) +{ + return E_MEETING_MODEL_COLUMN_COUNT; +} + +static int +row_count (ETableModel *etm) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + return (priv->attendees->len); +} + +static void +append_row (ETableModel *etm, ETableModel *source, int row) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + char *address; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + address = (char *) e_table_model_value_at (source, E_MEETING_MODEL_ADDRESS_COL, row); + if (find_match (im, address, NULL) != NULL) { + return; + } + + ia = E_MEETING_ATTENDEE (e_meeting_attendee_new ()); + + e_meeting_attendee_set_address (ia, g_strdup_printf ("MAILTO:%s", address)); + e_meeting_attendee_set_member (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_MEMBER_COL, row))); + e_meeting_attendee_set_cutype (ia, text_to_type (e_table_model_value_at (source, E_MEETING_MODEL_TYPE_COL, row))); + e_meeting_attendee_set_role (ia, text_to_role (e_table_model_value_at (source, E_MEETING_MODEL_ROLE_COL, row))); + e_meeting_attendee_set_rsvp (ia, text_to_boolean (e_table_model_value_at (source, E_MEETING_MODEL_RSVP_COL, row))); + e_meeting_attendee_set_delto (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_DELTO_COL, row))); + e_meeting_attendee_set_delfrom (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_DELFROM_COL, row))); + e_meeting_attendee_set_status (ia, text_to_partstat (e_table_model_value_at (source, E_MEETING_MODEL_STATUS_COL, row))); + e_meeting_attendee_set_cn (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_CN_COL, row))); + e_meeting_attendee_set_language (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_LANGUAGE_COL, row))); + + e_meeting_model_add_attendee (E_MEETING_MODEL (etm), ia); + g_object_unref (ia); +} + +static void * +value_at (ETableModel *etm, int col, int row) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + ia = g_ptr_array_index (priv->attendees, row); + + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + return (void *)itip_strip_mailto (e_meeting_attendee_get_address (ia)); + case E_MEETING_MODEL_MEMBER_COL: + return (void *)e_meeting_attendee_get_member (ia); + case E_MEETING_MODEL_TYPE_COL: + return type_to_text (e_meeting_attendee_get_cutype (ia)); + case E_MEETING_MODEL_ROLE_COL: + return role_to_text (e_meeting_attendee_get_role (ia)); + case E_MEETING_MODEL_RSVP_COL: + return boolean_to_text (e_meeting_attendee_get_rsvp (ia)); + case E_MEETING_MODEL_DELTO_COL: + return (void *)itip_strip_mailto (e_meeting_attendee_get_delto (ia)); + case E_MEETING_MODEL_DELFROM_COL: + return (void *)itip_strip_mailto (e_meeting_attendee_get_delfrom (ia)); + case E_MEETING_MODEL_STATUS_COL: + return partstat_to_text (e_meeting_attendee_get_status (ia)); + case E_MEETING_MODEL_CN_COL: + return (void *)e_meeting_attendee_get_cn (ia); + case E_MEETING_MODEL_LANGUAGE_COL: + return (void *)e_meeting_attendee_get_language (ia); + } + + return NULL; +} + +static void +set_value_at (ETableModel *etm, int col, int row, const void *val) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + icalparameter_cutype type; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + ia = g_ptr_array_index (priv->attendees, row); + + e_table_model_pre_change (etm); + + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + if (val != NULL && *((char *)val)) + e_meeting_attendee_set_address (ia, g_strdup_printf ("MAILTO:%s", (char *) val)); + break; + case E_MEETING_MODEL_MEMBER_COL: + e_meeting_attendee_set_member (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_TYPE_COL: + type = text_to_type (val); + e_meeting_attendee_set_cutype (ia, text_to_type (val)); + if (type == ICAL_CUTYPE_RESOURCE) { + e_meeting_attendee_set_role (ia, ICAL_ROLE_NONPARTICIPANT); + e_table_model_cell_changed (etm, E_MEETING_MODEL_ROLE_COL, row); + } + break; + case E_MEETING_MODEL_ROLE_COL: + e_meeting_attendee_set_role (ia, text_to_role (val)); + break; + case E_MEETING_MODEL_RSVP_COL: + e_meeting_attendee_set_rsvp (ia, text_to_boolean (val)); + break; + case E_MEETING_MODEL_DELTO_COL: + e_meeting_attendee_set_delto (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_DELFROM_COL: + e_meeting_attendee_set_delfrom (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_STATUS_COL: + e_meeting_attendee_set_status (ia, text_to_partstat (val)); + break; + case E_MEETING_MODEL_CN_COL: + e_meeting_attendee_set_cn (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_LANGUAGE_COL: + e_meeting_attendee_set_language (ia, g_strdup (val)); + break; + } + + e_table_model_cell_changed (etm, col, row); +} + +static gboolean +is_cell_editable (ETableModel *etm, int col, int row) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + EMeetingAttendeeEditLevel level; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + if (col == E_MEETING_MODEL_DELTO_COL + || col == E_MEETING_MODEL_DELFROM_COL) + return FALSE; + + if (row == -1) + return TRUE; + if (row >= priv->attendees->len) + return TRUE; + + ia = g_ptr_array_index (priv->attendees, row); + level = e_meeting_attendee_get_edit_level (ia); + + switch (level) { + case E_MEETING_ATTENDEE_EDIT_FULL: + return TRUE; + case E_MEETING_ATTENDEE_EDIT_STATUS: + return col == E_MEETING_MODEL_STATUS_COL; + case E_MEETING_ATTENDEE_EDIT_NONE: + return FALSE; + } + + return TRUE; +} + +static void * +duplicate_value (ETableModel *etm, int col, const void *val) +{ + return g_strdup (val); +} + +static void +free_value (ETableModel *etm, int col, void *val) +{ + g_free (val); +} + +static void * +init_value (ETableModel *etm, int col) +{ + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + return g_strdup (""); + case E_MEETING_MODEL_MEMBER_COL: + return g_strdup (""); + case E_MEETING_MODEL_TYPE_COL: + return g_strdup (_("Individual")); + case E_MEETING_MODEL_ROLE_COL: + return g_strdup (_("Required Participant")); + case E_MEETING_MODEL_RSVP_COL: + return g_strdup (_("Yes")); + case E_MEETING_MODEL_DELTO_COL: + return g_strdup (""); + case E_MEETING_MODEL_DELFROM_COL: + return g_strdup (""); + case E_MEETING_MODEL_STATUS_COL: + return g_strdup (_("Needs Action")); + case E_MEETING_MODEL_CN_COL: + return g_strdup (""); + case E_MEETING_MODEL_LANGUAGE_COL: + return g_strdup ("en"); + } + + return g_strdup (""); +} + +static gboolean +value_is_empty (ETableModel *etm, int col, const void *val) +{ + + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + case E_MEETING_MODEL_MEMBER_COL: + case E_MEETING_MODEL_DELTO_COL: + case E_MEETING_MODEL_DELFROM_COL: + case E_MEETING_MODEL_CN_COL: + if (val && !g_strcasecmp (val, "")) + return TRUE; + else + return FALSE; + default: + ; + } + + return TRUE; +} + +static char * +value_to_string (ETableModel *etm, int col, const void *val) +{ + return g_strdup (val); +} + +static void +class_init (EMeetingModelClass *klass) +{ + GObjectClass *gobject_class; + ETableModelClass *etm_class; + + gobject_class = G_OBJECT_CLASS (klass); + etm_class = E_TABLE_MODEL_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = finalize; + + etm_class->column_count = column_count; + etm_class->row_count = row_count; + etm_class->value_at = value_at; + etm_class->set_value_at = set_value_at; + etm_class->is_cell_editable = is_cell_editable; + etm_class->append_row = append_row; + etm_class->duplicate_value = duplicate_value; + etm_class->free_value = free_value; + etm_class->initialize_value = init_value; + etm_class->value_is_empty = value_is_empty; + etm_class->value_to_string = value_to_string; +} + + +static void +init (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = g_new0 (EMeetingModelPrivate, 1); + + im->priv = priv; + + priv->attendees = g_ptr_array_new (); + + priv->tables = NULL; + + priv->client = NULL; + priv->zone = icaltimezone_get_builtin_timezone (calendar_config_get_timezone ()); + + priv->ebook = NULL; + priv->book_loaded = FALSE; + priv->book_load_wait = FALSE; + + priv->refresh_queue = g_ptr_array_new (); + priv->refresh_data = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->refresh_idle_id = 0; + + priv->corba_select_names = CORBA_OBJECT_NIL; + + start_addressbook_server (im); +} + +static void +finalize (GObject *obj) +{ + EMeetingModel *im = E_MEETING_MODEL (obj); + EMeetingModelPrivate *priv; + GList *l; + int i; + + priv = im->priv; + + for (i = 0; i < priv->attendees->len; i++) + g_object_unref (g_ptr_array_index (priv->attendees, i)); + g_ptr_array_free (priv->attendees, TRUE); + + for (l = priv->tables; l != NULL; l = l->next) + g_signal_handlers_disconnect_matched (G_OBJECT (l->data), G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, im); + g_list_free (priv->tables); + + if (priv->client != NULL) + g_object_unref (priv->client); + + if (priv->ebook != NULL) + g_object_unref (priv->ebook); + + if (priv->corba_select_names != CORBA_OBJECT_NIL) { + CORBA_Environment ev; + CORBA_exception_init (&ev); + bonobo_object_release_unref (priv->corba_select_names, &ev); + CORBA_exception_free (&ev); + } + + while (priv->refresh_queue->len > 0) + refresh_queue_remove (im, g_ptr_array_index (priv->refresh_queue, 0)); + g_ptr_array_free (priv->refresh_queue, TRUE); + g_hash_table_destroy (priv->refresh_data); + + if (priv->refresh_idle_id) + g_source_remove (priv->refresh_idle_id); + + g_free (priv); + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (obj); +} + +GtkObject * +e_meeting_model_new (void) +{ + return g_object_new (E_TYPE_MEETING_MODEL, NULL); +} + + +CalClient * +e_meeting_model_get_cal_client (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + return priv->client; +} + +void +e_meeting_model_set_cal_client (EMeetingModel *im, CalClient *client) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + if (priv->client != NULL) + g_object_unref (priv->client); + + if (client != NULL) + g_object_ref (client); + priv->client = client; +} + +icaltimezone * +e_meeting_model_get_zone (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, NULL); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), NULL); + + priv = im->priv; + + return priv->zone; +} + +void +e_meeting_model_set_zone (EMeetingModel *im, icaltimezone *zone) +{ + EMeetingModelPrivate *priv; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + priv->zone = zone; +} + +static ETableScrolled * +build_etable (ETableModel *model, const gchar *spec_file, const gchar *state_file) +{ + GtkWidget *etable; + ETable *real_table; + ETableExtras *extras; + GList *strings; + ECell *popup_cell, *cell; + + extras = e_table_extras_new (); + + /* For type */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Individual")); + strings = g_list_append (strings, (char*) _("Group")); + strings = g_list_append (strings, (char*) _("Resource")); + strings = g_list_append (strings, (char*) _("Room")); + strings = g_list_append (strings, (char*) _("Unknown")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "typeedit", popup_cell); + + /* For role */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Chair")); + strings = g_list_append (strings, (char*) _("Required Participant")); + strings = g_list_append (strings, (char*) _("Optional Participant")); + strings = g_list_append (strings, (char*) _("Non-Participant")); + strings = g_list_append (strings, (char*) _("Unknown")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "roleedit", popup_cell); + + /* For rsvp */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Yes")); + strings = g_list_append (strings, (char*) _("No")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "rsvpedit", popup_cell); + + /* For status */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Needs Action")); + strings = g_list_append (strings, (char*) _("Accepted")); + strings = g_list_append (strings, (char*) _("Declined")); + strings = g_list_append (strings, (char*) _("Tentative")); + strings = g_list_append (strings, (char*) _("Delegated")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "statusedit", popup_cell); + + etable = e_table_scrolled_new_from_spec_file (model, extras, spec_file, NULL); + real_table = e_table_scrolled_get_table (E_TABLE_SCROLLED (etable)); + g_object_set (G_OBJECT (real_table), "uniform_row_height", TRUE, NULL); + e_table_load_state (real_table, state_file); + +#if 0 + g_signal_connect (real_table, "right_click", G_CALLBACK (right_click_cb), mpage); +#endif + + g_signal_connect (etable, "destroy", G_CALLBACK (table_destroy_state_cb), g_strdup (state_file)); + + g_object_unref (extras); + + return E_TABLE_SCROLLED (etable); +} + +void +e_meeting_model_add_attendee (EMeetingModel *im, EMeetingAttendee *ia) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + e_table_model_pre_change (E_TABLE_MODEL (im)); + + g_object_ref (ia); + g_ptr_array_add (priv->attendees, ia); + + g_signal_connect (ia, "changed", G_CALLBACK (attendee_changed_cb), im); + + e_table_model_row_inserted (E_TABLE_MODEL (im), row_count (E_TABLE_MODEL (im)) - 1); +} + +EMeetingAttendee * +e_meeting_model_add_attendee_with_defaults (EMeetingModel *im) +{ + EMeetingAttendee *ia; + char *str; + + ia = E_MEETING_ATTENDEE (e_meeting_attendee_new ()); + + e_meeting_attendee_set_address (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_ADDRESS_COL)); + e_meeting_attendee_set_member (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_MEMBER_COL)); + + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_TYPE_COL); + e_meeting_attendee_set_cutype (ia, text_to_type (str)); + g_free (str); + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_ROLE_COL); + e_meeting_attendee_set_role (ia, text_to_role (str)); + g_free (str); + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_RSVP_COL); + e_meeting_attendee_set_rsvp (ia, text_to_boolean (str)); + g_free (str); + + e_meeting_attendee_set_delto (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_DELTO_COL)); + e_meeting_attendee_set_delfrom (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_DELFROM_COL)); + + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_STATUS_COL); + e_meeting_attendee_set_status (ia, text_to_partstat (str)); + g_free (str); + + e_meeting_attendee_set_cn (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_CN_COL)); + e_meeting_attendee_set_language (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_LANGUAGE_COL)); + + e_meeting_model_add_attendee (im, ia); + + return ia; +} + +void +e_meeting_model_remove_attendee (EMeetingModel *im, EMeetingAttendee *ia) +{ + EMeetingModelPrivate *priv; + gint i, row = -1; + + priv = im->priv; + + for (i = 0; i < priv->attendees->len; i++) { + if (ia == g_ptr_array_index (priv->attendees, i)) { + row = i; + break; + } + } + + if (row != -1) { + e_table_model_pre_change (E_TABLE_MODEL (im)); + + g_ptr_array_remove_index (priv->attendees, row); + g_object_unref (ia); + + e_table_model_row_deleted (E_TABLE_MODEL (im), row); + } +} + +void +e_meeting_model_remove_all_attendees (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + gint i, len; + + priv = im->priv; + + e_table_model_pre_change (E_TABLE_MODEL (im)); + + len = priv->attendees->len; + + for (i = 0; i < len; i++) { + EMeetingAttendee *ia = g_ptr_array_index (priv->attendees, i); + g_object_unref (ia); + } + g_ptr_array_set_size (priv->attendees, 0); + + e_table_model_rows_deleted (E_TABLE_MODEL (im), 0, len); +} + +EMeetingAttendee * +e_meeting_model_find_attendee (EMeetingModel *im, const gchar *address, gint *row) +{ + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + int i; + + priv = im->priv; + + if (address == NULL) + return NULL; + + for (i = 0; i < priv->attendees->len; i++) { + const gchar *ia_address; + + ia = g_ptr_array_index (priv->attendees, i); + + ia_address = e_meeting_attendee_get_address (ia); + if (ia_address && !g_strcasecmp (itip_strip_mailto (ia_address), itip_strip_mailto (address))) { + if (row != NULL) + *row = i; + + return ia; + } + } + + return NULL; +} + +EMeetingAttendee * +e_meeting_model_find_attendee_at_row (EMeetingModel *im, gint row) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, NULL); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), NULL); + g_return_val_if_fail (row >= 0, NULL); + + priv = im->priv; + g_return_val_if_fail (row < priv->attendees->len, NULL); + + return g_ptr_array_index (priv->attendees, row); +} + +gint +e_meeting_model_count_actual_attendees (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + return e_table_model_row_count (E_TABLE_MODEL (im)); +} + +const GPtrArray * +e_meeting_model_get_attendees (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + return priv->attendees; +} + +static icaltimezone * +find_zone (icalproperty *ip, icalcomponent *tz_top_level) +{ + icalparameter *param; + icalcomponent *sub_comp; + const char *tzid; + icalcompiter iter; + + if (tz_top_level == NULL) + return NULL; + + param = icalproperty_get_first_parameter (ip, ICAL_TZID_PARAMETER); + if (param == NULL) + return NULL; + tzid = icalparameter_get_tzid (param); + + iter = icalcomponent_begin_component (tz_top_level, ICAL_VTIMEZONE_COMPONENT); + while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { + icalcomponent *clone; + const char *tz_tzid; + + /* FIXME We aren't passing a property here */ + tz_tzid = icalproperty_get_tzid (sub_comp); + if (!strcmp (tzid, tz_tzid)) { + icaltimezone *zone; + + zone = icaltimezone_new (); + clone = icalcomponent_new_clone (sub_comp); + icaltimezone_set_component (zone, clone); + + return zone; + } + + icalcompiter_next (&iter); + } + + return NULL; +} + + +static void +refresh_queue_add (EMeetingModel *im, int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data) +{ + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + EMeetingModelQueueData *qdata; + + priv = im->priv; + + ia = g_ptr_array_index (priv->attendees, row); + if (ia == NULL) + return; + + qdata = g_hash_table_lookup (priv->refresh_data, ia); + if (qdata == NULL) { + qdata = g_new0 (EMeetingModelQueueData, 1); + + qdata->im = im; + qdata->ia = ia; + e_meeting_attendee_clear_busy_periods (ia); + e_meeting_attendee_set_has_calendar_info (ia, FALSE); + + qdata->start = *start; + qdata->end = *end; + qdata->string = g_string_new (NULL); + qdata->call_backs = g_ptr_array_new (); + qdata->data = g_ptr_array_new (); + g_ptr_array_add (qdata->call_backs, call_back); + g_ptr_array_add (qdata->data, data); + + g_hash_table_insert (priv->refresh_data, ia, qdata); + } else { + if (e_meeting_time_compare_times (start, &qdata->start) == -1) + qdata->start = *start; + if (e_meeting_time_compare_times (end, &qdata->end) == 1) + qdata->end = *end; + g_ptr_array_add (qdata->call_backs, call_back); + g_ptr_array_add (qdata->data, data); + } + + g_object_ref (ia); + g_ptr_array_add (priv->refresh_queue, ia); + + if (priv->refresh_idle_id == 0) + priv->refresh_idle_id = g_idle_add (refresh_busy_periods, im); +} + +static void +refresh_queue_remove (EMeetingModel *im, EMeetingAttendee *ia) +{ + EMeetingModelPrivate *priv; + EMeetingModelQueueData *qdata; + + priv = im->priv; + + /* Free the queue data */ + qdata = g_hash_table_lookup (priv->refresh_data, ia); + g_assert (qdata != NULL); + + g_hash_table_remove (priv->refresh_data, ia); + g_ptr_array_free (qdata->call_backs, TRUE); + g_ptr_array_free (qdata->data, TRUE); + g_free (qdata); + + /* Unref the attendee */ + g_ptr_array_remove (priv->refresh_queue, ia); + g_object_unref (ia); +} + +static void +process_callbacks (EMeetingModelQueueData *qdata) +{ + EMeetingModel *im; + int i; + + for (i = 0; i < qdata->call_backs->len; i++) { + EMeetingModelRefreshCallback call_back; + gpointer *data; + + call_back = g_ptr_array_index (qdata->call_backs, i); + data = g_ptr_array_index (qdata->data, i); + + call_back (data); + } + + im = qdata->im; + refresh_queue_remove (qdata->im, qdata->ia); + g_object_unref (im); +} + +static void +process_free_busy_comp (EMeetingAttendee *ia, + icalcomponent *fb_comp, + icaltimezone *zone, + icalcomponent *tz_top_level) +{ + icalproperty *ip; + + ip = icalcomponent_get_first_property (fb_comp, ICAL_DTSTART_PROPERTY); + if (ip != NULL) { + struct icaltimetype dtstart; + icaltimezone *ds_zone; + + dtstart = icalproperty_get_dtstart (ip); + if (!dtstart.is_utc) + ds_zone = find_zone (ip, tz_top_level); + else + ds_zone = icaltimezone_get_utc_timezone (); + icaltimezone_convert_time (&dtstart, ds_zone, zone); + e_meeting_attendee_set_start_busy_range (ia, + dtstart.year, + dtstart.month, + dtstart.day, + dtstart.hour, + dtstart.minute); + } + + ip = icalcomponent_get_first_property (fb_comp, ICAL_DTEND_PROPERTY); + if (ip != NULL) { + struct icaltimetype dtend; + icaltimezone *de_zone; + + dtend = icalproperty_get_dtend (ip); + if (!dtend.is_utc) + de_zone = find_zone (ip, tz_top_level); + else + de_zone = icaltimezone_get_utc_timezone (); + icaltimezone_convert_time (&dtend, de_zone, zone); + e_meeting_attendee_set_end_busy_range (ia, + dtend.year, + dtend.month, + dtend.day, + dtend.hour, + dtend.minute); + } + + ip = icalcomponent_get_first_property (fb_comp, ICAL_FREEBUSY_PROPERTY); + while (ip != NULL) { + icalparameter *param; + struct icalperiodtype fb; + EMeetingFreeBusyType busy_type = E_MEETING_FREE_BUSY_LAST; + icalparameter_fbtype fbtype = ICAL_FBTYPE_BUSY; + + fb = icalproperty_get_freebusy (ip); + param = icalproperty_get_first_parameter (ip, ICAL_FBTYPE_PARAMETER); + if (param != NULL) + fbtype = icalparameter_get_fbtype (param); + + switch (fbtype) { + case ICAL_FBTYPE_BUSY: + busy_type = E_MEETING_FREE_BUSY_BUSY; + break; + + case ICAL_FBTYPE_BUSYUNAVAILABLE: + busy_type = E_MEETING_FREE_BUSY_OUT_OF_OFFICE; + break; + + case ICAL_FBTYPE_BUSYTENTATIVE: + busy_type = E_MEETING_FREE_BUSY_TENTATIVE; + break; + + default: + break; + } + + if (busy_type != E_MEETING_FREE_BUSY_LAST) { + icaltimezone *utc_zone = icaltimezone_get_utc_timezone (); + + icaltimezone_convert_time (&fb.start, utc_zone, zone); + icaltimezone_convert_time (&fb.end, utc_zone, zone); + e_meeting_attendee_add_busy_period (ia, + fb.start.year, + fb.start.month, + fb.start.day, + fb.start.hour, + fb.start.minute, + fb.end.year, + fb.end.month, + fb.end.day, + fb.end.hour, + fb.end.minute, + busy_type); + } + + ip = icalcomponent_get_next_property (fb_comp, ICAL_FREEBUSY_PROPERTY); + } +} + +static void +process_free_busy (EMeetingModelQueueData *qdata, char *text) +{ + EMeetingModel *im = qdata->im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia = qdata->ia; + icalcomponent *main_comp; + icalcomponent_kind kind = ICAL_NO_COMPONENT; + + priv = im->priv; + + main_comp = icalparser_parse_string (text); + if (main_comp == NULL) { + process_callbacks (qdata); + return; + } + + kind = icalcomponent_isa (main_comp); + if (kind == ICAL_VCALENDAR_COMPONENT) { + icalcompiter iter; + icalcomponent *tz_top_level, *sub_comp; + + tz_top_level = cal_util_new_top_level (); + + iter = icalcomponent_begin_component (main_comp, ICAL_VTIMEZONE_COMPONENT); + while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { + icalcomponent *clone; + + clone = icalcomponent_new_clone (sub_comp); + icalcomponent_add_component (tz_top_level, clone); + + icalcompiter_next (&iter); + } + + iter = icalcomponent_begin_component (main_comp, ICAL_VFREEBUSY_COMPONENT); + while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { + process_free_busy_comp (ia, sub_comp, priv->zone, tz_top_level); + + icalcompiter_next (&iter); + } + icalcomponent_free (tz_top_level); + } else if (kind == ICAL_VFREEBUSY_COMPONENT) { + process_free_busy_comp (ia, main_comp, priv->zone, NULL); + } + + icalcomponent_free (main_comp); + + process_callbacks (qdata); +} + +static void +async_close (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer data) +{ + EMeetingModelQueueData *qdata = data; + + process_free_busy (qdata, qdata->string->str); +} + +static void +async_read (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer buffer, + GnomeVFSFileSize requested, + GnomeVFSFileSize read, + gpointer data) +{ + EMeetingModelQueueData *qdata = data; + GnomeVFSFileSize buf_size = BUF_SIZE - 1; + + if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) { + gnome_vfs_async_close (handle, async_close, qdata); + return; + } + + ((char *)buffer)[read] = '\0'; + qdata->string = g_string_append (qdata->string, buffer); + + if (result == GNOME_VFS_ERROR_EOF) { + gnome_vfs_async_close (handle, async_close, qdata); + return; + } + + gnome_vfs_async_read (handle, qdata->buffer, buf_size, async_read, qdata); +} + +static void +async_open (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer data) +{ + EMeetingModelQueueData *qdata = data; + GnomeVFSFileSize buf_size = BUF_SIZE - 1; + + if (result != GNOME_VFS_OK) { + gnome_vfs_async_close (handle, async_close, qdata); + return; + } + + gnome_vfs_async_read (handle, qdata->buffer, buf_size, async_read, qdata); +} + +static void +contacts_cb (EBook *book, EBookStatus status, GList *contacts, gpointer data) +{ + EMeetingModelQueueData *qdata = data; + GList *l; + + if (status != E_BOOK_ERROR_OK) + return; + + for (l = contacts; l; l = l->next) { + GnomeVFSAsyncHandle *handle; + EContact *contact = E_CONTACT (l->data); + const char *fburl = e_contact_get_const (contact, E_CONTACT_FREEBUSY_URL); + + if (!fburl || !*fburl) + continue; + + /* Read in free/busy data from the url */ + gnome_vfs_async_open (&handle, fburl, GNOME_VFS_OPEN_READ, + GNOME_VFS_PRIORITY_DEFAULT, async_open, qdata); + + e_free_object_list (contacts); + return; + } + + process_callbacks (qdata); + e_free_object_list (contacts); +} + +static gboolean +refresh_busy_periods (gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + EMeetingAttendee *ia = NULL; + EMeetingModelQueueData *qdata = NULL; + char *query; + int i; + + priv = im->priv; + + /* Check to see if there are any remaining attendees in the queue */ + for (i = 0; i < priv->refresh_queue->len; i++) { + ia = g_ptr_array_index (priv->refresh_queue, i); + g_assert (ia != NULL); + + qdata = g_hash_table_lookup (priv->refresh_data, ia); + g_assert (qdata != NULL); + + if (!qdata->refreshing) + break; + } + + /* The everything in the queue is being refreshed */ + if (i >= priv->refresh_queue->len) { + priv->refresh_idle_id = 0; + return FALSE; + } + + /* Indicate we are trying to refresh it */ + qdata->refreshing = TRUE; + + /* We take a ref in case we get destroyed in the gui during a callback */ + g_object_ref (qdata->im); + + /* Check the server for free busy data */ + if (priv->client) { + GList *fb_data = NULL, *users = NULL; + struct icaltimetype itt; + time_t startt, endt; + const char *user; + + itt = icaltime_null_time (); + itt.year = g_date_year (&qdata->start.date); + itt.month = g_date_month (&qdata->start.date); + itt.day = g_date_day (&qdata->start.date); + itt.hour = qdata->start.hour; + itt.minute = qdata->start.minute; + startt = icaltime_as_timet_with_zone (itt, priv->zone); + + itt = icaltime_null_time (); + itt.year = g_date_year (&qdata->end.date); + itt.month = g_date_month (&qdata->end.date); + itt.day = g_date_day (&qdata->end.date); + itt.hour = qdata->end.hour; + itt.minute = qdata->end.minute; + endt = icaltime_as_timet_with_zone (itt, priv->zone); + + user = itip_strip_mailto (e_meeting_attendee_get_address (ia)); + users = g_list_append (users, g_strdup (user)); + + /* FIXME Error checking */ + cal_client_get_free_busy (priv->client, users, startt, endt, &fb_data, NULL); + + g_list_foreach (users, (GFunc)g_free, NULL); + g_list_free (users); + + if (fb_data != NULL) { + CalComponent *comp = fb_data->data; + char *comp_str; + + comp_str = cal_component_get_as_string (comp); + process_free_busy (qdata, comp_str); + g_free (comp_str); + return TRUE; + } + } + + /* Look for fburl's of attendee with no free busy info on server */ + if (!priv->book_loaded) { + priv->book_load_wait = TRUE; + gtk_main (); + } + + if (!e_meeting_attendee_is_set_address (ia)) { + process_callbacks (qdata); + return TRUE; + } + + query = g_strdup_printf ("(is \"email\" \"%s\")", + itip_strip_mailto (e_meeting_attendee_get_address (ia))); + if (!e_book_async_get_contacts (priv->ebook, query, contacts_cb, qdata)) + process_callbacks (qdata); + g_free (query); + + return TRUE; +} + +void +e_meeting_model_refresh_all_busy_periods (EMeetingModel *im, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data) +{ + EMeetingModelPrivate *priv; + int i; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + for (i = 0; i < priv->attendees->len; i++) + refresh_queue_add (im, i, start, end, call_back, data); +} + +void +e_meeting_model_refresh_busy_periods (EMeetingModel *im, + int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data) +{ + EMeetingModelPrivate *priv; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + refresh_queue_add (im, row, start, end, call_back, data); +} + +ETableScrolled * +e_meeting_model_etable_from_model (EMeetingModel *im, const gchar *spec_file, const gchar *state_file) +{ + EMeetingModelPrivate *priv; + ETableScrolled *ets; + + g_return_val_if_fail (im != NULL, NULL); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), NULL); + + priv = im->priv; + + ets = build_etable (E_TABLE_MODEL (im), spec_file, state_file); + + priv->tables = g_list_prepend (priv->tables, ets); + + g_signal_connect (ets, "destroy", G_CALLBACK (table_destroy_list_cb), im); + + return ets; +} + +void +e_meeting_model_etable_click_to_add (EMeetingModel *im, gboolean click_to_add) +{ + EMeetingModelPrivate *priv; + GList *l; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + for (l = priv->tables; l != NULL; l = l->next) { + ETableScrolled *ets; + ETable *real_table; + + ets = l->data; + real_table = e_table_scrolled_get_table (ets); + + g_object_set (G_OBJECT (real_table), "use_click_to_add", click_to_add, NULL); + } +} + +int +e_meeting_model_etable_model_to_view_row (ETable *et, EMeetingModel *im, int model_row) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, -1); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), -1); + + priv = im->priv; + + return e_table_model_to_view_row (et, model_row); +} + +int +e_meeting_model_etable_view_to_model_row (ETable *et, EMeetingModel *im, int view_row) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, -1); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), -1); + + priv = im->priv; + + return e_table_view_to_model_row (et, view_row); +} + + +static void +add_section (GNOME_Evolution_Addressbook_SelectNames corba_select_names, const char *name) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_SelectNames_addSection (corba_select_names, + name, + gettext (name), + &ev); + + CORBA_exception_free (&ev); +} + +static gboolean +get_select_name_dialog (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + CORBA_Environment ev; + int i; + + priv = im->priv; + + if (priv->corba_select_names != CORBA_OBJECT_NIL) { + Bonobo_Control corba_control; + GtkWidget *control_widget; + int i; + + CORBA_exception_init (&ev); + for (i = 0; sections[i] != NULL; i++) { + corba_control = GNOME_Evolution_Addressbook_SelectNames_getEntryBySection + (priv->corba_select_names, sections[i], &ev); + if (BONOBO_EX (&ev)) { + CORBA_exception_free (&ev); + return FALSE; + } + + control_widget = bonobo_widget_new_control_from_objref (corba_control, CORBA_OBJECT_NIL); + + bonobo_widget_set_property (BONOBO_WIDGET (control_widget), "text", TC_CORBA_string, "", NULL); + } + CORBA_exception_free (&ev); + + return TRUE; + } + + CORBA_exception_init (&ev); + + priv->corba_select_names = bonobo_activation_activate_from_id (SELECT_NAMES_OAFID, 0, NULL, &ev); + + for (i = 0; sections[i] != NULL; i++) + add_section (priv->corba_select_names, sections[i]); + + bonobo_event_source_client_add_listener (priv->corba_select_names, + (BonoboListenerCallbackFn) select_names_ok_cb, + "GNOME/Evolution:ok:dialog", + NULL, im); + + if (BONOBO_EX (&ev)) { + CORBA_exception_free (&ev); + return FALSE; + } + + CORBA_exception_free (&ev); + + return TRUE; +} + +void +e_meeting_model_invite_others_dialog (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + CORBA_Environment ev; + + priv = im->priv; + + if (!get_select_name_dialog (im)) + return; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_SelectNames_activateDialog ( + priv->corba_select_names, _("Required Participants"), &ev); + + CORBA_exception_free (&ev); +} + +static void +process_section (EMeetingModel *im, EABDestination **destv, icalparameter_role role) +{ + EMeetingModelPrivate *priv; + int i; + + if (!destv) + return; + + priv = im->priv; + for (i = 0; destv[i]; i++) { + EMeetingAttendee *ia; + const char *name, *attendee = NULL; + char *attr; + CORBA_Environment ev; + EABDestination *dest = destv[i]; + + CORBA_exception_init (&ev); + + /* Get the CN */ + name = eab_destination_get_name (dest); + + /* Get the field as attendee from the backend */ + if (cal_client_get_ldap_attribute (priv->client, &attr, NULL) && attr) { + /* FIXME this should be more general */ + if (!strcmp (attr, "icscalendar")) { + EContact *contact = eab_destination_get_contact (dest); + if (contact) + attendee = e_contact_get_const (contact, E_CONTACT_ICS_CALENDAR); + } + + g_free (attr); + } + + CORBA_exception_init (&ev); + + /* If we couldn't get the attendee prior, get the email address as the default */ + if (attendee == NULL || *attendee == '\0') { + attendee = eab_destination_get_email (dest); + } + + CORBA_exception_free (&ev); + + if (attendee == NULL || *attendee == '\0') + continue; + + if (e_meeting_model_find_attendee (im, attendee, NULL) == NULL) { + ia = e_meeting_model_add_attendee_with_defaults (im); + + e_meeting_attendee_set_address (ia, g_strdup_printf ("MAILTO:%s", attendee)); + e_meeting_attendee_set_role (ia, role); + if (role == ICAL_ROLE_NONPARTICIPANT) + e_meeting_attendee_set_cutype (ia, ICAL_CUTYPE_RESOURCE); + e_meeting_attendee_set_cn (ia, g_strdup (name)); + } + } +} + +static void +select_names_ok_cb (BonoboListener *listener, + const char *event_name, + const CORBA_any *arg, + CORBA_Environment *ev, + gpointer data) +{ + EMeetingModel *im = data; + EMeetingModelPrivate *priv; + Bonobo_Control corba_control; + GtkWidget *control_widget; + BonoboControlFrame *control_frame; + Bonobo_PropertyBag pb; + char *dest_str; + EABDestination **dest; + int i; + + priv = im->priv; + + for (i = 0; sections[i] != NULL; i++) { + corba_control = GNOME_Evolution_Addressbook_SelectNames_getEntryBySection + (priv->corba_select_names, sections[i], ev); + control_widget = bonobo_widget_new_control_from_objref + (corba_control, CORBA_OBJECT_NIL); + + control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_widget)); + pb = bonobo_control_frame_get_control_property_bag (control_frame, NULL); + dest_str = bonobo_pbclient_get_string (pb, "destinations", NULL); + dest = eab_destination_importv (dest_str); + process_section (im, dest, roles[i]); + eab_destination_freev (dest); + } +} + +static void +attendee_changed_cb (EMeetingAttendee *ia, gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + gint row = -1, i; + + priv = im->priv; + + /* FIXME: Ideally I think you are supposed to call pre_change() before + the data structures are changed. */ + e_table_model_pre_change (E_TABLE_MODEL (im)); + + for (i = 0; i < priv->attendees->len; i++) { + if (ia == g_ptr_array_index (priv->attendees, i)) { + row = i; + break; + } + } + + if (row == -1) + e_table_model_no_change (E_TABLE_MODEL (im)); + else + e_table_model_row_changed (E_TABLE_MODEL (im), row); +} + +static void +table_destroy_state_cb (ETableScrolled *etable, gpointer data) +{ + ETable *real_table; + char *filename = data; + + real_table = e_table_scrolled_get_table (etable); + e_table_save_state (real_table, filename); + + g_free (data); +} + +static void +table_destroy_list_cb (ETableScrolled *etable, gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + + priv = im->priv; + + priv->tables = g_list_remove (priv->tables, etable); +} + diff --git a/calendar/gui/e-meeting-model.h b/calendar/gui/e-meeting-model.h new file mode 100644 index 0000000000..50fba6c7a6 --- /dev/null +++ b/calendar/gui/e-meeting-model.h @@ -0,0 +1,116 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-model.h + * + * Copyright (C) 2001 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: JP Rosevear + */ + +#ifndef _E_MEETING_MODEL_H_ +#define _E_MEETING_MODEL_H_ + +#include <gtk/gtk.h> +#include <gal/e-table/e-table-scrolled.h> +#include <gal/e-table/e-table-model.h> +#include <cal-client/cal-client.h> +#include "e-meeting-attendee.h" + +G_BEGIN_DECLS + +#define E_TYPE_MEETING_MODEL (e_meeting_model_get_type ()) +#define E_MEETING_MODEL(obj) (GTK_CHECK_CAST ((obj), E_TYPE_MEETING_MODEL, EMeetingModel)) +#define E_MEETING_MODEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MEETING_MODEL, EMeetingModelClass)) +#define E_IS_MEETING_MODEL(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_MEETING_MODEL)) +#define E_IS_MEETING_MODEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MEETING_MODEL)) + + +typedef struct _EMeetingModel EMeetingModel; +typedef struct _EMeetingModelPrivate EMeetingModelPrivate; +typedef struct _EMeetingModelClass EMeetingModelClass; + +typedef enum { + E_MEETING_MODEL_ADDRESS_COL, + E_MEETING_MODEL_MEMBER_COL, + E_MEETING_MODEL_TYPE_COL, + E_MEETING_MODEL_ROLE_COL, + E_MEETING_MODEL_RSVP_COL, + E_MEETING_MODEL_DELTO_COL, + E_MEETING_MODEL_DELFROM_COL, + E_MEETING_MODEL_STATUS_COL, + E_MEETING_MODEL_CN_COL, + E_MEETING_MODEL_LANGUAGE_COL, + E_MEETING_MODEL_COLUMN_COUNT +} EMeetingModelColumns; + +struct _EMeetingModel { + ETableModel parent; + + EMeetingModelPrivate *priv; +}; + +struct _EMeetingModelClass { + ETableModelClass parent_class; +}; + +typedef void (* EMeetingModelRefreshCallback) (gpointer data); + + +GtkType e_meeting_model_get_type (void); +GtkObject *e_meeting_model_new (void); + +CalClient *e_meeting_model_get_cal_client (EMeetingModel *im); +void e_meeting_model_set_cal_client (EMeetingModel *im, CalClient *client); + +icaltimezone *e_meeting_model_get_zone (EMeetingModel *im); +void e_meeting_model_set_zone (EMeetingModel *im, icaltimezone *zone); + +void e_meeting_model_add_attendee (EMeetingModel *im, EMeetingAttendee *ia); +EMeetingAttendee *e_meeting_model_add_attendee_with_defaults (EMeetingModel *im); + +void e_meeting_model_remove_attendee (EMeetingModel *im, EMeetingAttendee *ia); +void e_meeting_model_remove_all_attendees (EMeetingModel *im); + +EMeetingAttendee *e_meeting_model_find_attendee (EMeetingModel *im, const gchar *address, gint *row); +EMeetingAttendee *e_meeting_model_find_attendee_at_row (EMeetingModel *im, gint row); + +gint e_meeting_model_count_actual_attendees (EMeetingModel *im); +const GPtrArray *e_meeting_model_get_attendees (EMeetingModel *im); + +void e_meeting_model_refresh_all_busy_periods (EMeetingModel *im, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data); +void e_meeting_model_refresh_busy_periods (EMeetingModel *im, + int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data); + + +/* Helpful functions */ +ETableScrolled *e_meeting_model_etable_from_model (EMeetingModel *im, const gchar *spec_file, const gchar *state_file); +void e_meeting_model_etable_click_to_add (EMeetingModel *im, gboolean click_to_add); +int e_meeting_model_etable_model_to_view_row (ETable *et, EMeetingModel *im, int model_row); +int e_meeting_model_etable_view_to_model_row (ETable *et, EMeetingModel *im, int view_row); + +void e_meeting_model_invite_others_dialog (EMeetingModel *im); + +G_END_DECLS + +#endif diff --git a/calendar/gui/e-meeting-store.c b/calendar/gui/e-meeting-store.c index 0129756e7c..6064971d9f 100644 --- a/calendar/gui/e-meeting-store.c +++ b/calendar/gui/e-meeting-store.c @@ -30,7 +30,6 @@ #include <libgnome/gnome-util.h> #include <libgnomevfs/gnome-vfs.h> #include <ebook/e-book.h> -#include <ebook/e-book-util.h> #include <cal-util/cal-component.h> #include <cal-util/cal-util.h> #include <cal-util/timeutil.h> @@ -50,8 +49,6 @@ struct _EMeetingStorePrivate { icaltimezone *zone; EBook *ebook; - gboolean book_loaded; - gboolean book_load_wait; GPtrArray *refresh_queue; GHashTable *refresh_data; @@ -81,26 +78,10 @@ struct _EMeetingStoreQueueData { static GObjectClass *parent_class = NULL; static void -book_open_cb (EBook *book, EBookStatus status, gpointer data) -{ - EMeetingStore *store = E_MEETING_STORE (data); - - if (status == E_BOOK_STATUS_SUCCESS) - store->priv->book_loaded = TRUE; - else - g_warning ("Book not loaded"); - - if (store->priv->book_load_wait) { - store->priv->book_load_wait = FALSE; - gtk_main_quit (); - } -} - -static void start_addressbook_server (EMeetingStore *store) { store->priv->ebook = e_book_new (); - e_book_load_default_book (store->priv->ebook, book_open_cb, store); + e_book_load_local_addressbook (store->priv->ebook, NULL); } static icalparameter_cutype @@ -914,9 +895,11 @@ find_zone (icalproperty *ip, icalcomponent *tz_top_level) iter = icalcomponent_begin_component (tz_top_level, ICAL_VTIMEZONE_COMPONENT); while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { icalcomponent *clone; + icalproperty *prop; const char *tz_tzid; - - tz_tzid = icalproperty_get_tzid (sub_comp); + + prop = icalcomponent_get_first_property (sub_comp, ICAL_TZID_PROPERTY); + tz_tzid = icalproperty_get_tzid (prop); if (!strcmp (tzid, tz_tzid)) { icaltimezone *zone; @@ -1141,7 +1124,7 @@ refresh_busy_periods (gpointer data) /* Check the server for free busy data */ if (priv->client) { - GList *fb_data, *users = NULL; + GList *fb_data = NULL, *users = NULL; struct icaltimetype itt; time_t startt, endt; const char *user; @@ -1164,7 +1147,7 @@ refresh_busy_periods (gpointer data) user = itip_strip_mailto (e_meeting_attendee_get_address (attendee)); users = g_list_append (users, g_strdup (user)); - fb_data = cal_client_get_free_busy (priv->client, users, startt, endt); + cal_client_get_free_busy (priv->client, users, startt, endt, &fb_data, NULL); g_list_foreach (users, (GFunc)g_free, NULL); g_list_free (users); @@ -1181,11 +1164,6 @@ refresh_busy_periods (gpointer data) } /* Look for fburl's of attendee with no free busy info on server */ - if (!priv->book_loaded) { - priv->book_load_wait = TRUE; - gtk_main (); - } - if (!e_meeting_attendee_is_set_address (attendee)) { process_callbacks (qdata); return TRUE; diff --git a/calendar/gui/e-meeting-time-sel.c b/calendar/gui/e-meeting-time-sel.c index 157320ef16..91d915a4d7 100644 --- a/calendar/gui/e-meeting-time-sel.c +++ b/calendar/gui/e-meeting-time-sel.c @@ -265,6 +265,7 @@ e_meeting_time_selector_init (EMeetingTimeSelector * mts) void e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *ems) { + char *filename; GtkWidget *hbox, *vbox, *separator, *button, *label, *table; GtkWidget *alignment, *child_hbox, *arrow, *menuitem; GSList *group; @@ -313,7 +314,12 @@ e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *em gtk_box_pack_start (GTK_BOX (vbox), mts->attendees_vbox, TRUE, TRUE, 0); gtk_widget_show (mts->attendees_vbox); + + /* build the etable */ + filename = g_build_filename (calendar_component_peek_config_directory (calendar_component_peek ()), + "config", "et-header-meeting-time-sel", NULL); mts->model = ems; + if (mts->model) g_object_ref (mts->model); diff --git a/calendar/gui/e-select-names-editable.c b/calendar/gui/e-select-names-editable.c index 2fcc93397a..29c54c7979 100644 --- a/calendar/gui/e-select-names-editable.c +++ b/calendar/gui/e-select-names-editable.c @@ -25,7 +25,7 @@ #include <gtk/gtkcelleditable.h> #include <bonobo/bonobo-exception.h> #include <bonobo/bonobo-widget.h> -#include <ebook/e-destination.h> +#include <addressbook/util/eab-destination.h> #include "e-select-names-editable.h" #include "Evolution-Addressbook-SelectNames.h" @@ -187,16 +187,16 @@ e_select_names_editable_new () gchar * e_select_names_editable_get_address (ESelectNamesEditable *esne) { - EDestination **dest; + EABDestination **dest; gchar *dest_str; gchar *result; g_return_val_if_fail (E_SELECT_NAMES_EDITABLE (esne), NULL); dest_str = bonobo_pbclient_get_string (esne->priv->bag, "destinations", NULL); - dest = e_destination_importv (dest_str); - result = g_strdup (e_destination_get_email (*dest)); - e_destination_freev (dest); + dest = eab_destination_importv (dest_str); + result = g_strdup (eab_destination_get_email (*dest)); + eab_destination_freev (dest); return result; } @@ -204,16 +204,16 @@ e_select_names_editable_get_address (ESelectNamesEditable *esne) gchar * e_select_names_editable_get_name (ESelectNamesEditable *esne) { - EDestination **dest; + EABDestination **dest; gchar *dest_str; gchar *result; g_return_val_if_fail (E_SELECT_NAMES_EDITABLE (esne), NULL); dest_str = bonobo_pbclient_get_string (esne->priv->bag, "destinations", NULL); - dest = e_destination_importv (dest_str); - result = g_strdup (e_destination_get_name (*dest)); - e_destination_freev (dest); + dest = eab_destination_importv (dest_str); + result = g_strdup (eab_destination_get_name (*dest)); + eab_destination_freev (dest); return result; } diff --git a/calendar/gui/e-tasks.c b/calendar/gui/e-tasks.c index b441aee09d..768b2e587c 100644 --- a/calendar/gui/e-tasks.c +++ b/calendar/gui/e-tasks.c @@ -572,7 +572,6 @@ GtkWidget * e_tasks_construct (ETasks *tasks) { ETasksPrivate *priv; - ECalModel *model; g_return_val_if_fail (tasks != NULL, NULL); g_return_val_if_fail (E_IS_TASKS (tasks), NULL); @@ -581,24 +580,6 @@ e_tasks_construct (ETasks *tasks) setup_widgets (tasks); - priv->client = cal_client_new (); - if (!priv->client) - return NULL; - - g_signal_connect (priv->client, "cal_opened", - G_CALLBACK (cal_opened_cb), tasks); - g_signal_connect (priv->client, "backend_error", - G_CALLBACK (backend_error_cb), tasks); - g_signal_connect (priv->client, "categories_changed", - G_CALLBACK (client_categories_changed_cb), tasks); - g_signal_connect (priv->client, "obj_updated", - G_CALLBACK (client_obj_updated_cb), tasks); - - model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); - g_assert (model != NULL); - - e_cal_model_add_client (model, priv->client); - return GTK_WIDGET (tasks); } @@ -685,6 +666,8 @@ e_tasks_open (ETasks *tasks, EUri *uri; char *real_uri; char *urinopwd; + ECalModel *model; + GError *error = NULL; g_return_val_if_fail (tasks != NULL, FALSE); g_return_val_if_fail (E_IS_TASKS (tasks), FALSE); @@ -704,10 +687,30 @@ e_tasks_open (ETasks *tasks, g_free (message); g_free (urinopwd); - if (!cal_client_open_calendar (priv->client, real_uri, FALSE)) { - g_message ("e_tasks_open(): Could not issue the request"); + /* create the CalClient */ + priv->client = cal_client_new (real_uri, CALOBJ_TYPE_TODO); + if (!priv->client) + return NULL; + + g_signal_connect (priv->client, "cal_opened", + G_CALLBACK (cal_opened_cb), tasks); + g_signal_connect (priv->client, "backend_error", + G_CALLBACK (backend_error_cb), tasks); + g_signal_connect (priv->client, "categories_changed", + G_CALLBACK (client_categories_changed_cb), tasks); + g_signal_connect (priv->client, "obj_updated", + G_CALLBACK (client_obj_updated_cb), tasks); + + model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); + g_assert (model != NULL); + + e_cal_model_add_client (model, priv->client); + + if (cal_client_open (priv->client, FALSE, &error)) { + g_message ("e_tasks_open(): %s", error->message); g_free (real_uri); e_uri_free (uri); + g_error_free (error); return FALSE; } @@ -787,7 +790,8 @@ cal_opened_cb (CalClient *client, location = calendar_config_get_timezone (); zone = icaltimezone_get_builtin_timezone (location); if (zone) - cal_client_set_default_timezone (client, zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (client, zone, NULL); return; case CAL_CLIENT_OPEN_ERROR: @@ -937,60 +941,6 @@ create_sexp (void) return sexp; } -/* Callback used when a component is updated in the live query */ -static void -query_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total, - gpointer data) -{ - ETasks *tasks; - ETasksPrivate *priv; - - tasks = E_TASKS (data); - priv = tasks->priv; - - delete_error_dialog (cal_client_remove_object (priv->client, uid), CAL_COMPONENT_TODO); -} - -/* Callback used when an evaluation error occurs when running a query */ -static void -query_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) -{ - ETasks *tasks; - ETasksPrivate *priv; - - tasks = E_TASKS (data); - priv = tasks->priv; - - g_warning ("eval error: %s\n", error_str); - - set_status_message (tasks, NULL); - - g_signal_handlers_disconnect_matched (priv->query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, tasks); - g_object_unref (priv->query); - priv->query = NULL; -} - -static void -query_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer data) -{ - ETasks *tasks; - ETasksPrivate *priv; - - tasks = E_TASKS (data); - priv = tasks->priv; - - if (status != CAL_QUERY_DONE_SUCCESS) - g_warning ("query done: %s\n", error_str); - - set_status_message (tasks, NULL); - - g_signal_handlers_disconnect_matched (priv->query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, tasks); - g_object_unref (priv->query); - priv->query = NULL; -} /** * e_tasks_expunge: * @tasks: A tasks control widget @@ -1002,31 +952,32 @@ e_tasks_delete_completed (ETasks *tasks) { ETasksPrivate *priv; char *sexp; + GList *objects, *l; g_return_if_fail (tasks != NULL); g_return_if_fail (E_IS_TASKS (tasks)); priv = tasks->priv; - /* If we have a query, we are already expunging */ - if (priv->query) - return; + /* FIXME Confirm expunge */ sexp = create_sexp (); set_status_message (tasks, _("Expunging")); - priv->query = cal_client_get_query (priv->client, sexp); - g_free (sexp); - - if (!priv->query) { + + if (!cal_client_get_object_list (priv->client, sexp, &objects, NULL)) { set_status_message (tasks, NULL); - g_message ("update_query(): Could not create the query"); + g_warning (G_STRLOC ": Could not get the objects"); + return; } + + for (l = objects; l; l = l->next) { + /* FIXME Better error handling */ + cal_client_remove_object (priv->client, icalcomponent_get_uid (l->data), NULL); + } - g_signal_connect (priv->query, "obj_updated", G_CALLBACK (query_obj_updated_cb), tasks); - g_signal_connect (priv->query, "query_done", G_CALLBACK (query_query_done_cb), tasks); - g_signal_connect (priv->query, "eval_error", G_CALLBACK (query_eval_error_cb), tasks); + set_status_message (tasks, NULL); } /* Callback used from the view collection when we need to display a new view */ @@ -1181,6 +1132,7 @@ e_tasks_update_all_config_settings (void) calendar_config_configure_e_calendar_table (E_CALENDAR_TABLE (priv->tasks_view)); if (zone) - cal_client_set_default_timezone (priv->client, zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (priv->client, zone, NULL); } } diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c index 139f28bb13..fd68130bc5 100644 --- a/calendar/gui/e-week-view-event-item.c +++ b/calendar/gui/e-week-view-event-item.c @@ -890,7 +890,6 @@ e_week_view_event_item_double_click (EWeekViewEventItem *wveitem, EWeekView *week_view; EWeekViewEvent *event; GnomeCanvasItem *item; - GnomeCalendar *calendar; item = GNOME_CANVAS_ITEM (wveitem); @@ -902,11 +901,7 @@ e_week_view_event_item_double_click (EWeekViewEventItem *wveitem, e_week_view_stop_editing_event (week_view); - calendar = e_cal_view_get_calendar (E_CAL_VIEW (week_view)); - if (calendar) - gnome_calendar_edit_object (calendar, event->comp_data->client, event->comp_data->icalcomp, FALSE); - else - g_warning ("Calendar not set"); + e_cal_view_edit_appointment (E_CAL_VIEW (week_view), event->comp_data->client, event->comp_data->icalcomp, FALSE); return TRUE; } diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index 8028bf13e6..1be94fc1de 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -62,6 +62,7 @@ #include "calendar-config.h" #include "print.h" #include "goto.h" +#include "e-cal-model-calendar.h" #include "e-week-view-event-item.h" #include "e-week-view-layout.h" #include "e-week-view-main-item.h" @@ -312,8 +313,6 @@ e_week_view_init (EWeekView *week_view) week_view->main_gc = NULL; - week_view->default_category = NULL; - /* Create the small font. */ week_view->use_small_font = TRUE; @@ -423,8 +422,11 @@ GtkWidget * e_week_view_new (void) { GtkWidget *week_view; + ECalModel *model; + + model = E_CAL_MODEL (e_cal_model_calendar_new ()); - week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), NULL)); + week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), "model", model, NULL)); return week_view; } @@ -457,11 +459,6 @@ e_week_view_destroy (GtkObject *object) week_view->small_font_desc = NULL; } - if (week_view->default_category) { - g_free (week_view->default_category); - week_view->default_category = NULL; - } - if (week_view->normal_cursor) { gdk_cursor_unref (week_view->normal_cursor); week_view->normal_cursor = NULL; @@ -1149,7 +1146,7 @@ process_component (EWeekView *week_view, ECalModelComponent *comp_data) g_object_unref (tmp_comp); } - /* Add the occurrences of the event. */ + /* Add the occurrences of the event */ num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; add_event_data.week_view = week_view; @@ -1158,8 +1155,7 @@ process_component (EWeekView *week_view, ECalModelComponent *comp_data) week_view->day_starts[0], week_view->day_starts[num_days], e_week_view_add_event, &add_event_data, - cal_client_resolve_tzid_cb, - comp_data->client, + cal_client_resolve_tzid_cb, comp_data->client, e_cal_view_get_timezone (E_CAL_VIEW (week_view))); g_object_unref (comp); @@ -1178,8 +1174,6 @@ e_week_view_update_query (ECalView *cal_view) e_week_view_free_events (week_view); e_week_view_queue_layout (week_view); - e_cal_view_set_status_message (E_CAL_VIEW (week_view), _("Searching")); - rows = e_table_model_row_count (E_TABLE_MODEL (e_cal_view_get_model (E_CAL_VIEW (week_view)))); for (r = 0; r < rows; r++) { ECalModelComponent *comp_data; @@ -1188,8 +1182,6 @@ e_week_view_update_query (ECalView *cal_view) g_assert (comp_data != NULL); process_component (week_view, comp_data); } - - e_cal_view_set_status_message (E_CAL_VIEW (week_view), NULL); } static void @@ -1217,27 +1209,6 @@ e_week_view_draw_shadow (EWeekView *week_view) gdk_draw_line (window, light_gc, x1, y2, x2, y2); } -/** - * e_week_view_set_default_category: - * @week_view: A week view. - * @category: Default category name or NULL for no category. - * - * Sets the default category that will be used when creating new calendar - * components from the week view. - **/ -void -e_week_view_set_default_category (EWeekView *week_view, const char *category) -{ - g_return_if_fail (week_view != NULL); - g_return_if_fail (E_IS_WEEK_VIEW (week_view)); - - if (week_view->default_category) - g_free (week_view->default_category); - - week_view->default_category = g_strdup (category); -} - - /* This sets the selected time range. The EWeekView will show the corresponding month and the days between start_time and end_time will be selected. To select a single day, use the same value for start_time & end_time. */ @@ -2015,7 +1986,7 @@ e_week_view_on_button_press (GtkWidget *widget, return FALSE; if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { - gnome_calendar_new_appointment (e_cal_view_get_calendar (E_CAL_VIEW (week_view))); + e_cal_view_new_appointment (E_CAL_VIEW (week_view)); return TRUE; } @@ -2876,14 +2847,11 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, { EWeekViewEvent *event; gint event_num, span_num; - GnomeCalendar *calendar; #if 0 g_print ("In e_week_view_on_text_item_event\n"); #endif - calendar = e_cal_view_get_calendar (E_CAL_VIEW (week_view)); - switch (gdkevent->type) { case GDK_KEY_PRESS: if (gdkevent && gdkevent->key.keyval == GDK_Return) { @@ -2912,10 +2880,9 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, event = &g_array_index (week_view->events, EWeekViewEvent, event_num); - if (calendar) - gnome_calendar_edit_object (calendar, event->comp_data->client, event->comp_data->icalcomp, FALSE); - else - g_warning ("Calendar not set"); + e_cal_view_edit_appointment (E_CAL_VIEW (week_view), + event->comp_data->client, + event->comp_data->icalcomp, FALSE); gtk_signal_emit_stop_by_name (GTK_OBJECT (item), "event"); return TRUE; @@ -3049,7 +3016,8 @@ e_week_view_on_editing_stopped (EWeekView *week_view, CalComponent *comp; CalComponentText summary; const char *uid; - + gboolean on_server; + /* Note: the item we are passed here isn't reliable, so we just stop the edit of whatever item was being edited. We also receive this event twice for some reason. */ @@ -3079,8 +3047,9 @@ e_week_view_on_editing_stopped (EWeekView *week_view, comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - if (string_is_empty (text) && - !cal_comp_is_on_server (comp, event->comp_data->client)) { + on_server = cal_comp_is_on_server (comp, event->comp_data->client); + + if (string_is_empty (text) && !on_server) { const char *uid; cal_component_get_uid (comp, &uid); @@ -3099,33 +3068,33 @@ e_week_view_on_editing_stopped (EWeekView *week_view, e_week_view_reshape_event_span (week_view, event_num, span_num); } else if (summary.value || !string_is_empty (text)) { + icalcomponent *icalcomp = cal_component_get_icalcomponent (comp); + summary.value = text; summary.altrep = NULL; cal_component_set_summary (comp, &summary); - - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (event->comp_data->client, comp, mod) - == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (week_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_week_view_on_editing_stopped(): Could not update the object!"); + + if (!on_server) { + if (!cal_client_create_object (event->comp_data->client, icalcomp, NULL, NULL)) + g_message (G_STRLOC ": Could not create the object!"); + } else { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; + + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + goto out; } } - } else if (cal_client_update_object (event->comp_data->client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (week_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_week_view_on_editing_stopped(): Could not update the object!"); + + /* FIXME When sending here, what exactly should we send? */ + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (week_view))); + if (cal_client_modify_object (event->comp_data->client, icalcomp, mod, NULL)) { + if (itip_organizer_is_user (comp, event->comp_data->client) + && send_component_dialog (toplevel, event->comp_data->client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + event->comp_data->client, NULL); + } } } @@ -3182,6 +3151,10 @@ e_week_view_find_event_from_uid (EWeekView *week_view, EWeekViewEvent *event; gint event_num, num_events; + *event_num_return = -1; + if (!uid) + return FALSE; + num_events = week_view->events->len; for (event_num = 0; event_num < num_events; event_num++) { const char *u; @@ -3291,6 +3264,8 @@ e_week_view_do_key_press (GtkWidget *widget, GdkEventKey *event) /* Add a new event covering the selected range. */ icalcomp = e_cal_model_create_component_with_defaults (e_cal_view_get_model (E_CAL_VIEW (week_view))); + if (!icalcomp) + return FALSE; uid = icalcomponent_get_uid (icalcomp); comp = cal_component_new (); @@ -3313,7 +3288,8 @@ e_week_view_do_key_press (GtkWidget *widget, GdkEventKey *event) e_cal_view_get_timezone (E_CAL_VIEW (week_view))); cal_component_set_dtend (comp, &date); - cal_component_set_categories (comp, week_view->default_category); + cal_component_set_categories ( + comp, e_cal_view_get_default_category (E_CAL_VIEW (week_view))); /* We add the event locally and start editing it. We don't send it to the server until the user finishes editing it. */ @@ -3546,63 +3522,6 @@ e_week_view_popup_menu (GtkWidget *widget) } void -e_week_view_unrecur_appointment (EWeekView *week_view) -{ - EWeekViewEvent *event; - CalComponent *comp, *new_comp; - CalComponentDateTime date; - struct icaltimetype itt; - - if (week_view->popup_event_num == -1) - return; - - event = &g_array_index (week_view->events, EWeekViewEvent, - week_view->popup_event_num); - - /* For the recurring object, we add a exception to get rid of the - instance. */ - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - - /* For the unrecurred instance we duplicate the original object, - create a new uid for it, get rid of the recurrence rules, and set - the start & end times to the instances times. */ - new_comp = cal_component_new (); - cal_component_set_icalcomponent (new_comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_component_set_uid (new_comp, cal_component_gen_uid ()); - cal_component_set_rdate_list (new_comp, NULL); - cal_component_set_rrule_list (new_comp, NULL); - cal_component_set_exdate_list (new_comp, NULL); - cal_component_set_exrule_list (new_comp, NULL); - - date.value = &itt; - date.tzid = icaltimezone_get_tzid (e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - - *date.value = icaltime_from_timet_with_zone (event->start, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - cal_component_set_dtstart (new_comp, &date); - *date.value = icaltime_from_timet_with_zone (event->end, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - cal_component_set_dtend (new_comp, &date); - - /* Now update both CalComponents. Note that we do this last since at - present the updates happen synchronously so our event may disappear. - */ - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_week_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (comp); - - if (cal_client_update_object (event->comp_data->client, new_comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_week_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (new_comp); -} - -void e_week_view_jump_to_button_item (EWeekView *week_view, GnomeCanvasItem *item) { gint day; diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h index c24470155d..0296c19c42 100644 --- a/calendar/gui/e-week-view.h +++ b/calendar/gui/e-week-view.h @@ -331,9 +331,6 @@ struct _EWeekView gchar *pm_string; gint am_string_width; gint pm_string_width; - - /* The default category for new events */ - char *default_category; }; struct _EWeekViewClass @@ -353,9 +350,6 @@ void e_week_view_get_first_day_shown (EWeekView *week_view, void e_week_view_set_first_day_shown (EWeekView *week_view, GDate *date); -void e_week_view_set_default_category (EWeekView *week_view, - const char *category); - /* The selected time range. The EWeekView will show the corresponding month and the days between start_time and end_time will be selected. To select a single day, use the same value for start_time & end_time. */ @@ -396,8 +390,6 @@ void e_week_view_set_24_hour_format (EWeekView *week_view, void e_week_view_delete_occurrence (EWeekView *week_view); -void e_week_view_unrecur_appointment (EWeekView *week_view); - /* Returns the number of selected events (0 or 1 at present). */ gint e_week_view_get_num_events_selected (EWeekView *week_view); diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index c2a0c2c61e..bcefd8eeee 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -61,8 +61,6 @@ #include "misc.h" #include "ea-calendar.h" -extern ECompEditorRegistry *comp_editor_registry; - /* Private part of the GnomeCalendar structure */ @@ -71,6 +69,8 @@ struct _GnomeCalendarPrivate { * The Calendar Folder. */ + GHashTable *clients; + /* Set of categories from the calendar client */ GPtrArray *cal_categories; @@ -119,6 +119,7 @@ struct _GnomeCalendarPrivate { /* This is the view currently shown. We use it to keep track of the positions of the panes. range_selected is TRUE if a range of dates was selected in the date navigator to show the view. */ + ECalView *views[GNOME_CAL_LAST_VIEW]; GnomeCalendarViewType current_view_type; gboolean range_selected; @@ -145,10 +146,6 @@ struct _GnomeCalendarPrivate { 'dates-shown-changed' signal.*/ time_t visible_start; time_t visible_end; - - /* Calendar query for purging old events */ - GList *exp_queries; - time_t exp_older_than; }; /* Signal IDs */ @@ -361,97 +358,70 @@ gnome_calendar_class_init (GnomeCalendarClass *class) /* Callback used when the calendar query reports of an updated object */ static void -dn_query_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total, - gpointer data) +dn_query_objects_added_cb (CalQuery *query, GList *objects, gpointer data) { GnomeCalendar *gcal; GnomeCalendarPrivate *priv; - CalComponent *comp = NULL; - icalcomponent *icalcomp; - CalClientGetStatus status; - + GList *l; + gcal = GNOME_CALENDAR (data); priv = gcal->priv; - /* If this is an update that is not part of an ongoing query, we have to - * retag the whole thing: an event may change dates and the - * tag_calendar_by_comp() below would not know how to untag the old - * dates. - */ - if (!query_in_progress) { - update_query (gcal); - return; - } + for (l = objects; l; l = l->next) { + CalComponent *comp = NULL; - status = cal_client_get_object (cal_query_get_client (query), uid, &icalcomp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { + if (!cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) { g_object_unref (comp); - icalcomponent_free (icalcomp); - return; + + continue; } - break; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("dn_query_obj_updated_cb(): Syntax error while getting object `%s'", uid); - return; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object is no longer in the server, so do nothing */ - return; - default: - g_assert_not_reached (); - return; + tag_calendar_by_comp (priv->date_navigator, comp, cal_query_get_client (query), NULL, + FALSE, TRUE); + g_object_unref (comp); } - - tag_calendar_by_comp (priv->date_navigator, comp, cal_query_get_client (query), NULL, - FALSE, TRUE); - g_object_unref (comp); } -/* Callback used when the calendar query reports of a removed object */ static void -dn_query_obj_removed_cb (CalQuery *query, const char *uid, gpointer data) +dn_query_objects_modified_cb (CalQuery *query, GList *objects, gpointer data) { GnomeCalendar *gcal; + GnomeCalendarPrivate *priv; gcal = GNOME_CALENDAR (data); + priv = gcal->priv; - /* Just retag the whole thing */ + /* We have to retag the whole thing: an event may change dates + * and the tag_calendar_by_comp() below would not know how to + * untag the old dates. + */ update_query (gcal); } -/* Callback used when the calendar query is done */ +/* Callback used when the calendar query reports of a removed object */ static void -dn_query_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, - gpointer data) +dn_query_objects_removed_cb (CalQuery *query, GList *uids, gpointer data) { GnomeCalendar *gcal; gcal = GNOME_CALENDAR (data); - /* FIXME */ - - if (status != CAL_QUERY_DONE_SUCCESS) - fprintf (stderr, "query done: %s\n", error_str); + /* Just retag the whole thing */ + update_query (gcal); } -/* Callback used when the calendar query reports an evaluation error */ +/* Callback used when the calendar query is done */ static void -dn_query_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) +dn_query_done_cb (CalQuery *query, ECalendarStatus status, gpointer data) { GnomeCalendar *gcal; gcal = GNOME_CALENDAR (data); - /* FIXME */ - - fprintf (stderr, "eval error: %s\n", error_str); + /* FIXME Better error reporting */ + if (status != E_CALENDAR_STATUS_OK) + g_warning (G_STRLOC ": Query did not successfully complete"); } /* Returns the current view widget, an EDayView, EWeekView or ECalListView. */ @@ -603,6 +573,7 @@ adjust_query_sexp (GnomeCalendar *gcal, const char *sexp) start, end, sexp); + g_free (start); g_free (end); @@ -649,22 +620,24 @@ update_query (GnomeCalendar *gcal) /* create queries for each loaded client */ client_list = e_cal_model_get_client_list (e_cal_view_get_model (E_CAL_VIEW (priv->day_view))); for (l = client_list; l != NULL; l = l->next) { - old_query = cal_client_get_query ((CalClient *) l->data, real_sexp); - if (!old_query) { - g_message ("update_query(): Could not create the query"); + if (!cal_client_get_query ((CalClient *) l->data, real_sexp, &old_query, NULL)) { + g_warning (G_STRLOC ": Could not create the query"); + continue; } - g_signal_connect (old_query, "obj_updated", - G_CALLBACK (dn_query_obj_updated_cb), gcal); - g_signal_connect (old_query, "obj_removed", - G_CALLBACK (dn_query_obj_removed_cb), gcal); + g_signal_connect (old_query, "objects_added", + G_CALLBACK (dn_query_objects_added_cb), gcal); + g_signal_connect (old_query, "objects_modified", + G_CALLBACK (dn_query_objects_modified_cb), gcal); + g_signal_connect (old_query, "objects_removed", + G_CALLBACK (dn_query_objects_removed_cb), gcal); g_signal_connect (old_query, "query_done", - G_CALLBACK (dn_query_query_done_cb), gcal); - g_signal_connect (old_query, "eval_error", - G_CALLBACK (dn_query_eval_error_cb), gcal); + G_CALLBACK (dn_query_done_cb), gcal); priv->dn_queries = g_list_append (priv->dn_queries, old_query); + + cal_query_start (old_query); } g_list_free (client_list); @@ -673,6 +646,30 @@ update_query (GnomeCalendar *gcal) e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); } +static void +adjust_query_for_view (ECalView *cal_view, const char *sexp) +{ + char *real_sexp, *start, *end; + time_t ttstart, ttend; + + e_cal_view_get_visible_time_range (cal_view, &ttstart, &ttend); + + start = isodate_from_time_t (ttstart); + end = isodate_from_time_t (ttend); + + real_sexp = g_strdup_printf ( + "(and (occur-in-time-range? (make-time \"%s\")" + " (make-time \"%s\"))" + " %s)", + start, end, sexp); + + e_cal_model_set_query (e_cal_view_get_model (cal_view), real_sexp); + + g_free (start); + g_free (end); + g_free (real_sexp); +} + /** * gnome_calendar_set_query: * @gcal: A calendar. @@ -685,6 +682,7 @@ gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp) { GnomeCalendarPrivate *priv; ECalModel *model; + int i; g_return_if_fail (gcal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (gcal)); @@ -701,9 +699,9 @@ gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp) update_query (gcal); - /* Set the query on the main view */ - model = e_cal_view_get_model (E_CAL_VIEW (gnome_calendar_get_current_view_widget (gcal))); - e_cal_model_set_query (model, sexp); + /* Set the query on the views */ + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) + adjust_query_for_view (E_CAL_VIEW (priv->views[i]), sexp); /* Set the query on the task pad */ model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); @@ -747,14 +745,15 @@ search_bar_category_changed_cb (CalSearchBar *cal_search, const char *category, GnomeCalendar *gcal; GnomeCalendarPrivate *priv; ECalModel *model; + int i; gcal = GNOME_CALENDAR (data); priv = gcal->priv; - e_day_view_set_default_category (E_DAY_VIEW (priv->day_view), category); - e_day_view_set_default_category (E_DAY_VIEW (priv->work_week_view), category); - e_week_view_set_default_category (E_WEEK_VIEW (priv->week_view), category); - e_week_view_set_default_category (E_WEEK_VIEW (priv->month_view), category); + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + e_cal_view_set_default_category (E_CAL_VIEW (priv->views[i]), + category); + } model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); e_cal_model_set_default_category (model, category); @@ -853,7 +852,6 @@ setup_widgets (GnomeCalendar *gcal) GtkWidget *w; gchar *filename; ETable *etable; - ECalModel *model; priv = gcal->priv; @@ -915,7 +913,8 @@ setup_widgets (GnomeCalendar *gcal) gtk_paned_pack2 (GTK_PANED (priv->vpane), priv->todo, TRUE, TRUE); gtk_widget_show (priv->todo); - filename = g_strdup_printf ("%s/config/TaskPad", evolution_dir); + filename = g_build_filename (calendar_component_peek_config_directory (calendar_component_peek ()), + "TaskPad", NULL); e_calendar_table_load_state (E_CALENDAR_TABLE (priv->todo), filename); g_free (filename); @@ -977,7 +976,7 @@ setup_widgets (GnomeCalendar *gcal) connect_week_view_focus (gcal, E_WEEK_VIEW (priv->month_view)); /* The List View. */ - filename = g_strdup_printf ("%s/config/CalListView", evolution_dir); + filename = g_strdup_printf (".evolution/config/CalListView"); priv->list_view = e_cal_list_view_new (filename); g_free (filename); @@ -988,14 +987,12 @@ setup_widgets (GnomeCalendar *gcal) connect_list_view_focus (gcal, E_CAL_LIST_VIEW (priv->list_view)); - model = (ECalModel *) e_cal_model_calendar_new (); - e_cal_view_set_model (E_CAL_VIEW (priv->day_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->work_week_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->week_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->month_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->list_view), model); + priv->views[GNOME_CAL_DAY_VIEW] = E_CAL_VIEW (priv->day_view); + priv->views[GNOME_CAL_WORK_WEEK_VIEW] = E_CAL_VIEW (priv->work_week_view); + priv->views[GNOME_CAL_WEEK_VIEW] = E_CAL_VIEW (priv->week_view); + priv->views[GNOME_CAL_MONTH_VIEW] = E_CAL_VIEW (priv->month_view); + priv->views[GNOME_CAL_LIST_VIEW] = E_CAL_VIEW (priv->list_view); - g_object_unref (model); gnome_calendar_update_config_settings (gcal, TRUE); } @@ -1008,6 +1005,8 @@ gnome_calendar_init (GnomeCalendar *gcal) priv = g_new0 (GnomeCalendarPrivate, 1); gcal->priv = priv; + priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->cal_categories = NULL; priv->tasks_categories = NULL; @@ -1027,8 +1026,6 @@ gnome_calendar_init (GnomeCalendar *gcal) priv->visible_start = -1; priv->visible_end = -1; - - priv->exp_queries = NULL; } /* Frees a set of categories */ @@ -1062,6 +1059,8 @@ gnome_calendar_destroy (GtkObject *object) if (priv) { GList *l, *client_list; + g_hash_table_destroy (priv->clients); + free_categories (priv->cal_categories); priv->cal_categories = NULL; @@ -1078,7 +1077,8 @@ gnome_calendar_destroy (GtkObject *object) g_list_free (client_list); /* Save the TaskPad layout. */ - filename = g_strdup_printf ("%s/config/TaskPad", evolution_dir); + filename = g_build_filename (calendar_component_peek_config_directory (calendar_component_peek ()), + "TaskPad", NULL); e_calendar_table_save_state (E_CALENDAR_TABLE (priv->todo), filename); g_free (filename); @@ -1120,19 +1120,6 @@ gnome_calendar_destroy (GtkObject *object) priv->view_menus = NULL; } - if (priv->exp_queries) { - GList *l; - - for (l = priv->exp_queries; l != NULL; l = l->next) { - g_signal_handlers_disconnect_matched ((CalQuery *) l->data, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - g_object_unref (l->data); - } - - g_list_free (priv->exp_queries); - priv->exp_queries = NULL; - } - g_free (priv); gcal->priv = NULL; } @@ -1764,7 +1751,8 @@ client_cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer da case CAL_CLIENT_OPEN_SUCCESS: /* Set the client's default timezone, if we have one. */ if (priv->zone) { - cal_client_set_default_timezone (client, priv->zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (client, priv->zone, NULL); } /* add the alarms for this client */ @@ -1996,7 +1984,7 @@ gnome_calendar_construct (GnomeCalendar *gcal) /* * TaskPad Folder Client. */ - priv->task_pad_client = cal_client_new (); + priv->task_pad_client = cal_client_new ("", CALOBJ_TYPE_TODO); /* FIXME: use default tasks */ if (!priv->task_pad_client) return NULL; @@ -2063,7 +2051,8 @@ gnome_calendar_get_calendar_model (GnomeCalendar *gcal) priv = gcal->priv; - return e_cal_view_get_model (E_CAL_VIEW (priv->week_view)); + return e_cal_view_get_model ( + gnome_calendar_get_current_view_widget (gcal)); } /** @@ -2078,6 +2067,28 @@ gnome_calendar_get_default_client (GnomeCalendar *gcal) } /** + * gnome_calendar_set_default_client + * @gcal: A calendar view. + * @client: The client to use as default. + * + * Set the default client on the given calendar view. The default calendar will + * be used as the default when creating events in the view. + */ +void +gnome_calendar_set_default_client (GnomeCalendar *gcal, CalClient *client) +{ + int i; + + g_return_if_fail (GNOME_IS_CALENDAR (gcal)); + + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + e_cal_model_set_default_client ( + e_cal_view_get_model (E_CAL_VIEW (gcal->priv->views[i])), + client); + } +} + +/** * gnome_calendar_get_task_pad_cal_client: * @gcal: A calendar view. * @@ -2145,67 +2156,56 @@ add_alarms (const char *uri) CORBA_exception_free (&ev); } +/** + * gnome_calendar_add_event_uri: + * @gcal: A GnomeCalendar. + * @str_uri: URI to add to the calendar views. + * + * Adds the given calendar URI to the calendar views. + * + * Returns: TRUE if successful, FALSE if error. + */ gboolean -gnome_calendar_open (GnomeCalendar *gcal, const char *str_uri) +gnome_calendar_add_event_uri (GnomeCalendar *gcal, const char *str_uri) { GnomeCalendarPrivate *priv; - gboolean success; - EUri *uri; - char *message; - char *real_uri; - char *urinopwd; CalClient *client; - + int i; + g_return_val_if_fail (gcal != NULL, FALSE); g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), FALSE); g_return_val_if_fail (str_uri != NULL, FALSE); priv = gcal->priv; - g_return_val_if_fail ( - cal_client_get_load_state (priv->task_pad_client) == CAL_CLIENT_LOAD_NOT_LOADED, - FALSE); - - uri = e_uri_new (str_uri); - if (!uri || !g_strncasecmp (uri->protocol, "file", 4)) - real_uri = g_concat_dir_and_file (str_uri, "calendar.ics"); - else - real_uri = g_strdup (str_uri); - - urinopwd = get_uri_without_password (str_uri); - message = g_strdup_printf (_("Opening calendar at %s"), urinopwd); - g_free (urinopwd); - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), message); - g_free (message); - - client = cal_client_new (); - g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (client_cal_opened_cb), gcal); + client = g_hash_table_lookup (priv->clients, str_uri); + if (client) + return TRUE; + + client = cal_client_new (str_uri, CALOBJ_TYPE_EVENT); + g_hash_table_insert (priv->clients, g_strdup (str_uri), g_object_ref (client)); + g_signal_connect (G_OBJECT (client), "backend_error", G_CALLBACK (backend_error_cb), gcal); g_signal_connect (G_OBJECT (client), "categories_changed", G_CALLBACK (client_categories_changed_cb), gcal); g_signal_connect (G_OBJECT (client), "backend_died", G_CALLBACK (backend_died_cb), gcal); - if (!cal_client_open_calendar (client, real_uri, FALSE)) { - g_warning (G_STRLOC ": Could not issue the request to open the calendar folder"); + if (!cal_client_open (client, FALSE, NULL)) { + g_hash_table_remove (priv->clients, str_uri); g_object_unref (client); - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); return FALSE; } - /* Open the appropriate Tasks folder to show in the TaskPad */ - e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), - _("Opening default tasks folder")); - success = cal_client_open_default_tasks (priv->task_pad_client, FALSE); - - g_free (real_uri); - e_uri_free (uri); - - if (!success) { - g_message ("gnome_calendar_open(): Could not issue the request to open the tasks folder"); - e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), NULL); - return FALSE; + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + ECalModel *model; + + model = e_cal_view_get_model (priv->views[i]); + e_cal_model_add_client (model, client); } + /* update date navigator query */ + update_query (gcal); + return TRUE; } @@ -2308,7 +2308,8 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal, CalClient *client = l->data; if (cal_client_get_load_state (client) == CAL_CLIENT_LOAD_LOADED) - cal_client_set_default_timezone (client, priv->zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (client, priv->zone, NULL); } g_list_free (client_list); @@ -2316,8 +2317,9 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal, if (priv->task_pad_client && cal_client_get_load_state (priv->task_pad_client) == CAL_CLIENT_LOAD_LOADED) { + /* FIXME Error Checking */ cal_client_set_default_timezone (priv->task_pad_client, - priv->zone); + priv->zone, NULL); } e_cal_view_set_timezone (E_CAL_VIEW (priv->day_view), priv->zone); @@ -2383,147 +2385,6 @@ gnome_calendar_get_selected_time_range (GnomeCalendar *gcal, *end_time = priv->selection_end_time; } -void -gnome_calendar_edit_object (GnomeCalendar *gcal, CalClient *client, icalcomponent *icalcomp, gboolean meeting) -{ - GnomeCalendarPrivate *priv; - CompEditor *ce; - const char *uid; - CalComponent *comp; - - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - g_return_if_fail (IS_CAL_CLIENT (client)); - g_return_if_fail (icalcomp != NULL); - - priv = gcal->priv; - - uid = icalcomponent_get_uid (icalcomp); - - ce = e_comp_editor_registry_find (comp_editor_registry, uid); - if (!ce) { - EventEditor *ee; - - ee = event_editor_new (client); - if (!ee) { - g_message ("gnome_calendar_edit_object(): Could not create the event editor"); - return; - } - ce = COMP_EDITOR (ee); - - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); - - comp_editor_edit_comp (ce, comp); - if (meeting) - event_editor_show_meeting (ee); - - e_comp_editor_registry_add (comp_editor_registry, ce, FALSE); - - g_object_unref (comp); - } - - comp_editor_focus (ce); -} - -/** - * gnome_calendar_new_appointment_for: - * @gcal: An Evolution calendar. - * @dtstart: a Unix time_t that marks the beginning of the appointment. - * @dtend: a Unix time_t that marks the end of the appointment. - * @all_day: if true, the dtstart and dtend are expanded to cover the entire - * day, and the event is set to TRANSPARENT. - * - * Opens an event editor dialog for a new appointment. - * - **/ -void -gnome_calendar_new_appointment_for (GnomeCalendar *cal, - time_t dtstart, time_t dtend, - gboolean all_day, - gboolean meeting) -{ - GnomeCalendarPrivate *priv; - struct icaltimetype itt; - CalComponentDateTime dt; - CalComponent *comp; - icalcomponent *icalcomp; - CalComponentTransparency transparency; - const char *category; - - g_return_if_fail (cal != NULL); - g_return_if_fail (GNOME_IS_CALENDAR (cal)); - - priv = cal->priv; - - dt.value = &itt; - if (all_day) - dt.tzid = NULL; - else - dt.tzid = icaltimezone_get_tzid (priv->zone); - - icalcomp = e_cal_model_create_component_with_defaults (e_cal_view_get_model (E_CAL_VIEW (priv->week_view))); - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomp); - - /* DTSTART, DTEND */ - - itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); - if (all_day) { - itt.hour = itt.minute = itt.second = 0; - itt.is_date = TRUE; - } - cal_component_set_dtstart (comp, &dt); - - itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); - if (all_day) { - /* We round it up to the end of the day, unless it is already - set to midnight. */ - if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { - icaltime_adjust (&itt, 1, 0, 0, 0); - } - itt.hour = itt.minute = itt.second = 0; - itt.is_date = TRUE; - } - cal_component_set_dtend (comp, &dt); - - transparency = all_day ? CAL_COMPONENT_TRANSP_TRANSPARENT - : CAL_COMPONENT_TRANSP_OPAQUE; - cal_component_set_transparency (comp, transparency); - - - /* Category */ - - category = cal_search_bar_get_category (CAL_SEARCH_BAR (priv->search_bar)); - cal_component_set_categories (comp, category); - - /* Edit! */ - - cal_component_commit_sequence (comp); - - gnome_calendar_edit_object (cal, gnome_calendar_get_default_client (cal), icalcomp, meeting); - g_object_unref (comp); -} - -/** - * gnome_calendar_new_appointment: - * @gcal: An Evolution calendar. - * - * Opens an event editor dialog for a new appointment. The appointment's start - * and end times are set to the currently selected time range in the calendar - * views. - **/ -void -gnome_calendar_new_appointment (GnomeCalendar *gcal) -{ - time_t dtstart, dtend; - - g_return_if_fail (gcal != NULL); - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - - gnome_calendar_get_current_time_range (gcal, &dtstart, &dtend); - gnome_calendar_new_appointment_for (gcal, dtstart, dtend, FALSE, FALSE); -} - /** * gnome_calendar_new_task: * @gcal: An Evolution calendar. @@ -3020,136 +2881,17 @@ gnome_calendar_delete_selected_occurrence (GnomeCalendar *gcal) } } -void -gnome_calendar_unrecur_selection (GnomeCalendar *gcal) -{ - GnomeCalendarPrivate *priv; - FocusLocation location; - GtkWidget *view; - - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - - priv = gcal->priv; - - location = get_focus_location (gcal); - - if (location == FOCUS_CALENDAR) { - - view = gnome_calendar_get_current_view_widget (gcal); - - if (E_IS_DAY_VIEW (view)) - e_day_view_unrecur_appointment (E_DAY_VIEW (view)); - else - e_week_view_unrecur_appointment (E_WEEK_VIEW (view)); - } -} - -typedef struct { - gboolean remove; - GnomeCalendar *gcal; -} obj_updated_closure; - static gboolean check_instance_cb (CalComponent *comp, time_t instance_start, time_t instance_end, gpointer data) { - obj_updated_closure *closure = data; - - if (instance_start >= closure->gcal->priv->exp_older_than || - instance_end >= closure->gcal->priv->exp_older_than) { - closure->remove = FALSE; - return FALSE; - } - - closure->remove = TRUE; - return TRUE; -} - -static void -purging_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total, - gpointer data) -{ - GnomeCalendarPrivate *priv; - GnomeCalendar *gcal = data; - CalComponent *comp; - icalcomponent *icalcomp; - obj_updated_closure closure; - gchar *msg; - - priv = gcal->priv; - - if (cal_client_get_object (cal_query_get_client (query), uid, &icalcomp) != CAL_CLIENT_GET_SUCCESS) - return; - - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - g_object_unref (comp); - icalcomponent_free (icalcomp); - return; - } - - msg = g_strdup_printf (_("Purging event %s"), uid); - - /* further filter the event, to check the last recurrence end date */ - if (cal_component_has_recurrences (comp)) { - closure.remove = TRUE; - closure.gcal = gcal; - - cal_recur_generate_instances (comp, priv->exp_older_than, -1, - (CalRecurInstanceFn) check_instance_cb, - &closure, - (CalRecurResolveTimezoneFn) cal_client_resolve_tzid_cb, - cal_query_get_client (query), priv->zone); - - if (closure.remove) { - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), msg); - delete_error_dialog (cal_client_remove_object (cal_query_get_client (query), uid), - CAL_COMPONENT_EVENT); - } - } else { - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), msg); - delete_error_dialog (cal_client_remove_object (cal_query_get_client (query), uid), CAL_COMPONENT_EVENT); - } - - g_object_unref (comp); - g_free (msg); -} - -static void -purging_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) -{ - GnomeCalendarPrivate *priv; - GnomeCalendar *gcal = data; - - priv = gcal->priv; - - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); - - g_signal_handlers_disconnect_matched (query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - - priv->exp_queries = g_list_remove (priv->exp_queries, query); - g_object_unref (query); -} + gboolean *remove = data; -static void -purging_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer data) -{ - GnomeCalendarPrivate *priv; - GnomeCalendar *gcal = data; - - priv = gcal->priv; - - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); + *remove = FALSE; - g_signal_handlers_disconnect_matched (query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - - priv->exp_queries = g_list_remove (priv->exp_queries, query); - g_object_unref (query); + return FALSE; } void @@ -3163,11 +2905,6 @@ gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than) priv = gcal->priv; - /* if we have a query, we are already purging */ - if (priv->exp_queries) - return; - - priv->exp_older_than = older_than; start = isodate_from_time_t (0); end = isodate_from_time_t (older_than); sexp = g_strdup_printf ("(and (= (get-vtype) \"VEVENT\")" @@ -3177,27 +2914,47 @@ gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than) e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), _("Purging")); + /* FIXME Confirm expunge */ + client_list = e_cal_model_get_client_list (e_cal_view_get_model (E_CAL_VIEW (priv->week_view))); for (l = client_list; l != NULL; l = l->next) { - CalQuery *exp_query; - - if (cal_client_is_read_only ((CalClient *) l->data)) + CalClient *client = l->data; + GList *objects, *l; + gboolean read_only = TRUE; + + cal_client_is_read_only (client, &read_only, NULL); + if (!read_only) continue; - - exp_query = cal_client_get_query ((CalClient *) l->data, sexp); - if (!exp_query) { - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); - g_message ("gnome_calendar_purge(): Could not create the query"); + + if (!cal_client_get_object_list (client, sexp, &objects, NULL)) { + g_warning (G_STRLOC ": Could not get the objects"); + continue; } - - g_signal_connect (exp_query, "obj_updated", G_CALLBACK (purging_obj_updated_cb), gcal); - g_signal_connect (exp_query, "query_done", G_CALLBACK (purging_query_done_cb), gcal); - g_signal_connect (exp_query, "eval_error", G_CALLBACK (purging_eval_error_cb), gcal); - - priv->exp_queries = g_list_append (priv->exp_queries, exp_query); + + for (l = objects; l; l = l->next) { + CalComponent *comp; + gboolean remove = TRUE; + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data)); + + cal_recur_generate_instances (comp, older_than, -1, + (CalRecurInstanceFn) check_instance_cb, + &remove, + (CalRecurResolveTimezoneFn) cal_client_resolve_tzid_cb, + client, priv->zone); + + /* FIXME Better error handling */ + if (remove) + cal_client_remove_object (client, icalcomponent_get_uid (l->data), NULL); + + g_object_unref (comp); + } } + e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); + g_list_free (client_list); g_free (sexp); g_free (start); diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h index c9bbcbaff4..f56ec69211 100644 --- a/calendar/gui/gnome-cal.h +++ b/calendar/gui/gnome-cal.h @@ -55,7 +55,8 @@ typedef enum { GNOME_CAL_WORK_WEEK_VIEW, GNOME_CAL_WEEK_VIEW, GNOME_CAL_MONTH_VIEW, - GNOME_CAL_LIST_VIEW + GNOME_CAL_LIST_VIEW, + GNOME_CAL_LAST_VIEW } GnomeCalendarViewType; typedef enum @@ -106,9 +107,10 @@ ECalendarTable *gnome_calendar_get_task_pad (GnomeCalendar *gcal); ECalModel *gnome_calendar_get_calendar_model (GnomeCalendar *gcal); CalClient *gnome_calendar_get_default_client (GnomeCalendar *gcal); +void gnome_calendar_set_default_client (GnomeCalendar *gcal, CalClient *client); CalClient *gnome_calendar_get_task_pad_cal_client(GnomeCalendar *gcal); -gboolean gnome_calendar_open (GnomeCalendar *gcal, const char *str_uri); +gboolean gnome_calendar_add_event_uri (GnomeCalendar *gcal, const char *str_uri); void gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp); @@ -145,17 +147,6 @@ void gnome_calendar_get_selected_time_range (GnomeCalendar *gcal, time_t *start_time, time_t *end_time); -void gnome_calendar_edit_object (GnomeCalendar *gcal, - CalClient *client, - icalcomponent *icalcomp, - gboolean meeting); - -void gnome_calendar_new_appointment (GnomeCalendar *gcal); -void gnome_calendar_new_appointment_for (GnomeCalendar *cal, - time_t dtstart, time_t dtend, - gboolean all_day, - gboolean meeting); - void gnome_calendar_new_task (GnomeCalendar *gcal); /* Returns the selected time range for the current view. Note that this may be @@ -193,7 +184,6 @@ void gnome_calendar_paste_clipboard (GnomeCalendar *gcal); void gnome_calendar_delete_selection (GnomeCalendar *gcal); void gnome_calendar_delete_selected_occurrence (GnomeCalendar *gcal); -void gnome_calendar_unrecur_selection (GnomeCalendar *gcal); void gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than); diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c index f5baa8bb05..e2640f01f4 100644 --- a/calendar/gui/itip-utils.c +++ b/calendar/gui/itip-utils.c @@ -70,8 +70,11 @@ static EAccountList *accounts = NULL; EAccountList * itip_addresses_get (void) { - if (accounts == NULL) - accounts = e_account_list_new(gconf_client_get_default()); + if (accounts == NULL) { + GConfClient *gconf_client = gconf_client_get_default (); + accounts = e_account_list_new (gconf_client); + g_object_unref (gconf_client); + } return accounts; } @@ -98,12 +101,14 @@ itip_organizer_is_user (CalComponent *comp, CalClient *client) strip = itip_strip_mailto (organizer.value); if (cal_client_get_static_capability (client, CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS)) { - const char *email; + char *email; - email = cal_client_get_cal_address (client); - if (email && !g_strcasecmp (email, strip)) + if (cal_client_get_cal_address (client, &email, NULL) && !g_strcasecmp (email, strip)) { + g_free (email); + return TRUE; - + } + return FALSE; } @@ -185,8 +190,8 @@ foreach_tzid_callback (icalparameter *param, gpointer data) zone = icalcomponent_get_timezone (tz_data->zones, tzid); if (zone == NULL) zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); - if (zone == NULL && tz_data->client != NULL) - cal_client_get_timezone (tz_data->client, tzid, &zone); + if (zone == NULL && tz_data->client != NULL) + cal_client_get_timezone (tz_data->client, tzid, &zone, NULL); if (zone == NULL) return; @@ -528,28 +533,23 @@ static gboolean comp_server_send (CalComponentItipMethod method, CalComponent *comp, CalClient *client, icalcomponent *zones, GList **users) { - CalClientSendResult result; - icalcomponent *top_level, *new_top_level = NULL; - char *error_msg; + icalcomponent *top_level; gboolean retval = TRUE; + GError *error = NULL; top_level = comp_toplevel_with_zones (method, comp, client, zones); - result = cal_client_send_object (client, top_level, &new_top_level, users, &error_msg); - - if (result == CAL_CLIENT_SEND_SUCCESS) { - icalcomponent *ical_comp; - - ical_comp = icalcomponent_get_inner (new_top_level); - icalcomponent_remove_component (new_top_level, ical_comp); - cal_component_set_icalcomponent (comp, ical_comp); - icalcomponent_free (new_top_level); - } else if (result == CAL_CLIENT_SEND_BUSY) { - e_notice (NULL, GTK_MESSAGE_ERROR, error_msg); - - g_free (error_msg); - retval = FALSE; + if (!cal_client_send_objects (client, top_level, &error)) { + /* FIXME Really need a book problem status code */ + if (error->code != E_CALENDAR_STATUS_OK) { + /* FIXME Better error message */ + e_notice (NULL, GTK_MESSAGE_ERROR, "Unable to book"); + + retval = FALSE; + } } + g_clear_error (&error); + icalcomponent_free (top_level); return retval; @@ -755,7 +755,8 @@ comp_compliant (CalComponentItipMethod method, CalComponent *comp, CalClient *cl if (from_zone == NULL) from_zone = icaltimezone_get_builtin_timezone_from_tzid (dt.tzid); if (from_zone == NULL && client != NULL) - cal_client_get_timezone (client, dt.tzid, &from_zone); + /* FIXME Error checking */ + cal_client_get_timezone (client, dt.tzid, &from_zone, NULL); } to_zone = icaltimezone_get_utc_timezone (); diff --git a/calendar/gui/main.c b/calendar/gui/main.c index a15c0ef846..681417f1df 100644 --- a/calendar/gui/main.c +++ b/calendar/gui/main.c @@ -49,9 +49,9 @@ #include "tasks-control.h" -#define FACTORY_ID "OAFIID:GNOME_Evolution_Calendar_Factory" +#define FACTORY_ID "OAFIID:GNOME_Evolution_Calendar_Factory_2" -#define CALENDAR_COMPONENT_ID "OAFIID:GNOME_Evolution_Calendar_ShellComponent" +#define CALENDAR_COMPONENT_ID "OAFIID:GNOME_Evolution_Calendar_Component" #define CALENDAR_CONTROL_ID "OAFIID:GNOME_Evolution_Calendar_Control" #define TASKS_CONTROL_ID "OAFIID:GNOME_Evolution_Tasks_Control" #define ITIP_CONTROL_ID "OAFIID:GNOME_Evolution_Calendar_iTip_Control" @@ -155,23 +155,19 @@ factory (BonoboGenericFactory *factory, initialized = TRUE; } - if (strcmp (component_id, CALENDAR_COMPONENT_ID) == 0) - return calendar_component_get_object (); - if (strcmp (component_id, CALENDAR_CONTROL_ID) == 0) + if (strcmp (component_id, CALENDAR_COMPONENT_ID) == 0) { + BonoboObject *object = BONOBO_OBJECT (calendar_component_peek ()); + bonobo_object_ref (object); + return object; + } else if (strcmp (component_id, CALENDAR_CONTROL_ID) == 0) return BONOBO_OBJECT (control_factory_new_control ()); - if (strcmp (component_id, TASKS_CONTROL_ID) == 0) + else if (strcmp (component_id, TASKS_CONTROL_ID) == 0) return BONOBO_OBJECT (tasks_control_new ()); - if (strcmp (component_id, ITIP_CONTROL_ID) == 0) + else if (strcmp (component_id, ITIP_CONTROL_ID) == 0) return BONOBO_OBJECT (itip_bonobo_control_new ()); - if (strcmp (component_id, CONFIG_CONTROL_ID) == 0) { - extern EvolutionShellClient *global_shell_client; /* FIXME ugly */ - - if (global_shell_client == NULL) - return NULL; - else - return BONOBO_OBJECT (cal_prefs_dialog_new ()); - } - if (strcmp (component_id, COMP_EDITOR_FACTORY_ID) == 0) + else if (strcmp (component_id, CONFIG_CONTROL_ID) == 0) + return BONOBO_OBJECT (cal_prefs_dialog_new ()); + else if (strcmp (component_id, COMP_EDITOR_FACTORY_ID) == 0) return BONOBO_OBJECT (comp_editor_factory_fn ()); g_warning (FACTORY_ID ": Don't know what to do with %s", component_id); diff --git a/calendar/gui/migration.c b/calendar/gui/migration.c new file mode 100644 index 0000000000..be93309f1f --- /dev/null +++ b/calendar/gui/migration.c @@ -0,0 +1,126 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* calendar-component.c + * + * Copyright (C) 2003 Ximian, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Rodrigo Moya <rodrigo@ximian.com> + */ + +#include <bonobo/bonobo-i18n.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-xfer.h> +#include <gal/util/e-util.h> +#include "migration.h" + +static gboolean +process_calendar_dir (ESourceGroup *source_group, const char *path, + const char *name, const char *base_uri) +{ + char *s; + GnomeVFSURI *from, *to; + GnomeVFSResult vres; + ESource *source; + GDir *dir; + gboolean retval = TRUE; + + s = g_build_filename (path, "calendar.ics", NULL); + if (!g_file_test (s, G_FILE_TEST_EXISTS)) { + g_free (s); + return FALSE; + } + + /* transfer the old file to its new location */ + from = gnome_vfs_uri_new (s); + g_free (s); + if (!from) + return FALSE; + + s = g_build_filename (e_source_group_peek_base_uri (source_group), base_uri, + "calendar.ics", NULL); + if (e_mkdir_hier (s, 0700) != 0) { + gnome_vfs_uri_unref (from); + g_free (s); + return FALSE; + } + to = gnome_vfs_uri_new (s); + g_free (s); + if (!to) { + gnome_vfs_uri_unref (from); + return FALSE; + } + + vres = gnome_vfs_xfer_uri ((const GnomeVFSURI *) from, + (const GnomeVFSURI *) to, + GNOME_VFS_XFER_DEFAULT, + GNOME_VFS_XFER_ERROR_MODE_ABORT, + GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, + NULL, NULL); + gnome_vfs_uri_unref (from); + gnome_vfs_uri_unref (to); + + if (vres != GNOME_VFS_OK) + return FALSE; + + /* create the new source */ + source = e_source_new (name, base_uri); + e_source_group_add_source (source_group, source, -1); + + /* process subfolders */ + s = g_build_filename (path, "subfolders", NULL); + dir = g_dir_open (s, 0, NULL); + if (dir) { + const char *name, *tmp_s; + + while ((name = g_dir_read_name (dir))) { + tmp_s = g_build_filename (s, name, NULL); + if (g_file_test (tmp_s, G_FILE_TEST_IS_DIR)) { + retval = process_calendar_dir (source_group, tmp_s, name, name); + } + + g_free (tmp_s); + } + + g_dir_close (dir); + } + + g_free (s); + + return retval; +} + +gboolean +migrate_old_calendars (ESourceGroup *source_group) +{ + char *path; + gboolean retval; + + g_return_val_if_fail (E_IS_SOURCE_GROUP (source_group), FALSE); + + path = g_build_filename (g_get_home_dir (), "evolution", NULL); + if (!g_file_test (path, G_FILE_TEST_IS_DIR)) { + g_free (path); + return FALSE; + } + g_free (path); + + /* look for the top-level calendar */ + path = g_build_filename (g_get_home_dir (), "evolution/local/Calendar", NULL); + retval = process_calendar_dir (source_group, path, _("Personal"), "Personal"); + g_free (path); + + return retval; +} diff --git a/calendar/gui/migration.h b/calendar/gui/migration.h new file mode 100644 index 0000000000..2453d47abd --- /dev/null +++ b/calendar/gui/migration.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* calendar-component.c + * + * Copyright (C) 2003 Ximian, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Rodrigo Moya <rodrigo@ximian.com> + */ + +#ifndef MIGRATION_H +#define MIGRATION_H + +#include <e-util/e-source-group.h> + +gboolean migrate_old_calendars (ESourceGroup *source_group); + +#endif diff --git a/calendar/gui/print.c b/calendar/gui/print.c index 6aeb9f6566..0c0fa44886 100644 --- a/calendar/gui/print.c +++ b/calendar/gui/print.c @@ -522,6 +522,16 @@ format_date(time_t time, int flags, char *buffer, int bufflen) return buffer; } +static gboolean +instance_cb (CalComponent *comp, time_t instance_start, time_t instance_end, gpointer data) +{ + gboolean *found = data; + + *found = TRUE; + + return FALSE; +} + /* print out the month small, embolden any days with events. @@ -625,16 +635,16 @@ print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, day = days[y * 7 + x]; if (day != 0) { - GList *uids; + gboolean found = FALSE; sprintf (buf, "%d", day); /* this is a slow messy way to do this ... but easy ... */ - uids = cal_client_get_objects_in_range (client, - CALOBJ_TYPE_EVENT, - now, time_day_end_with_zone (now, zone)); - font = uids ? font_bold : font_normal; - cal_obj_uid_list_free (uids); + cal_client_generate_instances (client, now, CALOBJ_TYPE_EVENT, + time_day_end_with_zone (now, zone), + instance_cb, &found); + + font = found ? font_bold : font_normal; next = time_add_day_with_zone (now, 1, zone); if ((now >= greystart && now < greyend) @@ -1805,7 +1815,7 @@ print_todo_details (GnomePrintContext *pc, GnomeCalendar *gcal, comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp)); - cal_component_get_summary (comp_data->icalcomp, &summary); + cal_component_get_summary (comp, &summary); if (!summary.value) { g_object_unref (comp); continue; @@ -2161,11 +2171,8 @@ get_zone_from_tzid (CalClient *client, const char *tzid) the builtin timezone with the TZID first. */ zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); if (!zone) { - CalClientGetStatus status; - - status = cal_client_get_timezone (client, tzid, &zone); - /* FIXME: Handle error better. */ - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (client, tzid, &zone, NULL)) + /* FIXME: Handle error better. */ g_warning ("Couldn't get timezone from server: %s", tzid ? tzid : ""); } diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c index 03e0b3dee4..147a69f246 100644 --- a/calendar/gui/tag-calendar.c +++ b/calendar/gui/tag-calendar.c @@ -162,7 +162,6 @@ resolve_tzid_cb (const char *tzid, gpointer data) { CalClient *client; icaltimezone *zone = NULL; - CalClientGetStatus status; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (IS_CAL_CLIENT (data), NULL); @@ -174,7 +173,7 @@ resolve_tzid_cb (const char *tzid, gpointer data) if (!zone) { /* FIXME: Handle errors. */ - status = cal_client_get_timezone (client, tzid, &zone); + cal_client_get_timezone (client, tzid, &zone, NULL); } return zone; diff --git a/calendar/gui/tasks-control.c b/calendar/gui/tasks-control.c index 5ed9faa0d6..d97ed2d585 100644 --- a/calendar/gui/tasks-control.c +++ b/calendar/gui/tasks-control.c @@ -235,12 +235,12 @@ static void sensitize_commands (ETasks *tasks, BonoboControl *control, int n_selected) { BonoboUIComponent *uic; - gboolean read_only; + gboolean read_only = TRUE; uic = bonobo_control_get_ui_component (control); g_assert (uic != NULL); - read_only = cal_client_is_read_only (e_tasks_get_cal_client (tasks)); + cal_client_is_read_only (e_tasks_get_cal_client (tasks), &read_only, NULL); bonobo_ui_component_set_prop (uic, "/commands/TasksCut", "sensitive", n_selected == 0 || read_only ? "0" : "1", |