summaryrefslogtreecommitdiffstats
path: root/divelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'divelist.c')
-rw-r--r--divelist.c248
1 files changed, 226 insertions, 22 deletions
diff --git a/divelist.c b/divelist.c
index c52a94191..aedcdf03e 100644
--- a/divelist.c
+++ b/divelist.c
@@ -65,6 +65,9 @@ enum {
DIVELIST_COLUMNS
};
+static void turn_dive_into_trip(GtkTreePath *path);
+static void merge_dive_into_trip_above_cb(GtkWidget *menuitem, GtkTreePath *path);
+
#ifdef DEBUG_MODEL
static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
@@ -136,6 +139,39 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx)
}
}
+static GtkTreePath *path_match;
+
+static gboolean match_dive(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+ int idx;
+ struct dive *dive = data;
+
+ gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1);
+ if (idx >= 0)
+ if (get_dive(idx)->when == dive->when) {
+ path_match = gtk_tree_path_copy(path);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static GtkTreePath *get_path_from(struct dive *dive)
+{
+ gtk_tree_model_foreach(TREEMODEL(dive_list), match_dive, dive);
+ return path_match;
+}
+
+static struct dive *dive_from_path(GtkTreePath *path)
+{
+ GtkTreeIter iter;
+ int idx;
+
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
+ return get_dive(idx);
+
+}
+
/* make sure that if we expand a summary row that is selected, the children show
up as selected, too */
void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
@@ -927,6 +963,49 @@ static struct dive *create_and_hookup_trip_from_dive(struct dive *dive)
return dive_trip;
}
+/* check that a dive should be in a trip starting at 'when'
+ * first the regular check (dive is before the trip start, but within the
+ * threshold)
+ * then for dives that are after the trip start we walk back to the dive
+ * that starts at when and check on the way that there is no ungrouped
+ * dive and no break beyond the 3 day threshold between dives that
+ * haven't already been assigned to this trip */
+static gboolean dive_can_be_in_trip(int idx, struct dive *dive_trip)
+{
+ struct dive *dive, *pdive;
+ int i = idx;
+ time_t when = dive_trip->when;
+
+ dive = get_dive(idx);
+ /* if the dive is before the trip start but within the threshold
+ * then just accept it, otherwise reject it */
+ if (dive->when < when) {
+ if (DIVE_FITS_TRIP(dive, dive_trip))
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ while (--i >= 0) {
+ pdive = get_dive(i);
+ /* an ungrouped dive cannot be in the middle of a trip
+ * also, if there are two consecutive dives that are too far apart
+ * that aren't both already labeled as 'in trip' (which shows that
+ * this was manually done so we shouldn't override that) */
+ if ( UNGROUPED_DIVE(pdive) ||
+ (! (DIVE_IN_TRIP(pdive) && DIVE_IN_TRIP(dive)) &&
+ dive->when - pdive->when > TRIP_THRESHOLD)) {
+ return FALSE;
+ }
+ if (pdive->when == when)
+ /* done - we have reached the first dive in the trip */
+ return TRUE;
+ dive = pdive;
+ }
+ /* we should never get here */
+ return TRUE;
+}
+
static void fill_dive_list(void)
{
int i;
@@ -965,17 +1044,27 @@ static void fill_dive_list(void)
/* first dives that go to the top level */
parent_ptr = NULL;
dive_trip = NULL;
- } else if (autogroup && !DIVE_IN_TRIP(dive)) {
- if ( ! dive_trip || ! DIVE_FITS_TRIP(dive, dive_trip)) {
- /* allocate new trip - all fields default to 0
- and get filled in further down */
- dive_trip = create_and_hookup_trip_from_dive(dive);
- dive_trip->tripflag = IN_TRIP; /* this marks an autogen trip */
- trip = FIND_TRIP(dive_trip->when);
+ } else if (autogroup && DIVE_NEEDS_TRIP(dive)){
+ /* if we already have existing trips there are up to two trips that this
+ * could potentially be part of. Let's try the one we are on, first */
+ if (! (dive_trip && dive_can_be_in_trip(i, dive_trip))) {
+ /* there could be a better trip in our list already */
+ trip = find_matching_trip(dive->when);
+ if (! (trip && dive_can_be_in_trip(i, DIVE_TRIP(trip)))) {
+ /* seems like neither of these trips work, so create
+ * a new one; all fields default to 0 and get filled
+ * in further down */
+ parent_ptr = NULL;
+ dive_trip = create_and_hookup_trip_from_dive(dive);
+ dive_trip->tripflag = IN_TRIP;
+ trip = FIND_TRIP(dive_trip->when);
+ }
+ if (trip)
+ dive_trip = DIVE_TRIP(trip);
}
} else if (DIVE_IN_TRIP(dive)) {
- trip = find_matching_trip(dive->when);
- dive_trip = DIVE_TRIP(trip);
+ trip = find_matching_trip(dive->when);
+ dive_trip = DIVE_TRIP(trip);
} else {
/* dive is not in a trip and we aren't autogrouping */
dive_trip = NULL;
@@ -1188,13 +1277,7 @@ void edit_selected_dives_cb(GtkWidget *menuitem, gpointer data)
void edit_dive_from_path_cb(GtkWidget *menuitem, GtkTreePath *path)
{
- GtkTreeIter iter;
- int idx;
- struct dive *dive;
-
- gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
- gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
- dive = get_dive(idx);
+ struct dive *dive = dive_from_path(path);
edit_multi_dive_info(dive);
}
@@ -1310,6 +1393,48 @@ static GtkTreeIter *move_dive_between_trips(GtkTreeIter *dive_iter, GtkTreeIter
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 (;;) {
+ dive->divetrip = prev_dive->divetrip;
+ dive->tripflag = IN_TRIP;
+ (void)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 void turn_dive_into_trip(GtkTreePath *path)
{
GtkTreeIter iter, *newiter, newparent;
@@ -1390,10 +1515,25 @@ static void insert_trip_before(GtkTreePath *path)
static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path)
{
/* is this splitting a trip or turning a dive into a trip? */
- if (gtk_tree_path_get_depth(path) == 2)
+ if (gtk_tree_path_get_depth(path) == 2) {
insert_trip_before(path);
- else
+ } else { /* this is a top level dive */
+ struct dive *dive, *next_dive;
+ GtkTreePath *next_path;
+
+ dive = dive_from_path(path);
turn_dive_into_trip(path);
+ /* if the dive was selected and the next dive was selected, too,
+ * then all of them should be part of the new trip */
+ if (dive->selected) {
+ next_path = gtk_tree_path_copy(path);
+ gtk_tree_path_next(next_path);
+ next_dive = dive_from_path(next_path);
+ if (next_dive && next_dive->selected)
+ merge_dive_into_trip_above_cb(menuitem, next_path);
+ }
+ }
+ mark_divelist_changed(TRUE);
}
static void remove_from_trip(GtkTreePath *path)
@@ -1492,6 +1632,7 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path)
/* just remove the dive the mouse pointer is on */
remove_from_trip(path);
}
+ mark_divelist_changed(TRUE);
}
void remove_trip(GtkTreePath *trippath, gboolean force_no_trip)
@@ -1540,6 +1681,7 @@ void remove_trip(GtkTreePath *trippath, gboolean force_no_trip)
void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath)
{
remove_trip(trippath, TRUE);
+ mark_divelist_changed(TRUE);
}
void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath)
@@ -1570,6 +1712,55 @@ void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath)
free(DIVE_TRIP(trip));
delete_trip(trip);
gtk_tree_store_remove(STORE(dive_list), &thistripiter);
+ 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 idx, i;
+ 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);
+ 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,
+ * so let's do this the manual way */
+ pdive = get_dive(idx - 1);
+ ndive = get_dive(idx + 1);
+ if (! (pdive && pdive->divetrip == dive->divetrip) &&
+ ! (ndive && ndive->divetrip == dive->divetrip)) {
+ /* if this is the only dive in the trip, remove the trip - the
+ * dive list update below will deal with making sure the treemodel
+ * is correct */
+ GList *trip = find_matching_trip(dive->when);
+ delete_trip(trip);
+ free(dive->divetrip);
+ }
+ }
+ /* 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++)
+ dive_table.dives[i] = dive_table.dives[i+1];
+ dive_table.nr--;
+ free(dive);
+ dive_list_update_dives();
+ /* now make sure the same dives stay selected and if necessary their trips are expanded */
+ for_each_dive(i, dive) {
+ if (dive->selected) {
+ GtkTreePath *path = get_path_from(dive);
+ if (MODEL(dive_list) == TREEMODEL(dive_list))
+ gtk_tree_view_expand_to_path(tree_view, path);
+ gtk_tree_selection_select_path(selection, path);
+ }
+ }
+ mark_divelist_changed(TRUE);
}
static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button, GdkEventButton *event)
@@ -1622,6 +1813,9 @@ 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 (dive->selected) {
@@ -1638,14 +1832,24 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
}
/* only offer trip editing options when we are displaying the tree model */
if (dive_list.model == dive_list.treemodel) {
- int depth;
- int *indices = gtk_tree_path_get_indices_with_depth(path, &depth);
-
+ int depth = gtk_tree_path_get_depth(path);
+ int *indices = gtk_tree_path_get_indices(path);
+ /* top level dive or child dive that is not the first child */
if (depth == 1 || indices[1] > 0) {
- menuitem = gtk_menu_item_new_with_label("Add new trip above");
+ menuitem = gtk_menu_item_new_with_label("Create new trip above");
g_signal_connect(menuitem, "activate", G_CALLBACK(insert_trip_before_cb), path);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
}
+ prevpath = gtk_tree_path_copy(path);
+ /* top level dive with a trip right before it */
+ if (depth == 1 &&
+ gtk_tree_path_prev(prevpath) &&
+ gtk_tree_model_get_iter(MODEL(dive_list), &previter, prevpath) &&
+ gtk_tree_model_iter_n_children(model, &previter)) {
+ menuitem = gtk_menu_item_new_with_label("Add to trip above");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(merge_dive_into_trip_above_cb), path);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ }
if (DIVE_IN_TRIP(dive)) {
if (dive->selected && amount_selected > 1)
menuitem = gtk_menu_item_new_with_label("Remove selected dives from trip");