[PATCH 2/2] Support merging of two adjacent dives

Linus Torvalds torvalds at linux-foundation.org
Sun Nov 11 01:40:27 PST 2012


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Sun, 11 Nov 2012 07:49:19 +0100
Subject: [PATCH 2/2] Support merging of two adjacent dives

This introduces the notion of merging two disjoint dives: you can select
two dives from the dive list, and if the selection is exactly two dives,
and they are adjacent (and share the same dive trip), we support the
notion of merging the dives into one dive.

The most common reason for this is an extended surface event, which made
the dive computer decide that the dive was ended, but maybe you were
just waiting for a buddy or a student at the surface, and you want to
stitch together two dives into one.

There are still details to be sorted out: my Suunto dive computers don't
actually do surface samples at the beginning or end of the dive, so when
you stitch two dives together, the profile ends up being this odd "a
couple of feet under water between the two parts of the dive" thing.

But that's an independent thing from the actual merging logic, and I'll
work on that separately.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---
 dive.c     |  9 +++-----
 dive.h     |  3 +++
 divelist.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 main.c     |  8 +++-----
 4 files changed, 77 insertions(+), 12 deletions(-)

diff --git a/dive.c b/dive.c
index da1dd0952be7..cc4e048d1010 100644
--- a/dive.c
+++ b/dive.c
@@ -809,15 +809,13 @@ static void merge_equipment(struct dive *res, struct dive *a, struct dive *b)
  * The 'next' dive is not involved in the dive merging, but is the dive
  * that will be the next dive after the merged dive.
  */
-static void pick_and_delete_trip(struct dive *res, struct dive *pick, struct dive *remove)
+static void pick_trip(struct dive *res, struct dive *pick)
 {
 	tripflag_t tripflag = pick->tripflag;
 	dive_trip_t *trip = pick->divetrip;
 
 	res->tripflag = tripflag;
 	add_dive_to_trip(res, trip);
-	remove_dive_from_trip(pick);
-	remove_dive_from_trip(remove);
 }
 
 /*
@@ -858,10 +856,9 @@ static void merge_trip(struct dive *res, struct dive *a, struct dive *b)
 	goto pick_b;
 
 pick_a:
-	pick_and_delete_trip(res, a, b);
-	return;
+	b = a;
 pick_b:
-	pick_and_delete_trip(res, b, a);
+	pick_trip(res, b);
 }
 
 /*
diff --git a/dive.h b/dive.h
index 6431cb1471ce..a1c96017b0ee 100644
--- a/dive.h
+++ b/dive.h
@@ -303,6 +303,9 @@ extern gboolean autogroup;
 extern void add_dive_to_trip(struct dive *, dive_trip_t *);
 extern void remove_dive_from_trip(struct dive *);
 
+extern void delete_single_dive(int idx);
+extern void add_single_dive(int idx, struct dive *dive);
+
 extern void insert_trip(dive_trip_t **trip);
 
 /*
diff --git a/divelist.c b/divelist.c
index 056a4f64af97..dcd4c7c9c62d 100644
--- a/divelist.c
+++ b/divelist.c
@@ -1919,7 +1919,7 @@ void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath)
 
 /* this implements the mechanics of removing the dive from the table,
  * but doesn't deal with updating dive trips, etc */
-static void delete_single_dive(int idx)
+void delete_single_dive(int idx)
 {
 	int i;
 	struct dive *dive = get_dive(idx);
@@ -1934,6 +1934,17 @@ static void delete_single_dive(int idx)
 	free(dive);
 }
 
+void add_single_dive(int idx, struct dive *dive)
+{
+	int i;
+	dive_table.nr++;
+	for (i = idx; i < dive_table.nr ; i++) {
+		struct dive *tmp = dive_table.dives[i];
+		dive_table.dives[i] = dive;
+		dive = tmp;
+	}
+}
+
 /* remember expanded state */
 static void remember_tree_state()
 {
@@ -2070,6 +2081,58 @@ static void delete_dive_cb(GtkWidget *menuitem, GtkTreePath *path)
 	mark_divelist_changed(TRUE);
 }
 
+static void merge_dive_index(int i, struct dive *a)
+{
+	struct dive *b = get_dive(i+1);
+	struct dive *res;
+
+	res = merge_dives(a, b, b->when - a->when);
+	if (!res)
+		return;
+
+	add_single_dive(i, res);
+	delete_single_dive(i+1);
+	delete_single_dive(i+1);
+
+	dive_list_update_dives();
+	restore_tree_state();
+	mark_divelist_changed(TRUE);
+}
+
+static void merge_dives_cb(GtkWidget *menuitem, void *unused)
+{
+	int i;
+	struct dive *dive;
+
+	for_each_dive(i, dive) {
+		if (dive->selected) {
+			merge_dive_index(i, dive);
+			return;
+		}
+	}
+}
+
+/* Called if there are exactly two selected dives and the dive at idx is one of them */
+static void add_dive_merge_label(int idx, GtkMenuShell *menu)
+{
+	struct dive *d;
+	GtkWidget *menuitem;
+
+	/* The other selected dive must be next to it.. */
+	if (!((d = get_dive(idx-1)) && d->selected) &&
+	    !((d = get_dive(idx+1)) && d->selected))
+		return;
+
+	/* .. and they had better be in the same dive trip */
+	if (d->divetrip != get_dive(idx)->divetrip)
+		return;
+
+	/* If so, we can add a "merge dive" menu entry */
+	menuitem = gtk_menu_item_new_with_label(_("Merge dives"));
+	g_signal_connect(menuitem, "activate", G_CALLBACK(merge_dives_cb), NULL);
+	gtk_menu_shell_append(menu, menuitem);
+}
+
 static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button, GdkEventButton *event)
 {
 	GtkWidget *menu, *menuitem, *image;
@@ -2142,6 +2205,10 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
 			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);
+
+			/* Two contiguous selected dives? */
+			if (amount_selected == 2)
+				add_dive_merge_label(idx, GTK_MENU_SHELL(menu));
 		} else {
 			deletelabel = _(deletesinglelabel);
 			menuitem = gtk_menu_item_new_with_label(deletelabel);
diff --git a/main.c b/main.c
index ca3722383d28..88a28c8c23f8 100644
--- a/main.c
+++ b/main.c
@@ -138,14 +138,12 @@ void report_dives(gboolean is_imported)
 		/* careful - we might free the dive that last points to. Oops... */
 		if (last == prev || last == dive)
 			last = merged;
-		free(prev);
-		free(dive);
-		*pp = merged;
-		dive_table.nr--;
-		memmove(pp+1, pp+2, sizeof(*pp)*(dive_table.nr - i));
 
 		/* Redo the new 'i'th dive */
 		i--;
+		add_single_dive(i, merged);
+		delete_single_dive(i+1);
+		delete_single_dive(i+1);
 	}
 
 	if (is_imported) {
-- 
1.8.0



More information about the subsurface mailing list