Rewrite "merge_dive_into_trip_above()" using our own data structures

This does the moving of dives into the trip above without the complexity
of the gtk data structures, and instead just recreates the whole
divelist afterwards.  As usual, this simplifies things a lot, and the
less gtk-specific code we have, the better.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Linus Torvalds 2013-02-19 11:30:17 -08:00 committed by Dirk Hohndel
parent e453ea8695
commit 7847de62b1

View file

@ -1654,160 +1654,6 @@ static void collapse_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
gtk_tree_view_collapse_all(tree_view);
}
/* copy the node and return the index */
static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b)
{
struct dive store_dive;
int totalweight, idx;
char *cylinder_text;
GdkPixbuf *icon;
gtk_tree_model_get(MODEL(dive_list), a,
DIVE_INDEX, &idx,
DIVE_NR, &store_dive.number,
DIVE_DATE, &store_dive.when,
DIVE_RATING, &store_dive.rating,
DIVE_DEPTH, &store_dive.maxdepth,
DIVE_DURATION, &store_dive.duration,
DIVE_TEMPERATURE, &store_dive.watertemp.mkelvin,
DIVE_TOTALWEIGHT, &totalweight,
DIVE_SUIT, &store_dive.suit,
DIVE_CYLINDER, &cylinder_text,
DIVE_SAC, &store_dive.sac,
DIVE_OTU, &store_dive.otu,
DIVE_MAXCNS, &store_dive.maxcns,
DIVE_LOCATION, &store_dive.location,
DIVE_LOC_ICON, &icon,
-1);
gtk_tree_store_set(STORE(dive_list), b,
DIVE_INDEX, idx,
DIVE_NR, store_dive.number,
DIVE_DATE, store_dive.when,
DIVE_RATING, store_dive.rating,
DIVE_DEPTH, store_dive.maxdepth,
DIVE_DURATION, store_dive.duration,
DIVE_TEMPERATURE, store_dive.watertemp.mkelvin,
DIVE_TOTALWEIGHT, totalweight,
DIVE_SUIT, store_dive.suit,
DIVE_CYLINDER, cylinder_text,
DIVE_SAC, store_dive.sac,
DIVE_OTU, store_dive.otu,
DIVE_MAXCNS, store_dive.maxcns,
DIVE_LOCATION, store_dive.location,
DIVE_LOC_ICON, icon,
-1);
free(cylinder_text);
free(store_dive.location);
free(store_dive.suit);
return idx;
}
/* to avoid complicated special cases based on ordering or number of children,
we always take the first and last child and pick the smaller timestamp_t (which
works regardless of ordering and also with just one child) */
static void update_trip_timestamp(GtkTreeIter *parent, dive_trip_t *divetrip)
{
GtkTreeIter first_child, last_child;
int nr;
timestamp_t t1, t2, tnew;
if (gtk_tree_store_iter_depth(STORE(dive_list), parent) != 0 ||
gtk_tree_model_iter_n_children(MODEL(dive_list), parent) == 0)
return;
nr = gtk_tree_model_iter_n_children(MODEL(dive_list), parent);
gtk_tree_model_iter_nth_child(MODEL(dive_list), &first_child, parent, 0);
gtk_tree_model_get(MODEL(dive_list), &first_child, DIVE_DATE, &t1, -1);
gtk_tree_model_iter_nth_child(MODEL(dive_list), &last_child, parent, nr - 1);
gtk_tree_model_get(MODEL(dive_list), &last_child, DIVE_DATE, &t2, -1);
tnew = MIN(t1, t2);
gtk_tree_store_set(STORE(dive_list), parent, DIVE_DATE, tnew, -1);
if (divetrip)
divetrip->when = tnew;
}
/* move dive_iter, which is a child of old_trip (could be NULL) to new_trip (could be NULL);
* either of the trips being NULL means that this was (or will be) a dive without a trip;
* update the dive trips (especially the starting times) accordingly
* maintain the selected status of the dive
* IMPORTANT - the move needs to keep the tree consistant - so no out of order moving... */
static GtkTreeIter *move_dive_between_trips(GtkTreeIter *dive_iter, GtkTreeIter *old_trip, GtkTreeIter *new_trip,
GtkTreeIter *sibling, gboolean before)
{
int idx;
timestamp_t old_when, new_when;
struct dive *dive;
dive_trip_t *old_divetrip, *new_divetrip;
GtkTreeIter *new_iter = malloc(sizeof(GtkTreeIter));
if (before)
gtk_tree_store_insert_before(STORE(dive_list), new_iter, new_trip, sibling);
else
gtk_tree_store_insert_after(STORE(dive_list), new_iter, new_trip, sibling);
idx = copy_tree_node(dive_iter, new_iter);
gtk_tree_model_get(MODEL(dive_list), new_iter, DIVE_INDEX, &idx, -1);
dive = get_dive(idx);
gtk_tree_store_remove(STORE(dive_list), dive_iter);
if (old_trip) {
gtk_tree_model_get(MODEL(dive_list), old_trip, DIVE_DATE, &old_when, -1);
old_divetrip = find_matching_trip(old_when);
update_trip_timestamp(old_trip, old_divetrip);
}
if (new_trip) {
gtk_tree_model_get(MODEL(dive_list), new_trip, DIVE_DATE, &new_when, -1);
new_divetrip = dive->divetrip;
update_trip_timestamp(new_trip, new_divetrip);
}
if (dive->selected) {
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
gtk_tree_selection_select_iter(selection, new_iter);
}
return new_iter;
}
/* this gets called when we are on a top level dive and we know that the previous
* top level node is a trip; if multiple consecutive dives are selected, they are
* all merged into the previous trip*/
static void merge_dive_into_trip_above_cb(GtkWidget *menuitem, GtkTreePath *path)
{
int idx;
GtkTreeIter dive_iter, trip_iter, prev_iter;
GtkTreePath *trip_path;
struct dive *dive, *prev_dive;
/* get the path and iter for the trip and the last dive of that trip */
trip_path = gtk_tree_path_copy(path);
(void)gtk_tree_path_prev(trip_path);
gtk_tree_model_get_iter(MODEL(dive_list), &trip_iter, trip_path);
gtk_tree_model_get_iter(MODEL(dive_list), &dive_iter, path);
gtk_tree_model_iter_nth_child(MODEL(dive_list), &prev_iter, &trip_iter,
gtk_tree_model_iter_n_children(MODEL(dive_list), &trip_iter) - 1);
gtk_tree_model_get(MODEL(dive_list), &dive_iter, DIVE_INDEX, &idx, -1);
dive = get_dive(idx);
gtk_tree_model_get(MODEL(dive_list), &prev_iter, DIVE_INDEX, &idx, -1);
prev_dive = get_dive(idx);
/* add the dive to the trip */
for (;;) {
add_dive_to_trip(dive, prev_dive->divetrip);
/* we intentionally changed the dive_trip, so update the time
* stamp that we fall back to when toggling autogroup */
dive->tripflag = IN_TRIP;
free(move_dive_between_trips(&dive_iter, NULL, &trip_iter, NULL, TRUE));
prev_dive = dive;
/* by merging the dive into the trip above the path now points to the next
top level entry. If that iter exists, it's also a dive and both this dive
and that next dive are selected, continue merging dives into the trip */
if (!gtk_tree_model_get_iter(MODEL(dive_list), &dive_iter, path))
break;
gtk_tree_model_get(MODEL(dive_list), &dive_iter, DIVE_INDEX, &idx, -1);
if (idx < 0)
break;
dive = get_dive(idx);
if (!dive->selected || !prev_dive->selected)
break;
}
mark_divelist_changed(TRUE);
}
static int get_path_index(GtkTreePath *path)
{
GtkTreeIter iter;
@ -1818,6 +1664,47 @@ static int get_path_index(GtkTreePath *path)
return idx;
}
/* Move a top-level dive into the trip above it */
static void merge_dive_into_trip_above_cb(GtkWidget *menuitem, GtkTreePath *path)
{
int idx;
struct dive *dive;
dive_trip_t *trip;
idx = get_path_index(path);
dive = get_dive(idx);
/* Needs to be a dive, and at the top level */
if (!dive || dive->divetrip)
return;
/* Find the "trip above". */
for (;;) {
if (!gtk_tree_path_prev(path))
return;
idx = get_path_index(path);
trip = find_trip_by_idx(idx);
if (trip)
break;
}
remember_tree_state();
add_dive_to_trip(dive, trip);
if (dive->selected) {
for_each_dive(idx, dive) {
if (!dive->selected)
continue;
add_dive_to_trip(dive, trip);
}
}
trip->expanded = 1;
dive_list_update_dives();
restore_tree_state();
mark_divelist_changed(TRUE);
}
static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path)
{
int idx;