diff options
-rw-r--r-- | calendar/ChangeLog | 75 | ||||
-rw-r--r-- | calendar/cal-client/cal-listener.c | 6 | ||||
-rw-r--r-- | calendar/cal-client/cal-query.c | 1 | ||||
-rw-r--r-- | calendar/cal-client/query-listener.c | 41 | ||||
-rw-r--r-- | calendar/cal-client/query-listener.h | 2 | ||||
-rw-r--r-- | calendar/gui/cal-search-bar.c | 45 | ||||
-rw-r--r-- | calendar/gui/calendar-commands.c | 16 | ||||
-rw-r--r-- | calendar/gui/calendar-model.c | 10 | ||||
-rw-r--r-- | calendar/gui/dialogs/recurrence-page.c | 2 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 48 | ||||
-rw-r--r-- | calendar/gui/e-day-view.h | 6 | ||||
-rw-r--r-- | calendar/gui/e-week-view.c | 49 | ||||
-rw-r--r-- | calendar/gui/e-week-view.h | 6 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.c | 487 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.h | 11 | ||||
-rw-r--r-- | calendar/gui/main.c | 2 | ||||
-rw-r--r-- | calendar/gui/tag-calendar.c | 12 | ||||
-rw-r--r-- | calendar/gui/tag-calendar.h | 2 |
18 files changed, 656 insertions, 165 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index fd71978bb1..7be7b830ef 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,5 +1,80 @@ 2001-08-03 Federico Mena Quintero <federico@ximian.com> + * cal-client/query-listener.c (query_listener_stop_notification): + New function; stops further notification from happening. This is + needed since the listener is destroyed asynchronously from the + Wombat and the corresponding CalQuery may already have died. + (impl_notifyObjUpdated): Do not notify if requested. + (impl_notifyObjRemoved): Likewise. + (impl_notifyQueryDone): Likewise. + (impl_notifyEvalError): Likewise. + + * cal-client/cal-query.c (cal_query_destroy): Use + query_listener_stop_notification(). + + * cal-client/cal-listener.c (cal_listener_destroy): Nullify the + pointers to the callback functions. + + * gui/e-day-view.c (update_query): Commit our state of no longer + having a query before unrefing it. We may reenter from the ORBit + main loop and we *really* want this information to be committed. + + * gui/e-week-view.c (update_query): Likewise. + + * gui/calendar-model.c (update_query): Likewise. + + * gui/tag-calendar.c (tag_calendar_by_comp): Added a "clear_first" + argument that indicates whether the ECalendar should be cleared of + any marks first. + + * gui/calendar-commands.c (calendar_control_activate): Removed + ifdefed-out view buttons code from the Gnomecal days. + + * gui/gnome-cal.c (client_categories_changed_cb): Merge the + categories of the calendar and tasks clients so that we can + display the categories in both sets. + (gnome_calendar_construct): Connect to "categories_changed" on + both clients. + (gnome_calendar_on_date_navigator_selection_changed): Removed call + to gnome_calendar_update_view_buttons(). + (gnome_calendar_update_view_buttons): Removed. We cannot have + this until Bonobo supports radio toolbar items. + (gnome_calendar_set_view_buttons): Removed. + (gnome_calendar_dayjump): Do not use priv->day_button. + (GnomeCalendarPrivate): Removed the {day,work_week,week,month}_button + fields. + (gnome_calendar_set_query): Start a retagging process of the date + navigator so that it reflects the current query. + (update_query): New function to restart a query for the date navigator. + (initial_load): Use update_query() instead of tagging the date + navigator directly. + (gnome_calendar_on_date_navigator_date_range_changed): Likewise. + (client_cal_opened_cb): Use update_query() instead of initial_load(). + (initial_load): Removed. + (client_obj_updated_cb): Removed. + (client_obj_removed_cb): Removed. + (gnome_calendar_new_appointment_for): Set the default category of + the new component. + (search_bar_category_changed_cb): Set the default category for the + calendar views. + + * gui/cal-search-bar.c (cal_search_bar_set_categories): Sort the + categories before creating the menu. + + * gui/e-day-view.c (adjust_query_sexp): Return NULL instead of + "#f" if the time range is not set yet. + (update_query): Do not start a query if the time range is not set. + (e_day_view_set_default_category): New function. + (e_day_view_key_press): Set the default category on the new + component. + + * gui/e-week-view.c (adjust_query_sexp): Analogous to the above. + (update_query): Analogous to the above. + (e_week_view_set_default_category): Analogous to the above. + (e_week_view_key_press): Analogous to the above. + +2001-08-03 Federico Mena Quintero <federico@ximian.com> + Fixes bug #1407. * gui/dialogs/cal-prefs-dialog.glade: Removed the alarm diff --git a/calendar/cal-client/cal-listener.c b/calendar/cal-client/cal-listener.c index 087d5e9c00..0062718155 100644 --- a/calendar/cal-client/cal-listener.c +++ b/calendar/cal-client/cal-listener.c @@ -115,6 +115,12 @@ cal_listener_destroy (GtkObject *object) listener = CAL_LISTENER (object); priv = listener->priv; + priv->cal_opened_fn = NULL; + priv->obj_updated_fn = NULL; + priv->obj_removed_fn = NULL; + priv->categories_changed_fn = NULL; + priv->fn_data = NULL; + CORBA_exception_init (&ev); result = CORBA_Object_is_nil (priv->cal, &ev); diff --git a/calendar/cal-client/cal-query.c b/calendar/cal-client/cal-query.c index 727a2dcb3b..958bad9f52 100644 --- a/calendar/cal-client/cal-query.c +++ b/calendar/cal-client/cal-query.c @@ -181,6 +181,7 @@ cal_query_destroy (GtkObject *object) priv = query->priv; /* The server unrefs the query listener, so we just NULL it out here */ + query_listener_stop_notification (priv->ql); priv->ql = NULL; if (priv->corba_query != CORBA_OBJECT_NIL) { diff --git a/calendar/cal-client/query-listener.c b/calendar/cal-client/query-listener.c index 980b0a1ece..51563fd9b0 100644 --- a/calendar/cal-client/query-listener.c +++ b/calendar/cal-client/query-listener.c @@ -36,6 +36,9 @@ struct _QueryListenerPrivate { QueryListenerQueryDoneFn query_done_fn; QueryListenerEvalErrorFn eval_error_fn; gpointer fn_data; + + /* Whether notification is desired */ + gboolean notify : 1; }; @@ -105,6 +108,8 @@ query_listener_init (QueryListener *ql) priv->query_done_fn = NULL; priv->eval_error_fn = NULL; priv->fn_data = NULL; + + priv->notify = TRUE; } /* Destroy handler for the live search query listener */ @@ -126,6 +131,8 @@ query_listener_destroy (GtkObject *object) priv->eval_error_fn = NULL; priv->fn_data = NULL; + priv->notify = FALSE; + g_free (priv); ql->priv = NULL; @@ -152,6 +159,9 @@ impl_notifyObjUpdated (PortableServer_Servant servant, ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; + if (!priv->notify) + return; + g_assert (priv->obj_updated_fn != NULL); (* priv->obj_updated_fn) (ql, uid, query_in_progress, n_scanned, total, priv->fn_data); } @@ -168,6 +178,9 @@ impl_notifyObjRemoved (PortableServer_Servant servant, ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; + if (!priv->notify) + return; + g_assert (priv->obj_removed_fn != NULL); (* priv->obj_removed_fn) (ql, uid, priv->fn_data); } @@ -185,6 +198,9 @@ impl_notifyQueryDone (PortableServer_Servant servant, ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; + if (!priv->notify) + return; + g_assert (priv->query_done_fn != NULL); (* priv->query_done_fn) (ql, corba_status, error_str, priv->fn_data); } @@ -201,6 +217,9 @@ impl_notifyEvalError (PortableServer_Servant servant, ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; + if (!priv->notify) + return; + g_assert (priv->eval_error_fn != NULL); (* priv->eval_error_fn) (ql, error_str, priv->fn_data); } @@ -279,3 +298,25 @@ query_listener_new (QueryListenerObjUpdatedFn obj_updated_fn, eval_error_fn, fn_data); } + +/** + * query_listener_stop_notification: + * @ql: A query listener. + * + * Informs a query listener that no further notification is desired. The + * callbacks specified when the listener was created will no longer be invoked + * after this function is called. + **/ +void +query_listener_stop_notification (QueryListener *ql) +{ + QueryListenerPrivate *priv; + + g_return_if_fail (ql != NULL); + g_return_if_fail (IS_QUERY_LISTENER (ql)); + + priv = ql->priv; + g_return_if_fail (priv->notify != FALSE); + + priv->notify = FALSE; +} diff --git a/calendar/cal-client/query-listener.h b/calendar/cal-client/query-listener.h index 53be9f3229..1330216260 100644 --- a/calendar/cal-client/query-listener.h +++ b/calendar/cal-client/query-listener.h @@ -89,6 +89,8 @@ QueryListener *query_listener_new (QueryListenerObjUpdatedFn obj_updated_fn, QueryListenerEvalErrorFn eval_error_fn, gpointer fn_data); +void query_listener_stop_notification (QueryListener *ql); + END_GNOME_DECLS diff --git a/calendar/gui/cal-search-bar.c b/calendar/gui/cal-search-bar.c index e5cfcf95e9..a112409412 100644 --- a/calendar/gui/cal-search-bar.c +++ b/calendar/gui/cal-search-bar.c @@ -23,6 +23,7 @@ #include <config.h> #endif +#include <stdlib.h> #include <glib.h> #include <gtk/gtkmenu.h> #include <gtk/gtkmenuitem.h> @@ -401,6 +402,39 @@ item_destroyed_cb (GtkObject *object, gpointer data) g_free (category); } +/* Used from qsort() */ +static int +compare_categories_cb (const void *a, const void *b) +{ + const char **ca, **cb; + + ca = (const char **) a; + cb = (const char **) b; + + /* FIXME: should use some utf8 strcoll() thingy */ + return strcmp (*ca, *cb); +} + +/* Creates a sorted array of categories based on the original one; does not + * duplicate the string values. + */ +static GPtrArray * +sort_categories (GPtrArray *categories) +{ + GPtrArray *c; + int i; + + c = g_ptr_array_new (); + g_ptr_array_set_size (c, categories->len); + + for (i = 0; i < categories->len; i++) + c->pdata[i] = categories->pdata[i]; + + qsort (c->pdata, c->len, sizeof (gpointer), compare_categories_cb); + + return c; +} + /** * cal_search_bar_set_categories: * @cal_search: A calendar search bar. @@ -417,6 +451,7 @@ cal_search_bar_set_categories (CalSearchBar *cal_search, GPtrArray *categories) CalSearchBarPrivate *priv; GtkMenu *menu; GtkWidget *item; + GPtrArray *sorted; int i; g_return_if_fail (cal_search != NULL); @@ -450,19 +485,21 @@ cal_search_bar_set_categories (CalSearchBar *cal_search, GPtrArray *categories) /* Categories items */ - for (i = 0; i < categories->len; i++) { + sorted = sort_categories (categories); + + for (i = 0; i < sorted->len; i++) { char *str; /* FIXME: Put the category icons here */ - str = e_utf8_to_gtk_string (GTK_WIDGET (menu), categories->pdata[i]); + str = e_utf8_to_gtk_string (GTK_WIDGET (menu), sorted->pdata[i]); if (!str) continue; item = gtk_menu_item_new_with_label (str); g_free (str); - gtk_object_set_user_data (GTK_OBJECT (item), g_strdup (categories->pdata[i])); + gtk_object_set_user_data (GTK_OBJECT (item), g_strdup (sorted->pdata[i])); gtk_signal_connect (GTK_OBJECT (item), "destroy", GTK_SIGNAL_FUNC (item_destroyed_cb), NULL); @@ -471,6 +508,8 @@ cal_search_bar_set_categories (CalSearchBar *cal_search, GPtrArray *categories) gtk_widget_show (item); } + g_ptr_array_free (sorted, TRUE); + /* Set the new menu; the old one will be destroyed automatically */ gtk_option_menu_set_menu (priv->categories_omenu, GTK_WIDGET (menu)); diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c index 8f4c9da265..22640d2629 100644 --- a/calendar/gui/calendar-commands.c +++ b/calendar/gui/calendar-commands.c @@ -513,22 +513,6 @@ calendar_control_activate (BonoboControl *control, bonobo_ui_component_set_container (uic, remote_uih); bonobo_object_release_unref (remote_uih, NULL); -#if 0 - /* FIXME: Need to update this to use new Bonobo ui stuff somehow. - Also need radio buttons really. */ - - /* Note that these indices should correspond with the button indices - in the gnome_toolbar_view_buttons UIINFO struct. */ - gnome_calendar_set_view_buttons (cal, - gnome_toolbar_view_buttons[0].widget, - gnome_toolbar_view_buttons[1].widget, - gnome_toolbar_view_buttons[2].widget, - gnome_toolbar_view_buttons[3].widget); - - /* This makes the appropriate radio button in the toolbar active. */ - gnome_calendar_update_view_buttons (cal); -#endif - bonobo_ui_component_add_verb_list_with_data (uic, verbs, gcal); bonobo_ui_component_freeze (uic, NULL); diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c index 94221fdd61..43195071f0 100644 --- a/calendar/gui/calendar-model.c +++ b/calendar/gui/calendar-model.c @@ -1897,6 +1897,7 @@ static void update_query (CalendarModel *model) { CalendarModelPrivate *priv; + CalQuery *old_query; char *real_sexp; priv = model->priv; @@ -1909,9 +1910,12 @@ update_query (CalendarModel *model) && cal_client_get_load_state (priv->client) == CAL_CLIENT_LOAD_LOADED)) return; - if (priv->query) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->query), model); - gtk_object_unref (GTK_OBJECT (priv->query)); + old_query = priv->query; + priv->query = NULL; + + if (old_query) { + gtk_signal_disconnect_by_data (GTK_OBJECT (old_query), model); + gtk_object_unref (GTK_OBJECT (old_query)); } g_assert (priv->sexp != NULL); diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c index 5c7e7d65cb..20310f6433 100644 --- a/calendar/gui/dialogs/recurrence-page.c +++ b/calendar/gui/dialogs/recurrence-page.c @@ -900,7 +900,7 @@ preview_recur (RecurrencePage *rpage) fill_component (rpage, comp); tag_calendar_by_comp (E_CALENDAR (priv->preview_calendar), comp, - COMP_EDITOR_PAGE (rpage)->client); + COMP_EDITOR_PAGE (rpage)->client, TRUE); gtk_object_unref (GTK_OBJECT (comp)); } diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index daff360ab6..e1b5a7b444 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -565,6 +565,8 @@ e_day_view_init (EDayView *day_view) day_view->auto_scroll_timeout_id = 0; + day_view->default_category = NULL; + /* Create the large font. */ day_view->large_font = gdk_font_load (E_DAY_VIEW_LARGE_FONT); if (!day_view->large_font) @@ -896,8 +898,15 @@ e_day_view_destroy (GtkObject *object) day_view->query = NULL; } - if (day_view->large_font) + if (day_view->large_font) { gdk_font_unref (day_view->large_font); + day_view->large_font = NULL; + } + + if (day_view->default_category) { + g_free (day_view->default_category); + day_view->default_category = NULL; + } gdk_cursor_destroy (day_view->normal_cursor); gdk_cursor_destroy (day_view->move_cursor); @@ -1562,7 +1571,7 @@ adjust_query_sexp (EDayView *day_view, const char *sexp) /* If the dates have not been set yet, we just want an empty query. */ if (day_view->lower == 0 || day_view->upper == 0) - return g_strdup ("#f"); + return NULL; start = isodate_from_time_t (day_view->lower); end = isodate_from_time_t (day_view->upper); @@ -1585,6 +1594,7 @@ adjust_query_sexp (EDayView *day_view, const char *sexp) static void update_query (EDayView *day_view) { + CalQuery *old_query; char *real_sexp; e_day_view_free_events (day_view); @@ -1595,13 +1605,19 @@ update_query (EDayView *day_view) && cal_client_get_load_state (day_view->client) == CAL_CLIENT_LOAD_LOADED)) return; - if (day_view->query) { - gtk_signal_disconnect_by_data (GTK_OBJECT (day_view->query), day_view); - gtk_object_unref (GTK_OBJECT (day_view->query)); + old_query = day_view->query; + day_view->query = NULL; + + if (old_query) { + gtk_signal_disconnect_by_data (GTK_OBJECT (old_query), day_view); + gtk_object_unref (GTK_OBJECT (old_query)); } g_assert (day_view->sexp != NULL); + real_sexp = adjust_query_sexp (day_view, day_view->sexp); + if (!real_sexp) + return; /* No time range is set, so don't start a query */ day_view->query = cal_client_get_query (day_view->client, real_sexp); g_free (real_sexp); @@ -1698,6 +1714,26 @@ e_day_view_set_query (EDayView *day_view, const char *sexp) } +/** + * 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, @@ -4933,6 +4969,8 @@ e_day_view_key_press (GtkWidget *widget, GdkEventKey *event) day_view->zone); cal_component_set_dtend (comp, &dt); + cal_component_set_categories (comp, day_view->default_category); + /* We add the event locally and start editing it. When we get the "update_event" callback from the server, we basically ignore it. If we were to wait for the "update_event" callback it wouldn't be diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index bddc36b708..bc663d7a6c 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -480,6 +480,9 @@ struct _EDayView /* the invisible widget to manage the clipboard selections */ GtkWidget *invisible; gchar *clipboard_selection; + + /* The default category for new events */ + char *default_category; }; struct _EDayViewClass @@ -500,6 +503,9 @@ void e_day_view_set_cal_client (EDayView *day_view, 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); + /* This sets the selected time range. The EDayView will show the day or week corresponding to the start time. If the start_time & end_time are not equal and are both visible in the view, then the selection is set to those times, diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index c0b9d82a10..5d269cf471 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -297,6 +297,8 @@ 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; week_view->small_font = gdk_font_load (E_WEEK_VIEW_SMALL_FONT); @@ -463,8 +465,15 @@ e_week_view_destroy (GtkObject *object) week_view->query = NULL; } - if (week_view->small_font) + if (week_view->small_font) { gdk_font_unref (week_view->small_font); + week_view->small_font = NULL; + } + + if (week_view->default_category) { + g_free (week_view->default_category); + week_view->default_category = NULL; + } gdk_cursor_destroy (week_view->normal_cursor); gdk_cursor_destroy (week_view->move_cursor); @@ -1056,7 +1065,7 @@ adjust_query_sexp (EWeekView *week_view, const char *sexp) /* If the dates have not been set yet, we just want an empty query. */ if (!g_date_valid (&week_view->first_day_shown)) - return g_strdup ("#f"); + return NULL; num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; @@ -1080,6 +1089,7 @@ adjust_query_sexp (EWeekView *week_view, const char *sexp) static void update_query (EWeekView *week_view) { + CalQuery *old_query; char *real_sexp; e_week_view_free_events (week_view); @@ -1089,13 +1099,19 @@ update_query (EWeekView *week_view) && cal_client_get_load_state (week_view->client) == CAL_CLIENT_LOAD_LOADED)) return; - if (week_view->query) { - gtk_signal_disconnect_by_data (GTK_OBJECT (week_view->query), week_view); - gtk_object_unref (GTK_OBJECT (week_view->query)); + old_query = week_view->query; + week_view->query = NULL; + + if (old_query) { + gtk_signal_disconnect_by_data (GTK_OBJECT (old_query), week_view); + gtk_object_unref (GTK_OBJECT (old_query)); } g_assert (week_view->sexp != NULL); + real_sexp = adjust_query_sexp (week_view, week_view->sexp); + if (!real_sexp) + return; /* No time range is set, so don't start a query */ week_view->query = cal_client_get_query (week_view->client, real_sexp); g_free (real_sexp); @@ -1192,6 +1208,27 @@ e_week_view_set_query (EWeekView *week_view, const char *sexp) } +/** + * 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. */ @@ -3091,6 +3128,8 @@ e_week_view_key_press (GtkWidget *widget, GdkEventKey *event) week_view->zone); cal_component_set_dtend (comp, &date); + cal_component_set_categories (comp, week_view->default_category); + /* We add the event locally and start editing it. We don't send the new event to the server until the edit is finished. FIXME: If we get an obj-updated or obj-removed signal while editing diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h index 5b3f257f5e..a75cc5df5e 100644 --- a/calendar/gui/e-week-view.h +++ b/calendar/gui/e-week-view.h @@ -353,6 +353,9 @@ struct _EWeekView /* the invisible widget to manage the clipboard selections */ GtkWidget *invisible; gchar *clipboard_selection; + + /* The default category for new events */ + char *default_category; }; struct _EWeekViewClass @@ -381,6 +384,9 @@ void e_week_view_set_cal_client (EWeekView *week_view, void e_week_view_set_query (EWeekView *week_view, const char *sexp); +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. */ diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 847a89ea06..2588d4dee2 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -65,6 +65,9 @@ struct _GnomeCalendarPrivate { /* The calendar client object we monitor */ CalClient *client; + /* Set of categories from the calendar client */ + GPtrArray *cal_categories; + /* * The TaskPad Folder. */ @@ -72,6 +75,9 @@ struct _GnomeCalendarPrivate { /* The calendar client object we monitor */ CalClient *task_pad_client; + /* Set of categories from the tasks client */ + GPtrArray *tasks_categories; + /* * Fields for the calendar view */ @@ -101,11 +107,9 @@ struct _GnomeCalendarPrivate { GtkWidget *week_view; GtkWidget *month_view; - /* These are the toolbar radio buttons for switching views. */ - GtkWidget *day_button; - GtkWidget *work_week_button; - GtkWidget *week_button; - GtkWidget *month_button; + /* Calendar query for the date navigator */ + CalQuery *dn_query; + char *sexp; /* 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 @@ -170,6 +174,8 @@ static void gnome_calendar_on_date_navigator_selection_changed (ECalendarItem GnomeCalendar *gcal); static void gnome_calendar_notify_dates_shown_changed (GnomeCalendar *gcal); +static void update_query (GnomeCalendar *gcal); + static GtkVBoxClass *parent_class; @@ -227,6 +233,197 @@ gnome_calendar_class_init (GnomeCalendarClass *class) class->dates_shown_changed = NULL; } +/* 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) +{ + GnomeCalendar *gcal; + GnomeCalendarPrivate *priv; + CalComponent *comp; + CalClientGetStatus status; + + gcal = GNOME_CALENDAR (data); + priv = gcal->priv; + + status = cal_client_get_object (priv->client, uid, &comp); + + switch (status) { + case CAL_CLIENT_GET_SUCCESS: + /* Everything is fine */ + break; + + case CAL_CLIENT_GET_SYNTAX_ERROR: + g_message ("dn_query_obj_updated_cb(): Syntax error while getting object `%s'", uid); + break; + + case CAL_CLIENT_GET_NOT_FOUND: + /* The object is no longer in the server, so do nothing */ + break; + + default: + g_assert_not_reached (); + return; + } + + tag_calendar_by_comp (priv->date_navigator, comp, priv->client, FALSE); + gtk_object_unref (GTK_OBJECT (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) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + /* Just retag the whole thing */ + update_query (gcal); +} + +/* Callback used when the calendar query is done */ +static void +dn_query_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, + gpointer data) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + /* FIXME */ + + if (status != CAL_QUERY_DONE_SUCCESS) + fprintf (stderr, "query done: %s\n", error_str); +} + +/* Callback used when the calendar query reports an evaluation error */ +static void +dn_query_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + /* FIXME */ + + fprintf (stderr, "eval error: %s\n", error_str); +} + +/* Computes the range of time that the date navigator is showing */ +static void +get_date_navigator_range (GnomeCalendar *gcal, time_t *start_time, time_t *end_time) +{ + GnomeCalendarPrivate *priv; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + struct icaltimetype start_tt; + struct icaltimetype end_tt; + + priv = gcal->priv; + + start_tt = icaltime_null_time (); + end_tt = icaltime_null_time (); + + if (!e_calendar_item_get_date_range (priv->date_navigator->calitem, + &start_year, &start_month, &start_day, + &end_year, &end_month, &end_day)) { + *start_time = -1; + *end_time = -1; + return; + } + + start_tt.year = start_year; + start_tt.month = start_month + 1; + start_tt.day = start_day; + + end_tt.year = end_year; + end_tt.month = end_month + 1; + end_tt.day = end_day; + + icaltime_adjust (&end_tt, 1, 0, 0, 0); + + *start_time = icaltime_as_timet_with_zone (start_tt, priv->zone); + *end_time = icaltime_as_timet_with_zone (end_tt, priv->zone); +} + +/* Adjusts a given query sexp with the time range of the date navigator */ +static char * +adjust_query_sexp (GnomeCalendar *gcal, const char *sexp) +{ + time_t start_time, end_time; + char *start, *end; + char *new_sexp; + + get_date_navigator_range (gcal, &start_time, &end_time); + if (start_time == -1 || end_time == -1) + return NULL; + + start = isodate_from_time_t (start_time); + end = isodate_from_time_t (end_time); + + new_sexp = g_strdup_printf ("(and (= (get-vtype) \"VEVENT\")" + " (occur-in-time-range? (make-time \"%s\")" + " (make-time \"%s\"))" + " %s)", + start, end, + sexp); + + g_free (start); + g_free (end); + + return new_sexp; +} + +/* Restarts a query for the date navigator in the calendar */ +static void +update_query (GnomeCalendar *gcal) +{ + GnomeCalendarPrivate *priv; + CalQuery *old_query; + char *real_sexp; + + priv = gcal->priv; + + e_calendar_item_clear_marks (priv->date_navigator->calitem); + + if (!(priv->client + && cal_client_get_load_state (priv->client) == CAL_CLIENT_LOAD_LOADED)) + return; + + old_query = priv->dn_query; + priv->dn_query = NULL; + + if (old_query) { + gtk_signal_disconnect_by_data (GTK_OBJECT (old_query), gcal); + gtk_object_unref (GTK_OBJECT (old_query)); + } + + g_assert (priv->sexp != NULL); + + real_sexp = adjust_query_sexp (gcal, priv->sexp); + if (!real_sexp) + return; /* No time range is set, so don't start a query */ + + priv->dn_query = cal_client_get_query (priv->client, real_sexp); + g_free (real_sexp); + + if (!priv->dn_query) { + g_message ("update_query(): Could not create the query"); + return; + } + + gtk_signal_connect (GTK_OBJECT (priv->dn_query), "obj_updated", + GTK_SIGNAL_FUNC (dn_query_obj_updated_cb), gcal); + gtk_signal_connect (GTK_OBJECT (priv->dn_query), "obj_removed", + GTK_SIGNAL_FUNC (dn_query_obj_removed_cb), gcal); + gtk_signal_connect (GTK_OBJECT (priv->dn_query), "query_done", + GTK_SIGNAL_FUNC (dn_query_query_done_cb), gcal); + gtk_signal_connect (GTK_OBJECT (priv->dn_query), "eval_error", + GTK_SIGNAL_FUNC (dn_query_eval_error_cb), gcal); +} + /** * gnome_calendar_set_query: * @gcal: A calendar. @@ -246,6 +443,15 @@ gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp) priv = gcal->priv; + /* Set the query on the date navigator */ + + if (priv->sexp) + g_free (priv->sexp); + + priv->sexp = g_strdup (sexp); + + update_query (gcal); + /* Set the query on the main view */ switch (priv->current_view_type) { @@ -323,9 +529,10 @@ search_bar_category_changed_cb (CalSearchBar *cal_search, const char *category, gcal = GNOME_CALENDAR (data); priv = gcal->priv; - /* FIXME: Set the default category for the calendar views */ - - /* Set the default category for the task pad */ + 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); model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); calendar_model_set_default_category (model, category); @@ -452,12 +659,17 @@ gnome_calendar_init (GnomeCalendar *gcal) priv = g_new0 (GnomeCalendarPrivate, 1); gcal->priv = priv; + priv->cal_categories = NULL; + priv->tasks_categories = NULL; + priv->object_editor_hash = g_hash_table_new (g_str_hash, g_str_equal); priv->current_view_type = GNOME_CAL_DAY_VIEW; priv->range_selected = FALSE; setup_widgets (gcal); + priv->dn_query = NULL; + priv->sexp = g_strdup ("#t"); /* Match all */ priv->selection_start_time = time_day_begin_with_zone (time (NULL), priv->zone); @@ -467,6 +679,21 @@ gnome_calendar_init (GnomeCalendar *gcal) priv->view_menus = NULL; } +/* Frees a set of categories */ +static void +free_categories (GPtrArray *categories) +{ + int i; + + if (!categories) + return; + + for (i = 0; i < categories->len; i++) + g_free (categories->pdata[i]); + + g_ptr_array_free (categories, TRUE); +} + /* Used from g_hash_table_foreach(); frees an UID string */ static void destroy_editor_cb (gpointer key, gpointer value, gpointer data) @@ -490,11 +717,28 @@ gnome_calendar_destroy (GtkObject *object) gcal = GNOME_CALENDAR (object); priv = gcal->priv; + free_categories (priv->cal_categories); + priv->cal_categories = NULL; + + free_categories (priv->tasks_categories); + priv->tasks_categories = NULL; + /* Save the TaskPad layout. */ filename = g_strdup_printf ("%s/config/TaskPad", evolution_dir); e_calendar_table_save_state (E_CALENDAR_TABLE (priv->todo), filename); g_free (filename); + if (priv->dn_query) { + gtk_signal_disconnect_by_data (GTK_OBJECT (priv->dn_query), gcal); + gtk_object_unref (GTK_OBJECT (priv->dn_query)); + priv->dn_query = NULL; + } + + if (priv->sexp) { + g_free (priv->sexp); + priv->sexp = NULL; + } + if (priv->client) { gtk_object_unref (GTK_OBJECT (priv->client)); priv->client = NULL; @@ -672,10 +916,7 @@ gnome_calendar_dayjump (GnomeCalendar *gcal, time_t time) priv->zone); priv->selection_end_time = time_add_day_with_zone (priv->selection_start_time, 1, priv->zone); - if (priv->day_button) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->day_button), TRUE); - else - gnome_calendar_set_view (gcal, GNOME_CAL_DAY_VIEW, FALSE, TRUE); + gnome_calendar_set_view (gcal, GNOME_CAL_DAY_VIEW, FALSE, TRUE); } static void @@ -998,19 +1239,6 @@ gnome_calendar_set_pane_positions (GnomeCalendar *gcal) gtk_widget_set_usize (GTK_WIDGET (priv->date_navigator), -2, top_pane_height + 1); } -/* Loads the initial data into the calendar; this should be called right after - * the cal_opened signal from the client is invoked. - */ -static void -initial_load (GnomeCalendar *gcal) -{ - GnomeCalendarPrivate *priv; - - priv = gcal->priv; - - tag_calendar_by_client (priv->date_navigator, priv->client); -} - /* Displays an error to indicate that opening a calendar failed */ static void open_error (GnomeCalendar *gcal, const char *uri) @@ -1035,7 +1263,7 @@ method_error (GnomeCalendar *gcal, const char *uri) /* Callback from the calendar client when a calendar is loaded */ static void -cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) +client_cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) { GnomeCalendar *gcal; GnomeCalendarPrivate *priv; @@ -1046,7 +1274,7 @@ cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) switch (status) { case CAL_CLIENT_OPEN_SUCCESS: if (client == priv->client) - initial_load (gcal); + update_query (gcal); break; @@ -1069,30 +1297,118 @@ cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) } } -/* Callback from the calendar client when an object is updated */ +/* Duplicates an array of categories */ +static GPtrArray * +copy_categories (GPtrArray *categories) +{ + GPtrArray *c; + int i; + + c = g_ptr_array_new (); + g_ptr_array_set_size (c, categories->len); + + for (i = 0; i < categories->len; i++) + c->pdata[i] = g_strdup (categories->pdata[i]); + + return c; +} + +/* Adds the categories from an array to a hash table if they don't exist there + * already. + */ static void -obj_updated_cb (CalClient *client, const char *uid, gpointer data) +add_categories (GHashTable *categories, GPtrArray *c) { - GnomeCalendar *gcal; - GnomeCalendarPrivate *priv; + int i; - gcal = GNOME_CALENDAR (data); - priv = gcal->priv; + if (!c) + return; + + for (i = 0; i < c->len; i++) { + const char *cat; + const char *str; + + cat = c->pdata[i]; + str = g_hash_table_lookup (categories, cat); + + if (!str) + g_hash_table_insert (categories, (char *) cat, NULL); + } +} + +/* Used to append categories from a hash table to an array */ +struct append_category_closure { + GPtrArray *c; + + int i; +}; + +/* Appends a category from the hash table to the array */ +static void +append_category_cb (gpointer key, gpointer value, gpointer data) +{ + struct append_category_closure *closure; + const char *category; + + category = key; + closure = data; + + closure->c->pdata[closure->i] = g_strdup (category); + closure->i++; +} + +/* Creates the union of two sets of categories */ +static GPtrArray * +merge_categories (GPtrArray *a, GPtrArray *b) +{ + GHashTable *categories; + int n; + GPtrArray *c; + struct append_category_closure closure; + + categories = g_hash_table_new (g_str_hash, g_str_equal); + + add_categories (categories, a); + add_categories (categories, b); - tag_calendar_by_client (priv->date_navigator, priv->client); + n = g_hash_table_size (categories); + + c = g_ptr_array_new (); + g_ptr_array_set_size (c, n); + + closure.c = c; + closure.i = 0; + g_hash_table_foreach (categories, append_category_cb, &closure); + g_hash_table_destroy (categories); + + return c; } -/* Callback from the calendar client when an object is removed */ +/* Callback from the calendar client when the set of categories changes. We + * have to merge the categories of the calendar and tasks clients. + */ static void -obj_removed_cb (CalClient *client, const char *uid, gpointer data) +client_categories_changed_cb (CalClient *client, GPtrArray *categories, gpointer data) { GnomeCalendar *gcal; GnomeCalendarPrivate *priv; + GPtrArray *merged; gcal = GNOME_CALENDAR (data); priv = gcal->priv; - tag_calendar_by_client (priv->date_navigator, priv->client); + if (client == priv->client) { + free_categories (priv->cal_categories); + priv->cal_categories = copy_categories (categories); + } else if (client == priv->task_pad_client) { + free_categories (priv->tasks_categories); + priv->tasks_categories = copy_categories (categories); + } else + g_assert_not_reached (); + + merged = merge_categories (priv->cal_categories, priv->tasks_categories); + cal_search_bar_set_categories (CAL_SEARCH_BAR (priv->search_bar), merged); + free_categories (merged); } GtkWidget * @@ -1115,11 +1431,9 @@ gnome_calendar_construct (GnomeCalendar *gcal) return NULL; gtk_signal_connect (GTK_OBJECT (priv->client), "cal_opened", - GTK_SIGNAL_FUNC (cal_opened_cb), gcal); - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_updated", - GTK_SIGNAL_FUNC (obj_updated_cb), gcal); - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_removed", - GTK_SIGNAL_FUNC (obj_removed_cb), gcal); + GTK_SIGNAL_FUNC (client_cal_opened_cb), gcal); + gtk_signal_connect (GTK_OBJECT (priv->client), "categories_changed", + GTK_SIGNAL_FUNC (client_categories_changed_cb), gcal); e_day_view_set_cal_client (E_DAY_VIEW (priv->day_view), priv->client); @@ -1138,7 +1452,9 @@ gnome_calendar_construct (GnomeCalendar *gcal) return NULL; gtk_signal_connect (GTK_OBJECT (priv->task_pad_client), "cal_opened", - GTK_SIGNAL_FUNC (cal_opened_cb), gcal); + GTK_SIGNAL_FUNC (client_cal_opened_cb), gcal); + gtk_signal_connect (GTK_OBJECT (priv->task_pad_client), "categories_changed", + GTK_SIGNAL_FUNC (client_categories_changed_cb), gcal); model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); g_assert (model != NULL); @@ -1559,6 +1875,7 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal, struct icaltimetype itt; CalComponentDateTime dt; CalComponent *comp; + const char *category; g_return_if_fail (cal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (cal)); @@ -1568,9 +1885,13 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal, dt.value = &itt; dt.tzid = icaltimezone_get_tzid (priv->zone); + /* Component type */ + comp = cal_component_new (); cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); + /* DTSTART, DTEND */ + itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); if (all_day) itt.hour = itt.minute = itt.second = 0; @@ -1583,6 +1904,13 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal, } cal_component_set_dtend (comp, &dt); + /* 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, comp); @@ -1801,7 +2129,6 @@ gnome_calendar_on_date_navigator_selection_changed (ECalendarItem *calitem, gnome_calendar_set_view (gcal, GNOME_CAL_DAY_VIEW, TRUE, FALSE); } - gnome_calendar_update_view_buttons (gcal); focus_current_view (gcal); } @@ -1810,11 +2137,7 @@ static void gnome_calendar_on_date_navigator_date_range_changed (ECalendarItem *calitem, GnomeCalendar *gcal) { - GnomeCalendarPrivate *priv; - - priv = gcal->priv; - - tag_calendar_by_client (priv->date_navigator, priv->client); + update_query (gcal); } @@ -1918,72 +2241,6 @@ gnome_calendar_on_date_navigator_size_allocate (GtkWidget *widget, } void -gnome_calendar_set_view_buttons (GnomeCalendar *gcal, - GtkWidget *day_button, - GtkWidget *work_week_button, - GtkWidget *week_button, - GtkWidget *month_button) -{ - GnomeCalendarPrivate *priv; - - g_return_if_fail (gcal != NULL); - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - g_return_if_fail (day_button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (day_button)); - g_return_if_fail (work_week_button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (work_week_button)); - g_return_if_fail (week_button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (week_button)); - g_return_if_fail (month_button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (month_button)); - - priv = gcal->priv; - - priv->day_button = day_button; - priv->work_week_button = work_week_button; - priv->week_button = week_button; - priv->month_button = month_button; -} - -/* This makes the appropriate radio button in the toolbar active. It blocks the - * signals so that we can do a clean setup without affecting the views. - */ -void -gnome_calendar_update_view_buttons (GnomeCalendar *gcal) -{ - GnomeCalendarPrivate *priv; - GtkWidget *button; - - priv = gcal->priv; - - switch (priv->current_view_type) { - case GNOME_CAL_DAY_VIEW: - button = priv->day_button; - break; - - case GNOME_CAL_WORK_WEEK_VIEW: - button = priv->work_week_button; - break; - - case GNOME_CAL_WEEK_VIEW: - button = priv->week_button; - break; - - case GNOME_CAL_MONTH_VIEW: - button = priv->month_button; - break; - - default: - g_assert_not_reached (); - return; - } - - gtk_signal_handler_block_by_data (GTK_OBJECT (button), gcal); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (button), gcal); -} - -void gnome_calendar_cut_clipboard (GnomeCalendar *gcal) { GnomeCalendarPrivate *priv; diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h index 5409c6f55e..85f490aea0 100644 --- a/calendar/gui/gnome-cal.h +++ b/calendar/gui/gnome-cal.h @@ -126,17 +126,6 @@ void gnome_calendar_get_current_time_range (GnomeCalendar *gcal, void gnome_calendar_update_config_settings (GnomeCalendar *gcal, gboolean initializing); -void gnome_calendar_set_view_buttons (GnomeCalendar *gcal, - GtkWidget *day_button, - GtkWidget *work_week_button, - GtkWidget *week_button, - GtkWidget *month_button); - -/* This makes the appropriate radio button in the toolbar active. - It sets the ignore_view_button_clicks flag so the "clicked" signal handlers - just return without doing anything. */ -void gnome_calendar_update_view_buttons (GnomeCalendar *gcal); - /* Get the current timezone. */ icaltimezone *gnome_calendar_get_timezone (GnomeCalendar *gcal); diff --git a/calendar/gui/main.c b/calendar/gui/main.c index 8054bbb752..318fbfbfa3 100644 --- a/calendar/gui/main.c +++ b/calendar/gui/main.c @@ -61,6 +61,8 @@ init_bonobo (int argc, char **argv) int main (int argc, char **argv) { + free (malloc (8)); + bindtextdomain(PACKAGE, EVOLUTION_LOCALEDIR); textdomain(PACKAGE); diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c index a84f4e965e..de59407c20 100644 --- a/calendar/gui/tag-calendar.c +++ b/calendar/gui/tag-calendar.c @@ -42,7 +42,7 @@ struct calendar_tag_closure { * Returns FALSE if the calendar has no dates shown. */ static gboolean -prepare_tag (ECalendar *ecal, struct calendar_tag_closure *c) +prepare_tag (ECalendar *ecal, struct calendar_tag_closure *c, gboolean clear_first) { gint start_year, start_month, start_day; gint end_year, end_month, end_day; @@ -50,7 +50,8 @@ prepare_tag (ECalendar *ecal, struct calendar_tag_closure *c) struct icaltimetype end_tt = icaltime_null_time (); char *location; - e_calendar_item_clear_marks (ecal->calitem); + if (clear_first) + e_calendar_item_clear_marks (ecal->calitem); if (!e_calendar_item_get_date_range (ecal->calitem, &start_year, &start_month, @@ -127,7 +128,7 @@ tag_calendar_by_client (ECalendar *ecal, CalClient *client) if (cal_client_get_load_state (client) != CAL_CLIENT_LOAD_LOADED) return; - if (!prepare_tag (ecal, &c)) + if (!prepare_tag (ecal, &c, TRUE)) return; #if 0 @@ -142,12 +143,13 @@ tag_calendar_by_client (ECalendar *ecal, CalClient *client) * tag_calendar_by_comp: * @ecal: Calendar widget to tag. * @comp: A calendar component object. + * @clear_first: Whether the #ECalendar should be cleared of any marks first. * * Tags an #ECalendar widget with any occurrences of a specific calendar * component that occur within the calendar's current time range. **/ void -tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, CalClient *client) +tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, CalClient *client, gboolean clear_first) { struct calendar_tag_closure c; @@ -160,7 +162,7 @@ tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, CalClient *client) if (!GTK_WIDGET_VISIBLE (ecal)) return; - if (!prepare_tag (ecal, &c)) + if (!prepare_tag (ecal, &c, clear_first)) return; #if 0 diff --git a/calendar/gui/tag-calendar.h b/calendar/gui/tag-calendar.h index f9b11c1a5a..0ec7b5a148 100644 --- a/calendar/gui/tag-calendar.h +++ b/calendar/gui/tag-calendar.h @@ -28,6 +28,6 @@ void tag_calendar_by_client (ECalendar *ecal, CalClient *client); void tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, - CalClient *client); + CalClient *client, gboolean clear_first); #endif |