From 6458057599e6b80a8a04a29d2aa975347f69ff8c Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Sat, 22 Sep 2012 23:31:55 +0300 Subject: Added different delete label when right clicking multiple drives When clicking multiple dives in the list, check if more than one are selected and if so show the text "Delete dives". Signed-off-by: Lubomir I. Ivanov --- divelist.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/divelist.c b/divelist.c index 810b5be7c..a62f259d5 100644 --- a/divelist.c +++ b/divelist.c @@ -1900,6 +1900,7 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int { GtkWidget *menu, *menuitem, *image; char editlabel[] = "Edit dives"; + char deletelabel[] = "Delete dives"; GtkTreePath *path, *prevpath, *nextpath; GtkTreeIter iter, previter, nextiter; int idx, previdx, nextidx; @@ -1946,18 +1947,26 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int g_signal_connect(menuitem, "activate", G_CALLBACK(remove_trip_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } else { - menuitem = gtk_menu_item_new_with_label("Delete Dive"); - g_signal_connect(menuitem, "activate", G_CALLBACK(delete_dive_cb), path); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); dive = get_dive(idx); - /* if we right click on selected dive(s), edit those */ + /* if we right click on selected dive(s), edit or delete those */ if (dive->selected) { - if (amount_selected == 1) + if (amount_selected == 1) { + deletelabel[strlen(deletelabel) - 1] = '\0'; editlabel[strlen(editlabel) - 1] = '\0'; + } + menuitem = gtk_menu_item_new_with_label(deletelabel); + g_signal_connect(menuitem, "activate", G_CALLBACK(NULL), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = gtk_menu_item_new_with_label(editlabel); g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } else { + deletelabel[strlen(deletelabel) - 1] = '\0'; + menuitem = gtk_menu_item_new_with_label(deletelabel); + g_signal_connect(menuitem, "activate", G_CALLBACK(delete_dive_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + editlabel[strlen(editlabel) - 1] = '\0'; menuitem = gtk_menu_item_new_with_label(editlabel); g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_from_path_cb), path); -- cgit v1.2.3-70-g09d2 From 4d9abf6e8ee465728d1ff1308e18265557dbca42 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Sun, 23 Sep 2012 01:03:19 +0300 Subject: Added the functionality to delete selected (multiple) dives Moved portion of the code from delete_dive_cb() to a function called delete_single_dive(), that directly accepts a GtkTreeIter pointer. Added the function delete_selected_dives_cb(), which is called when calling "Delete dives" from the combo box for the selected dives. The above function iterates trought the selection calling delete_selected_foreach(), which on its own calls delete_single_dive(). The "for-each" API in this case looks much prettier C code wise, however we do potentially create an extra jump and also do not have anything but the redirection: delete_selected_foreach() -> delete_single_dive() Probably slighly slower than using gtk_tree_selection_get_selected_rows(), performance wise, but less C code. Signed-off-by: Lubomir I. Ivanov --- divelist.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/divelist.c b/divelist.c index a62f259d5..b9fe927d6 100644 --- a/divelist.c +++ b/divelist.c @@ -1842,19 +1842,15 @@ void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath) mark_divelist_changed(TRUE); } -/* this gets called with path pointing to a dive, either in the top level - * or as part of a trip */ -static void delete_dive_cb(GtkWidget *menuitem, GtkTreePath *path) +/* delete a dive by passing a tree iterator */ +static void delete_single_dive(GtkTreeIter *iter) { - GtkTreeIter iter; - int idx, i; + int i, idx; struct dive *dive, *pdive, *ndive; - GtkTreeView *tree_view = GTK_TREE_VIEW(dive_list.tree_view); - GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); - gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); - gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + gtk_tree_model_get(MODEL(dive_list), iter, DIVE_INDEX, &idx, -1); dive = get_dive(idx); + if (dive->divetrip) { /* we could be displaying the list model, in which case we can't find out * if this is part of a trip and the only dive in that trip from the model, @@ -1879,6 +1875,42 @@ static void delete_dive_cb(GtkWidget *menuitem, GtkTreePath *path) if (dive->selected) amount_selected--; free(dive); +} + +/* much simpler to use compared to gtk_tree_selection_get_selected_rows() */ +static void delete_selected_foreach(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer userdata) +{ + delete_single_dive(iter); +} + +/* called when multiple dives are selected and one of these is right-clicked for delete */ +static void delete_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + GtkTreeView *tree_view = GTK_TREE_VIEW(dive_list.tree_view); + GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); + gtk_tree_selection_selected_foreach(selection, delete_selected_foreach, NULL); + + dive_list_update_dives(); + mark_divelist_changed(TRUE); +} + +/* this gets called with path pointing to a dive, either in the top level + * or as part of a trip */ +static void delete_dive_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + GtkTreeIter iter; + int i, idx; + struct dive *dive; + GtkTreeView *tree_view = GTK_TREE_VIEW(dive_list.tree_view); + GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); + + gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); + delete_single_dive(&iter); + + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + /* now make sure the correct dive list is displayed, the same * dives stay selected and if necessary their trips are * expanded. If no selected dives are left then fill_dive_list() @@ -1955,7 +1987,7 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int editlabel[strlen(editlabel) - 1] = '\0'; } menuitem = gtk_menu_item_new_with_label(deletelabel); - g_signal_connect(menuitem, "activate", G_CALLBACK(NULL), path); + g_signal_connect(menuitem, "activate", G_CALLBACK(delete_selected_dives_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); menuitem = gtk_menu_item_new_with_label(editlabel); -- cgit v1.2.3-70-g09d2 From 9036f3f80e32dc72280e6b9f6ff4560171210331 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Sun, 23 Sep 2012 16:28:23 +0300 Subject: Update the trip's "when" flag after deleting a dive from it Both gtk_tree_selection_selected_foreach() and gtk_tree_selection_get_selected_rows() are problematic. gtk_tree_selection_get_selected_rows is not compatible with older GTK, while gtk_tree_selection_selected_foreach() should not be used to modify the tree. A workaround to is allocate memory and store what is returned from the gtk_tree_selection_selected_foreach() callback function as a GtkTreeIter array. Once done iterate trought the array and pass the values to delete_single_dive(). A bit excesive, but it is not certain how safe is modifying the tree while in the "_foreach" loop, even if it only shows a warning. On the other hand the GTK source shows gtk_tree_selection_get_selected_rows() to be a rather complicated and slow method. Inside delete_single_dive(), once a dive is no longer part of "dive_table" and if the dive was part of a trip, remove the dive from the tree (gtk_tree_store_remove()) and call update_trip_timestamp(). The struct type "tree_selected_st" and tree_selected_foreach() are reusable. Reported-by: Dirk Hohndel Signed-off-by: Lubomir I. Ivanov --- divelist.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/divelist.c b/divelist.c index b9fe927d6..ce9796d82 100644 --- a/divelist.c +++ b/divelist.c @@ -1847,6 +1847,7 @@ static void delete_single_dive(GtkTreeIter *iter) { int i, idx; struct dive *dive, *pdive, *ndive; + GtkTreeIter parent; gtk_tree_model_get(MODEL(dive_list), iter, DIVE_INDEX, &idx, -1); dive = get_dive(idx); @@ -1865,8 +1866,10 @@ static void delete_single_dive(GtkTreeIter *iter) GList *trip = find_matching_trip(dive->when); delete_trip(trip); free(dive->divetrip); + dive->divetrip = NULL; } } + /* simply remove the dive and recreate the divelist * (we can't just manipulate the tree_view as the indices for dives change) */ for (i = idx; i < dive_table.nr - 1; i++) @@ -1874,22 +1877,48 @@ static void delete_single_dive(GtkTreeIter *iter) dive_table.nr--; if (dive->selected) amount_selected--; + + /* once the dive is deleted, update the 'when' flag of the trip it was part of + * to the 'when' flag of the earliest dive left in the same trip */ + if (dive->divetrip) { + gtk_tree_model_iter_parent(MODEL(dive_list), &parent, iter); + gtk_tree_store_remove(STORE(dive_list), iter); + update_trip_timestamp(&parent, dive->divetrip); + } + free(dive); } -/* much simpler to use compared to gtk_tree_selection_get_selected_rows() */ -static void delete_selected_foreach(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer userdata) +/* workaround for not using gtk_tree_selection_get_selected_rows() or modifying the tree + * directly from the gtk_tree_selection_selected_foreach() callback function */ +struct tree_selected_st { + GtkTreeIter *list; + int total; +}; + +static void tree_selected_foreach(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer userdata) { - delete_single_dive(iter); + struct tree_selected_st *st = (struct tree_selected_st *)userdata; + + st->total++; + st->list = (GtkTreeIter *)realloc(st->list, sizeof(GtkTreeIter) * st->total); + memcpy(&st->list[st->total - 1], iter, sizeof(GtkTreeIter)); } /* called when multiple dives are selected and one of these is right-clicked for delete */ static void delete_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path) { + int i; GtkTreeView *tree_view = GTK_TREE_VIEW(dive_list.tree_view); GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); - gtk_tree_selection_selected_foreach(selection, delete_selected_foreach, NULL); + struct tree_selected_st st = {NULL, 0}; + + gtk_tree_selection_selected_foreach(selection, tree_selected_foreach, &st); + + for (i = 0; i < st.total; i++) + delete_single_dive(&st.list[i]); + free(st.list); dive_list_update_dives(); mark_divelist_changed(TRUE); -- cgit v1.2.3-70-g09d2