From 1dcf7c2a308edb953759b4abd5e0f8e1f94050dd Mon Sep 17 00:00:00 2001 From: JP Rosevear Date: Wed, 14 Jul 2004 02:20:55 +0000 Subject: Fixes #57287, 58748 2004-07-12 JP Rosevear Fixes #57287, 58748 * gui/tasks-component.c (source_added_cb): if the source was added in the main calendar, select it because the user caused this to happen by creating a task (create_component_view): listen for source_added signal on the tasks * gui/gnome-cal.c (view_selection_changed_cb): if the user created a task, make sure we are displaying the relevant event list (set_timezone): set the default zone of the default client (setup_widgets): listen for the user_created signal (gnome_calendar_destroy): clean up default client (client_cal_opened_cb): disconnect from the open signal (default_client_cal_opened_cb): set the default client on the models (open_ecal): make the callback function a param (gnome_calendar_add_source): include the default client when searching for an existing client (gnome_calendar_set_default_source): make the default client independent of the rest of the clients * gui/e-week-view.c (e_week_view_on_editing_stopped): emit user_created signal * gui/e-tasks.c (user_created_cb): if the user created a task, make sure we are displaying the relevant task list (set_timezone): set the timezone on the client (setup_widgets): listen for user_created signal (e_tasks_destroy): unref default client (default_client_cal_opened_cb): set the default on the model when it opens (open_ecal): open a task list (e_tasks_add_todo_source): include the default client when searching for an existing client (e_tasks_set_default_source): make the default client independent of the rest of the clients * gui/e-day-view.c (e_day_view_on_editing_stopped): emit user_created signal * gui/e-calendar-view.h: add signal proto * gui/e-calendar-view.c (e_calendar_view_class_init): add user_created signal * gui/e-calendar-table.h: add signal proto * gui/e-calendar-table.c (e_calendar_table_class_init): add user_created signal (row_appended_cb): if row is appended, emit user_created signal (e_calendar_table_init): listen for row_appended signal * gui/e-cal-model.h: add signal proto * gui/e-cal-model.c (e_cal_model_class_init): add row_appended signal (ecm_append_row): don't leak, emit row appended signal (e_cal_model_set_default_client): remove the existing default if it was only used as the default (update_e_cal_view_for_client): short circuit query create (add_new_client): look for an existing client and update its record if found, handle opening things here (e_cal_model_add_client): just call add_new_client (remove_client_objects): just remove a client's objects (remove_client): use above, handle removal of client if its default * gui/calendar-component.c (source_added_cb): if the source was added in the main calendar, select it because the user caused this to happen by creating an appointment (create_component_view): listen for source_added signal on the calendar svn path=/trunk/; revision=26644 --- calendar/gui/calendar-component.c | 14 ++++ calendar/gui/e-cal-model.c | 121 ++++++++++++++++++++------- calendar/gui/e-cal-model.h | 1 + calendar/gui/e-calendar-table.c | 23 ++++++ calendar/gui/e-calendar-table.h | 3 + calendar/gui/e-calendar-view.c | 29 +++++-- calendar/gui/e-calendar-view.h | 1 + calendar/gui/e-day-view.c | 2 + calendar/gui/e-tasks.c | 151 +++++++++++++++++++++++++++------- calendar/gui/e-week-view.c | 2 + calendar/gui/gnome-cal.c | 168 ++++++++++++++++++++++++++++++-------- calendar/gui/tasks-component.c | 8 ++ 12 files changed, 424 insertions(+), 99 deletions(-) (limited to 'calendar/gui') diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c index 6b84eac36f..51b6402eb4 100644 --- a/calendar/gui/calendar-component.c +++ b/calendar/gui/calendar-component.c @@ -443,6 +443,18 @@ primary_source_selection_changed_cb (ESourceSelector *selector, CalendarComponen update_uri_for_primary_selection (component_view); } +static void +source_added_cb (GnomeCalendar *calendar, ECalSourceType source_type, ESource *source, CalendarComponentView *component_view) +{ + switch (source_type) { + case E_CAL_SOURCE_TYPE_EVENT: + e_source_selector_select_source (E_SOURCE_SELECTOR (component_view->source_selector), source); + break; + default: + break; + } +} + static void source_removed_cb (GnomeCalendar *calendar, ECalSourceType source_type, ESource *source, CalendarComponentView *component_view) { @@ -1078,6 +1090,8 @@ create_component_view (CalendarComponent *calendar_component) component_view->calendar = (GnomeCalendar *) bonobo_control_get_widget (component_view->view_control); /* This signal is thrown if backends die - we update the selector */ + g_signal_connect (component_view->calendar, "source_added", + G_CALLBACK (source_added_cb), component_view); g_signal_connect (component_view->calendar, "source_removed", G_CALLBACK (source_removed_cb), component_view); diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c index c2d4fc57ad..ebba86d864 100644 --- a/calendar/gui/e-cal-model.c +++ b/calendar/gui/e-cal-model.c @@ -34,6 +34,8 @@ typedef struct { ECal *client; ECalView *query; + + gboolean do_query; } ECalModelClient; struct _ECalModelPrivate { @@ -88,9 +90,15 @@ static char *ecm_value_to_string (ETableModel *etm, int col, const void *value); static const char *ecm_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data); +static ECalModelClient *add_new_client (ECalModel *model, ECal *client, gboolean do_query); +static ECalModelClient *find_client_data (ECalModel *model, ECal *client); +static void remove_client_objects (ECalModel *model, ECalModelClient *client_data); +static void remove_client (ECalModel *model, ECalModelClient *client_data); + /* Signal IDs */ enum { TIME_RANGE_CHANGED, + ROW_APPENDED, LAST_SIGNAL }; @@ -135,6 +143,15 @@ e_cal_model_class_init (ECalModelClass *klass) NULL, NULL, e_calendar_marshal_VOID__LONG_LONG, G_TYPE_NONE, 2, G_TYPE_LONG, G_TYPE_LONG); + + signals[ROW_APPENDED] = + g_signal_new ("row_appended", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ECalModelClass, row_appended), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -758,9 +775,13 @@ ecm_append_row (ETableModel *etm, ETableModel *source, int row) g_warning (G_STRLOC ": Could not create the object!"); /* FIXME: show error dialog */ + icalcomponent_free (comp_data.icalcomp); + return; } icalcomponent_free (comp_data.icalcomp); + + g_signal_emit (G_OBJECT (model), signals[ROW_APPENDED], 0); } static void * @@ -1097,6 +1118,8 @@ e_cal_model_get_default_client (ECalModel *model) priv = model->priv; + /* FIXME Should we force the client to be open? */ + /* we always return a valid ECal, since we rely on it in many places */ if (priv->default_client) return priv->default_client; @@ -1113,6 +1136,7 @@ void e_cal_model_set_default_client (ECalModel *model, ECal *client) { ECalModelPrivate *priv; + ECalModelClient *client_data; g_return_if_fail (model != NULL); g_return_if_fail (E_IS_CAL_MODEL (model)); @@ -1121,11 +1145,21 @@ e_cal_model_set_default_client (ECalModel *model, ECal *client) priv = model->priv; + if (priv->default_client) { + ECalModelClient *client_data; + + client_data = find_client_data (model, priv->default_client); + g_assert (client_data); + + if (!client_data->do_query) + remove_client (model, client_data); + } + /* Make sure its in the model */ - e_cal_model_add_client (model, client); + client_data = add_new_client (model, client, FALSE); /* Store the default client */ - priv->default_client = e_cal_model_get_client_for_uri (model, e_cal_get_uri (client)); + priv->default_client = client_data->client; } /** @@ -1366,6 +1400,10 @@ update_e_cal_view_for_client (ECalModel *model, ECalModelClient *client_data) /* prepare the query */ g_assert (priv->full_sexp != NULL); + /* Don't create the new query if we won't use it */ + if (!client_data->do_query) + return; + if (!e_cal_get_query (client_data->client, priv->full_sexp, &client_data->query, NULL)) { g_warning (G_STRLOC ": Unable to get query"); @@ -1412,24 +1450,46 @@ cal_opened_cb (ECal *client, ECalendarStatus status, gpointer user_data) update_e_cal_view_for_client (model, client_data); } + static ECalModelClient * -add_new_client (ECalModel *model, ECal *client) +add_new_client (ECalModel *model, ECal *client, gboolean do_query) { ECalModelPrivate *priv; ECalModelClient *client_data; - + ECal *existing_client; + priv = model->priv; + /* Look for an existing client with the same URI */ + existing_client = e_cal_model_get_client_for_uri (model, e_cal_get_uri (client)); + if (existing_client) { + client_data = find_client_data (model, client); + g_assert (client_data); + + if (!client_data->do_query) + client_data->do_query = do_query; + + goto load; + } + client_data = g_new0 (ECalModelClient, 1); - client_data->client = client; + client_data->client = g_object_ref (client); client_data->query = NULL; - g_object_ref (client_data->client); + client_data->do_query = do_query; priv->clients = g_list_append (priv->clients, client_data); g_signal_connect (G_OBJECT (client_data->client), "backend_died", G_CALLBACK (backend_died_cb), model); + load: + if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED) { + update_e_cal_view_for_client (model, client_data); + } else { + g_signal_connect (client, "cal_opened", G_CALLBACK (cal_opened_cb), model); + e_cal_open_async (client, TRUE); + } + return client_data; } @@ -1447,29 +1507,14 @@ e_cal_model_add_client (ECalModel *model, ECal *client) priv = model->priv; - if (e_cal_model_get_client_for_uri (model, e_cal_get_uri (client))) - return; - - client_data = add_new_client (model, client); - if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED) { - update_e_cal_view_for_client (model, client_data); - } else { - g_signal_connect (client, "cal_opened", G_CALLBACK (cal_opened_cb), model); - e_cal_open_async (client, TRUE); - } + client_data = add_new_client (model, client, TRUE); } static void -remove_client (ECalModel *model, ECalModelClient *client_data) +remove_client_objects (ECalModel *model, ECalModelClient *client_data) { - gint i; - - g_signal_handlers_disconnect_matched (client_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); - if (client_data->query) - g_signal_handlers_disconnect_matched (client_data->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); - - model->priv->clients = g_list_remove (model->priv->clients, client_data); - + int i; + /* remove all objects belonging to this client */ for (i = model->priv->objects->len; i > 0; i--) { ECalModelComponent *comp_data = (ECalModelComponent *) g_ptr_array_index (model->priv->objects, i - 1); @@ -1485,11 +1530,29 @@ remove_client (ECalModel *model, ECalModelClient *client_data) e_table_model_row_deleted (E_TABLE_MODEL (model), i - 1); } } +} + +static void +remove_client (ECalModel *model, ECalModelClient *client_data) +{ + /* FIXME We might not want to disconnect the open signal for the default client */ + g_signal_handlers_disconnect_matched (client_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); + if (client_data->query) + g_signal_handlers_disconnect_matched (client_data->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); + + remove_client_objects (model, client_data); + + /* If this is the default client and we were querying (so it + * was also a source), keep it around but don't query it */ + if (model->priv->default_client == client_data->client && client_data->do_query) { + client_data->do_query = FALSE; + + return; + } + + /* Remove the client from the list */ + model->priv->clients = g_list_remove (model->priv->clients, client_data); - /* If this was the default client, unset it */ - if (model->priv->default_client == client_data->client) - model->priv->default_client = NULL; - /* free all remaining memory */ g_object_unref (client_data->client); if (client_data->query) diff --git a/calendar/gui/e-cal-model.h b/calendar/gui/e-cal-model.h index aef2e3d539..846d7b4acd 100644 --- a/calendar/gui/e-cal-model.h +++ b/calendar/gui/e-cal-model.h @@ -84,6 +84,7 @@ typedef struct { /* Signals */ void (* time_range_changed) (ECalModel *model, time_t start, time_t end); + void (* row_appended) (ECalModel *model); } ECalModelClass; GType e_cal_model_get_type (void); diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index c3044195fe..a0688fa8b5 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -104,6 +104,13 @@ static void mark_row_complete_cb (int model_row, gpointer data); static ECalModelComponent *get_selected_comp (ECalendarTable *cal_table); static void open_task (ECalendarTable *cal_table, ECalModelComponent *comp_data, gboolean assign); +/* Signal IDs */ +enum { + USER_CREATED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; /* The icons to represent the task. */ #define E_CALENDAR_MODEL_NUM_ICONS 4 @@ -131,6 +138,15 @@ e_calendar_table_class_init (ECalendarTableClass *class) /* Method override */ object_class->destroy = e_calendar_table_destroy; + signals[USER_CREATED] = + g_signal_new ("user_created", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ECalendarTableClass, user_created), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /* clipboard atom */ if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); @@ -278,6 +294,12 @@ priority_compare_cb (gconstpointer a, gconstpointer b) return 0; } +static void +row_appended_cb (ECalModel *model, ECalendarTable *cal_table) +{ + g_signal_emit (cal_table, signals[USER_CREATED], 0); +} + static void e_calendar_table_init (ECalendarTable *cal_table) { @@ -292,6 +314,7 @@ e_calendar_table_init (ECalendarTable *cal_table) /* Create the model */ cal_table->model = (ECalModel *) e_cal_model_tasks_new (); + g_signal_connect (cal_table->model, "row_appended", G_CALLBACK (row_appended_cb), cal_table); /* Create the header columns */ diff --git a/calendar/gui/e-calendar-table.h b/calendar/gui/e-calendar-table.h index c69c95d56e..fc7afe5d4c 100644 --- a/calendar/gui/e-calendar-table.h +++ b/calendar/gui/e-calendar-table.h @@ -68,6 +68,9 @@ struct _ECalendarTable { struct _ECalendarTableClass { GtkTableClass parent_class; + + /* Notification signals */ + void (* user_created) (ECalendarTable *cal_table); }; diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 2150ca0993..00cce026b4 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -103,6 +103,7 @@ enum { TIMEZONE_CHANGED, EVENT_CHANGED, EVENT_ADDED, + USER_CREATED, OPEN_EVENT, LAST_SIGNAL }; @@ -166,6 +167,7 @@ e_calendar_view_class_init (ECalendarViewClass *klass) klass->selected_time_changed = NULL; klass->event_changed = NULL; klass->event_added = NULL; + klass->user_created = NULL; klass->get_selected_events = NULL; klass->get_selected_time_range = NULL; @@ -214,15 +216,6 @@ e_calendar_view_class_init (ECalendarViewClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); - e_calendar_view_signals[OPEN_EVENT] = - g_signal_new ("open_event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (ECalendarViewClass, open_event), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - e_calendar_view_signals[EVENT_ADDED] = g_signal_new ("event_added", G_TYPE_FROM_CLASS (object_class), @@ -233,6 +226,24 @@ e_calendar_view_class_init (ECalendarViewClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); + e_calendar_view_signals[USER_CREATED] = + g_signal_new ("user_created", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ECalendarViewClass, user_created), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + e_calendar_view_signals[OPEN_EVENT] = + g_signal_new ("open_event", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ECalendarViewClass, open_event), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /* clipboard atom */ if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); diff --git a/calendar/gui/e-calendar-view.h b/calendar/gui/e-calendar-view.h index 8ee125e1d2..724833c1a4 100644 --- a/calendar/gui/e-calendar-view.h +++ b/calendar/gui/e-calendar-view.h @@ -87,6 +87,7 @@ struct _ECalendarViewClass { void (* timezone_changed) (ECalendarView *cal_view, icaltimezone *old_zone, icaltimezone *new_zone); void (* event_changed) (ECalendarView *day_view, ECalendarViewEvent *event); void (* event_added) (ECalendarView *day_view, ECalendarViewEvent *event); + void (* user_created) (ECalendarView *cal_view); /* Virtual methods */ GList * (* get_selected_events) (ECalendarView *cal_view); /* a GList of ECalendarViewEvent's */ diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 30232e7279..0be9d6f4ca 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -6049,6 +6049,8 @@ e_day_view_on_editing_stopped (EDayView *day_view, if (!on_server) { if (!e_cal_create_object (client, icalcomp, NULL, NULL)) g_message (G_STRLOC ": Could not create the object!"); + else + g_signal_emit_by_name (day_view, "user_created"); } else { CalObjModType mod = CALOBJ_MOD_ALL; GtkWindow *toplevel; diff --git a/calendar/gui/e-tasks.c b/calendar/gui/e-tasks.c index 9f83428228..a935f09863 100644 --- a/calendar/gui/e-tasks.c +++ b/calendar/gui/e-tasks.c @@ -61,6 +61,7 @@ struct _ETasksPrivate { /* The task lists for display */ GHashTable *clients; GList *clients_list; + ECal *default_client; ECalView *query; @@ -88,7 +89,6 @@ struct _ETasksPrivate { GList *notifications; }; - static void e_tasks_class_init (ETasksClass *class); static void e_tasks_init (ETasks *tasks); static void setup_widgets (ETasks *tasks); @@ -178,6 +178,21 @@ table_selection_change_cb (ETable *etable, gpointer data) n_selected); } +static void +user_created_cb (GtkWidget *view, ETasks *tasks) +{ + ETasksPrivate *priv; + ECal *ecal; + ECalModel *model; + + priv = tasks->priv; + + model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); + ecal = e_cal_model_get_default_client (model); + + e_tasks_add_todo_source (tasks, e_cal_get_source (ecal)); +} + /* Callback used when the sexp in the search bar changes */ static void search_bar_sexp_changed_cb (CalSearchBar *cal_search, const char *sexp, gpointer data) @@ -237,6 +252,10 @@ set_timezone (ETasks *tasks) e_cal_set_default_timezone (client, zone, NULL); } + if (priv->default_client && e_cal_get_load_state (priv->default_client) == E_CAL_LOAD_LOADED) + /* FIXME Error checking */ + e_cal_set_default_timezone (priv->default_client, zone, NULL); + if (priv->preview) e_cal_component_preview_set_default_timezone (E_CAL_COMPONENT_PREVIEW (priv->preview), zone); } @@ -477,6 +496,8 @@ setup_widgets (ETasks *tasks) priv->tasks_view = e_calendar_table_new (); priv->tasks_view_config = e_calendar_table_config_new (E_CALENDAR_TABLE (priv->tasks_view)); + g_signal_connect (priv->tasks_view, "user_created", G_CALLBACK (user_created_cb), tasks); + etable = e_table_scrolled_get_table ( E_TABLE_SCROLLED (E_CALENDAR_TABLE (priv->tasks_view)->etable)); e_table_set_state (etable, E_TASKS_TABLE_DEFAULT_STATE); @@ -492,6 +513,7 @@ setup_widgets (ETasks *tasks) G_CALLBACK(table_drag_data_get), tasks); g_signal_connect (etable, "table_drag_data_delete", G_CALLBACK(table_drag_data_delete), tasks); + /* e_table_drag_dest_set (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), 0, list_drag_types, num_list_drag_types, GDK_ACTION_LINK); @@ -651,6 +673,10 @@ e_tasks_destroy (GtkObject *object) g_hash_table_destroy (priv->clients); g_list_free (priv->clients_list); + if (priv->default_client) + g_object_unref (priv->default_client); + priv->default_client = NULL; + if (priv->current_uid) { g_free (priv->current_uid); priv->current_uid = NULL; @@ -761,6 +787,8 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, ETasks *tasks) switch (status) { case E_CALENDAR_STATUS_OK : + g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, client_cal_opened_cb, NULL); + set_status_message (tasks, _("Loading tasks")); model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); e_cal_model_add_client (model, ecal); @@ -789,6 +817,63 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, ETasks *tasks) } } +static void +default_client_cal_opened_cb (ECal *ecal, ECalendarStatus status, ETasks *tasks) +{ + ECalModel *model; + ESource *source; + ETasksPrivate *priv; + + priv = tasks->priv; + + source = e_cal_get_source (ecal); + + switch (status) { + case E_CALENDAR_STATUS_OK : + g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, default_client_cal_opened_cb, NULL); + model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); + + set_timezone (tasks); + e_cal_model_set_default_client (model, ecal); + break; + default : + /* Make sure the source doesn't disappear on us */ + g_object_ref (source); + + priv->clients_list = g_list_remove (priv->clients_list, ecal); + g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, tasks); + + /* Do this last because it unrefs the client */ + g_hash_table_remove (priv->clients, e_cal_get_uri (ecal)); + + gtk_signal_emit (GTK_OBJECT (tasks), e_tasks_signals[SOURCE_REMOVED], source); + + set_status_message (tasks, NULL); + g_object_unref (ecal); + g_object_unref (source); + + break; + } +} + +typedef void (*open_func) (ECal *, ECalendarStatus, ETasks *); + +static gboolean +open_ecal (ETasks *tasks, ECal *cal, gboolean only_if_exists, open_func of) +{ + ETasksPrivate *priv; + + priv = tasks->priv; + + set_status_message (tasks, _("Opening tasks at %s"), e_cal_get_uri (cal)); + + g_signal_connect (G_OBJECT (cal), "cal_opened", G_CALLBACK (of), tasks); + e_cal_open_async (cal, only_if_exists); + + return TRUE; +} + void e_tasks_open_task (ETasks *tasks) { @@ -833,8 +918,6 @@ e_tasks_add_todo_source (ETasks *tasks, ESource *source) { ETasksPrivate *priv; ECal *client; - char *str_uri; - GError *error = NULL; const char *uid; g_return_val_if_fail (tasks != NULL, FALSE); @@ -845,32 +928,40 @@ e_tasks_add_todo_source (ETasks *tasks, ESource *source) uid = e_source_peek_uid (source); client = g_hash_table_lookup (priv->clients, uid); - if (client) - return TRUE; - + if (client) { + /* We already have it */ - /* FIXME Loading should be async */ - /* FIXME With no event handling here the status message never actually changes */ - str_uri = e_source_get_uri (source); - set_status_message (tasks, _("Opening tasks at %s"), str_uri); + return TRUE; + } else { + ESource *default_source; + + if (priv->default_client) { + default_source = e_cal_get_source (priv->default_client); + + /* We don't have it but the default client is it */ + if (!strcmp (e_source_peek_uid (default_source), uid)) + client = g_object_ref (priv->default_client); + } - client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO); - if (!client) { - g_free (str_uri); - return FALSE; + /* Create a new one */ + if (!client) { + client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO); + if (!client) + return FALSE; + } } - g_hash_table_insert (priv->clients, g_strdup (uid) , client); - priv->clients_list = g_list_prepend (priv->clients_list, client); - g_signal_connect (G_OBJECT (client), "backend_error", G_CALLBACK (backend_error_cb), tasks); g_signal_connect (G_OBJECT (client), "categories_changed", G_CALLBACK (client_categories_changed_cb), tasks); g_signal_connect (G_OBJECT (client), "backend_died", G_CALLBACK (backend_died_cb), tasks); - g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (client_cal_opened_cb), tasks); + + /* add the client to internal structure */ + g_hash_table_insert (priv->clients, g_strdup (uid) , client); + priv->clients_list = g_list_prepend (priv->clients_list, client); gtk_signal_emit (GTK_OBJECT (tasks), e_tasks_signals[SOURCE_ADDED], source); - e_cal_open_async (client, FALSE); + open_ecal (tasks, client, FALSE, client_cal_opened_cb); return TRUE; } @@ -915,8 +1006,6 @@ e_tasks_set_default_source (ETasks *tasks, ESource *source) { ETasksPrivate *priv; ECal *ecal; - ECalModel *model; - char *str_uri; g_return_val_if_fail (tasks != NULL, FALSE); g_return_val_if_fail (E_IS_TASKS (tasks), FALSE); @@ -924,14 +1013,20 @@ e_tasks_set_default_source (ETasks *tasks, ESource *source) priv = tasks->priv; - str_uri = e_source_get_uri (source); - model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); - ecal = e_cal_model_get_client_for_uri (model, str_uri); - g_free (str_uri); - if (!ecal) - return FALSE; + ecal = g_hash_table_lookup (priv->clients, e_source_peek_uid (source)); + + if (priv->default_client) + g_object_unref (priv->default_client); + + if (ecal) { + priv->default_client = g_object_ref (ecal); + } else { + priv->default_client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO); + if (!priv->default_client) + return FALSE; + } - e_cal_model_set_default_client (model, ecal); + open_ecal (tasks, priv->default_client, FALSE, default_client_cal_opened_cb); return TRUE; } diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index 7affe611b6..6efaac9529 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -3333,6 +3333,8 @@ e_week_view_on_editing_stopped (EWeekView *week_view, if (!on_server) { if (!e_cal_create_object (client, icalcomp, NULL, NULL)) g_message (G_STRLOC ": Could not create the object!"); + else + g_signal_emit_by_name (week_view, "user_created"); } else { CalObjModType mod = CALOBJ_MOD_ALL; GtkWindow *toplevel; diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 034c0be1bd..cbddfcbf4c 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -91,6 +91,7 @@ struct _GnomeCalendarPrivate { GHashTable *clients[E_CAL_SOURCE_TYPE_LAST]; GList *clients_list[E_CAL_SOURCE_TYPE_LAST]; + ECal *default_client; /* Categories from the calendar clients */ /* FIXME are we getting all the categories? */ @@ -845,6 +846,21 @@ view_selection_changed_cb (GtkWidget *view, GnomeCalendar *gcal) gnome_calendar_signals[CALENDAR_SELECTION_CHANGED]); } +static void +user_created_cb (GtkWidget *view, GnomeCalendar *gcal) +{ + GnomeCalendarPrivate *priv; + ECal *ecal; + ECalModel *model; + + priv = gcal->priv; + + model = e_calendar_view_get_model (priv->views[priv->current_view_type]); + ecal = e_cal_model_get_default_client (model); + + gnome_calendar_add_source (gcal, E_CAL_SOURCE_TYPE_EVENT, e_cal_get_source (ecal)); +} + /* Callback used when the taskpad receives a focus event. We emit the * corresponding signal so that parents can change the menus as appropriate. @@ -967,6 +983,10 @@ set_timezone (GnomeCalendar *calendar) e_cal_set_default_timezone (client, priv->zone, NULL); } } + + if (priv->default_client && e_cal_get_load_state (priv->default_client) == E_CAL_LOAD_LOADED) + /* FIXME Error checking */ + e_cal_set_default_timezone (priv->default_client, priv->zone, NULL); } static void @@ -1268,6 +1288,9 @@ setup_widgets (GnomeCalendar *gcal) gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), GTK_WIDGET (priv->views[i]), gtk_label_new ("")); + g_signal_connect (priv->views[i], "user_created", + G_CALLBACK (user_created_cb), gcal); + gtk_widget_show (GTK_WIDGET (priv->views[i])); } @@ -1351,6 +1374,13 @@ gnome_calendar_destroy (GtkObject *object) priv->clients[i] = NULL; priv->clients_list[i] = NULL; } + + if (priv->default_client) { + g_signal_handlers_disconnect_matched (priv->default_client, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, gcal); + g_object_unref (priv->default_client); + } + priv->default_client = NULL; for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) { free_categories (priv->categories[i]); @@ -1988,9 +2018,6 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal) g_object_ref (source); priv->clients_list[source_type] = g_list_remove (priv->clients_list[source_type], ecal); - g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - g_hash_table_remove (priv->clients[source_type], e_source_peek_uid (source)); gtk_signal_emit (GTK_OBJECT (gcal), gnome_calendar_signals[SOURCE_REMOVED], source_type, source); @@ -2000,6 +2027,8 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal) return; } + g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, client_cal_opened_cb, NULL); + e_cal_set_default_timezone (ecal, priv->zone, NULL); switch (source_type) { @@ -2038,8 +2067,69 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal) } } +static void +default_client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal) +{ + GnomeCalendarPrivate *priv; + ECalSourceType source_type; + ESource *source; + int i; + + priv = gcal->priv; + + source_type = e_cal_get_source_type (ecal); + source = e_cal_get_source (ecal); + + if (source_type == E_CAL_SOURCE_TYPE_EVENT) + e_calendar_view_set_status_message (priv->views[priv->current_view_type], NULL); + else + e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), NULL); + + if (status != E_CALENDAR_STATUS_OK) { + /* Make sure the source doesn't disappear on us */ + g_object_ref (source); + + /* FIXME should we do this to prevent multiple error dialogs? */ + priv->clients_list[source_type] = g_list_remove (priv->clients_list[source_type], ecal); + g_hash_table_remove (priv->clients[source_type], e_source_peek_uid (source)); + + /* FIXME Is there a better way to handle this? */ + g_object_unref (priv->default_client); + priv->default_client = NULL; + + gtk_signal_emit (GTK_OBJECT (gcal), gnome_calendar_signals[SOURCE_REMOVED], source_type, source); + + g_object_unref (source); + + return; + } + + g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, default_client_cal_opened_cb, NULL); + + e_cal_set_default_timezone (ecal, priv->zone, NULL); + + switch (source_type) { + case E_CAL_SOURCE_TYPE_EVENT: + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + e_cal_model_set_default_client ( + e_calendar_view_get_model (E_CALENDAR_VIEW (priv->views[i])), + ecal); + } + break; + + case E_CAL_SOURCE_TYPE_TODO: + e_cal_model_set_default_client (e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)), ecal); + break; + + default: + return; + } +} + +typedef void (*open_func) (ECal *, ECalendarStatus, GnomeCalendar *); + static gboolean -open_ecal (GnomeCalendar *gcal, ECal *cal, gboolean only_if_exists) +open_ecal (GnomeCalendar *gcal, ECal *cal, gboolean only_if_exists, open_func of) { GnomeCalendarPrivate *priv; char *msg; @@ -2061,7 +2151,7 @@ open_ecal (GnomeCalendar *gcal, ECal *cal, gboolean only_if_exists) g_free (msg); - g_signal_connect (G_OBJECT (cal), "cal_opened", G_CALLBACK (client_cal_opened_cb), gcal); + g_signal_connect (G_OBJECT (cal), "cal_opened", G_CALLBACK (of), gcal); e_cal_open_async (cal, only_if_exists); return TRUE; @@ -2177,10 +2267,12 @@ backend_died_cb (ECal *ecal, gpointer data) gcal = GNOME_CALENDAR (data); priv = gcal->priv; + /* FIXME What about default sources? */ + /* Make sure the source doesn't go away on us since we use it below */ source_type = e_cal_get_source_type (ecal); - source = g_object_ref (e_cal_get_source (ecal)); - + source = g_object_ref (e_cal_get_source (ecal)); + priv->clients_list[source_type] = g_list_remove (priv->clients_list[source_type], ecal); g_hash_table_remove (priv->clients[source_type], e_source_peek_uid (source)); @@ -2329,12 +2421,29 @@ gnome_calendar_add_source (GnomeCalendar *gcal, ECalSourceType source_type, ESou priv = gcal->priv; client = g_hash_table_lookup (priv->clients[source_type], e_source_peek_uid (source)); - if (client) + if (client) { + /* We already have it */ + return TRUE; - - client = auth_new_cal_from_source (source, source_type); - if (!client) - return FALSE; + } else { + ESource *default_source; + + if (priv->default_client) { + default_source = e_cal_get_source (priv->default_client); + + g_message ("Check if default client matches (%s %s)", e_source_peek_uid (default_source), e_source_peek_uid (source)); + /* We don't have it but the default client is it */ + if (!strcmp (e_source_peek_uid (default_source), e_source_peek_uid (source))) + client = g_object_ref (priv->default_client); + } + + /* Create a new one */ + if (!client) { + client = auth_new_cal_from_source (source, source_type); + if (!client) + return FALSE; + } + } 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); @@ -2346,7 +2455,7 @@ gnome_calendar_add_source (GnomeCalendar *gcal, ECalSourceType source_type, ESou gtk_signal_emit (GTK_OBJECT (gcal), gnome_calendar_signals[SOURCE_ADDED], source_type, source); - open_ecal (gcal, client, FALSE); + open_ecal (gcal, client, FALSE, client_cal_opened_cb); return TRUE; } @@ -2456,8 +2565,7 @@ gnome_calendar_set_default_source (GnomeCalendar *gcal, ECalSourceType source_ty { GnomeCalendarPrivate *priv; ECal *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 (E_IS_SOURCE (source), FALSE); @@ -2465,26 +2573,20 @@ gnome_calendar_set_default_source (GnomeCalendar *gcal, ECalSourceType source_ty priv = gcal->priv; client = g_hash_table_lookup (priv->clients[source_type], e_source_peek_uid (source)); - if (!client) - return FALSE; - - switch (source_type) { - case E_CAL_SOURCE_TYPE_EVENT: - for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { - e_cal_model_set_default_client ( - e_calendar_view_get_model (E_CALENDAR_VIEW (priv->views[i])), - client); - } - break; - case E_CAL_SOURCE_TYPE_TODO: - e_cal_model_set_default_client (e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)), client); - break; - - default: - return FALSE; + if (priv->default_client) + g_object_unref (priv->default_client); + + if (client) { + priv->default_client = g_object_ref (client); + } else { + priv->default_client = auth_new_cal_from_source (source, source_type); + if (!priv->default_client) + return FALSE; } - + + open_ecal (gcal, priv->default_client, FALSE, default_client_cal_opened_cb); + return TRUE; } diff --git a/calendar/gui/tasks-component.c b/calendar/gui/tasks-component.c index 1fa67ed6b7..dc87020592 100644 --- a/calendar/gui/tasks-component.c +++ b/calendar/gui/tasks-component.c @@ -390,6 +390,12 @@ primary_source_selection_changed_cb (ESourceSelector *selector, TasksComponentVi update_uri_for_primary_selection (component_view); } +static void +source_added_cb (ETasks *tasks, ESource *source, TasksComponentView *component_view) +{ + e_source_selector_select_source (E_SOURCE_SELECTOR (component_view->source_selector), source); +} + static void source_removed_cb (ETasks *tasks, ESource *source, TasksComponentView *component_view) { @@ -894,6 +900,8 @@ create_component_view (TasksComponent *tasks_component) component_view->model = E_TABLE_MODEL (e_calendar_table_get_model (e_tasks_get_calendar_table (component_view->tasks))); /* This signal is thrown if backends die - we update the selector */ + g_signal_connect (component_view->tasks, "source_added", + G_CALLBACK (source_added_cb), component_view); g_signal_connect (component_view->tasks, "source_removed", G_CALLBACK (source_removed_cb), component_view); -- cgit v1.2.3