diff options
author | Milan Crha <mcrha@redhat.com> | 2021-05-26 22:11:31 +0200 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2021-05-26 22:12:14 +0200 |
commit | 686b9264f1df86eda95ecc76d0bd2167e123be66 (patch) | |
tree | 56960a4767d5d28047b63cb8b61f0e9b69e9dc2a | |
parent | 498c0f8f1f7eaa9422e015e43e4d9c0f3dcd26e2 (diff) | |
download | evolution-686b9264f1df86eda95ecc76d0bd2167e123be66.tar.gz |
I#1507 - Contacts: Preserve selection after search change
Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/1507
-rw-r--r-- | src/addressbook/gui/widgets/e-addressbook-model.c | 21 | ||||
-rw-r--r-- | src/addressbook/gui/widgets/e-addressbook-view.c | 110 |
2 files changed, 125 insertions, 6 deletions
diff --git a/src/addressbook/gui/widgets/e-addressbook-model.c b/src/addressbook/gui/widgets/e-addressbook-model.c index 3b83cd16b2..49d0d33b49 100644 --- a/src/addressbook/gui/widgets/e-addressbook-model.c +++ b/src/addressbook/gui/widgets/e-addressbook-model.c @@ -68,6 +68,7 @@ enum { enum { WRITABLE_STATUS, STATUS_MESSAGE, + BEFORE_SEARCH, SEARCH_STARTED, SEARCH_RESULT, FOLDER_BAR_MESSAGE, @@ -372,6 +373,8 @@ client_view_ready_cb (GObject *source_object, return; } + g_signal_emit (model, signals[BEFORE_SEARCH], 0); + remove_book_view (model); free_data (model); @@ -681,6 +684,15 @@ e_addressbook_model_class_init (EAddressbookModelClass *class) G_TYPE_STRING, G_TYPE_INT); + signals[BEFORE_SEARCH] = g_signal_new ( + "before-search", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + /* G_STRUCT_OFFSET (EAddressbookModelClass, before_search) */ 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SEARCH_STARTED] = g_signal_new ( "search_started", G_OBJECT_CLASS_TYPE (object_class), @@ -851,6 +863,7 @@ e_addressbook_model_contact_at (EAddressbookModel *model, gint index) { g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); + g_return_val_if_fail (index >= 0 && (guint) index < model->priv->contacts->len, NULL); return model->priv->contacts->pdata[index]; } @@ -862,11 +875,6 @@ e_addressbook_model_find (EAddressbookModel *model, GPtrArray *array; gint ii; - /* XXX This searches for a particular EContact instance, - * as opposed to an equivalent but possibly different - * EContact instance. Might have to revise this in - * the future. */ - g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), -1); g_return_val_if_fail (E_IS_CONTACT (contact), -1); @@ -874,7 +882,8 @@ e_addressbook_model_find (EAddressbookModel *model, for (ii = 0; ii < array->len; ii++) { EContact *candidate = array->pdata[ii]; - if (contact == candidate) + if (contact == candidate || + g_strcmp0 (e_contact_get_const (contact, E_CONTACT_UID), e_contact_get_const (candidate, E_CONTACT_UID)) == 0) return ii; } diff --git a/src/addressbook/gui/widgets/e-addressbook-view.c b/src/addressbook/gui/widgets/e-addressbook-view.c index 0b6d8827d6..b4c4ff199b 100644 --- a/src/addressbook/gui/widgets/e-addressbook-view.c +++ b/src/addressbook/gui/widgets/e-addressbook-view.c @@ -78,6 +78,11 @@ struct _EAddressbookViewPrivate { GtkTargetList *copy_target_list; GtkTargetList *paste_target_list; + + GSList *previous_selection; /* EContact * */ + EContact *cursor_contact; + gint cursor_col; + gboolean awaiting_search_start; }; enum { @@ -145,6 +150,14 @@ addressbook_view_emit_popup_event (EAddressbookView *view, static void addressbook_view_emit_selection_change (EAddressbookView *view) { + if (!view->priv->awaiting_search_start && + e_selection_model_selected_count (e_addressbook_view_get_selection_model (view)) > 0) { + g_slist_free_full (view->priv->previous_selection, g_object_unref); + view->priv->previous_selection = NULL; + + g_clear_object (&view->priv->cursor_contact); + } + g_signal_emit (view, signals[SELECTION_CHANGE], 0); } @@ -429,6 +442,89 @@ addressbook_view_display_view_cb (GalViewInstance *view_instance, command_state_change (view); } +static void +addressbook_view_model_before_search_cb (EAddressbookModel *model, + gpointer user_data) +{ + EAddressbookView *view = user_data; + ESelectionModel *selection_model; + gint cursor_row; + + selection_model = e_addressbook_view_get_selection_model (view); + + g_slist_free_full (view->priv->previous_selection, g_object_unref); + view->priv->previous_selection = e_addressbook_view_get_selected (view); + + g_clear_object (&view->priv->cursor_contact); + + cursor_row = e_selection_model_cursor_row (selection_model); + + if (cursor_row >= 0 && cursor_row < e_addressbook_model_contact_count (model)) + view->priv->cursor_contact = g_object_ref (e_addressbook_model_contact_at (model, cursor_row)); + + view->priv->cursor_col = e_selection_model_cursor_col (selection_model); + view->priv->awaiting_search_start = TRUE; +} + +static void +addressbook_view_model_search_started_cb (EAddressbookModel *model, + gpointer user_data) +{ + EAddressbookView *view = user_data; + + view->priv->awaiting_search_start = FALSE; +} + +static void +addressbook_view_model_search_result_cb (EAddressbookModel *model, + const GError *error, + gpointer user_data) +{ + EAddressbookView *view = user_data; + ESelectionModel *selection_model; + EContact *cursor_contact; + GSList *previous_selection, *link; + gint row; + + view->priv->awaiting_search_start = FALSE; + + if (!view->priv->previous_selection && !view->priv->cursor_contact) + return; + + /* This can change selection, which frees the 'previous_selection', thus take + ownership of it. */ + previous_selection = view->priv->previous_selection; + view->priv->previous_selection = NULL; + + cursor_contact = view->priv->cursor_contact; + view->priv->cursor_contact = NULL; + + selection_model = e_addressbook_view_get_selection_model (view); + + if (cursor_contact) { + row = e_addressbook_model_find (model, cursor_contact); + + if (row >= 0) { + e_selection_model_change_cursor (selection_model, row, view->priv->cursor_col); + e_selection_model_cursor_changed (selection_model, row, view->priv->cursor_col); + } + } + + for (link = previous_selection; link; link = g_slist_next (link)) { + EContact *contact = link->data; + + row = e_addressbook_model_find (model, contact); + + if (row >= 0) + e_selection_model_change_one_row (selection_model, row, TRUE); + } + + g_slist_free_full (previous_selection, g_object_unref); + g_clear_object (&cursor_contact); + + e_selection_model_selection_changed (selection_model); +} + static gboolean address_book_view_focus_in_cb (EAddressbookView *view, GdkEvent *event) @@ -575,6 +671,11 @@ addressbook_view_dispose (GObject *object) g_clear_pointer (&priv->copy_target_list, gtk_target_list_unref); g_clear_pointer (&priv->paste_target_list, gtk_target_list_unref); + g_slist_free_full (priv->previous_selection, g_object_unref); + priv->previous_selection = NULL; + + g_clear_object (&priv->cursor_contact); + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_addressbook_view_parent_class)->dispose (object); } @@ -601,6 +702,15 @@ addressbook_view_constructed (GObject *object) view->priv->model = e_addressbook_model_new (client_cache); + g_signal_connect_object (view->priv->model, "before-search", + G_CALLBACK (addressbook_view_model_before_search_cb), view, 0); + + g_signal_connect_object (view->priv->model, "search-started", + G_CALLBACK (addressbook_view_model_search_started_cb), view, 0); + + g_signal_connect_object (view->priv->model, "search-result", + G_CALLBACK (addressbook_view_model_search_result_cb), view, 0); + view_instance = e_shell_view_new_view_instance (shell_view, uid); g_signal_connect ( view_instance, "display-view", |