summaryrefslogtreecommitdiffstats
path: root/divelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'divelist.c')
-rw-r--r--divelist.c647
1 files changed, 581 insertions, 66 deletions
diff --git a/divelist.c b/divelist.c
index 1e1d1c921..c52a94191 100644
--- a/divelist.c
+++ b/divelist.c
@@ -31,6 +31,13 @@ struct DiveList {
};
static struct DiveList dive_list;
+#define MODEL(_dl) GTK_TREE_MODEL((_dl).model)
+#define TREEMODEL(_dl) GTK_TREE_MODEL((_dl).treemodel)
+#define LISTMODEL(_dl) GTK_TREE_MODEL((_dl).listmodel)
+#define STORE(_dl) GTK_TREE_STORE((_dl).model)
+#define TREESTORE(_dl) GTK_TREE_STORE((_dl).treemodel)
+#define LISTSTORE(_dl) GTK_TREE_STORE((_dl).listmodel)
+
GList *dive_trip_list;
gboolean autogroup = FALSE;
@@ -65,9 +72,17 @@ static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
char *location;
int idx, nr, duration;
struct dive *dive;
+ time_t when;
+ struct tm *tm;
- gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1);
- printf("entry #%d : nr %d duration %d location %s ", idx, nr, duration, location);
+ gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DATE, &when,
+ DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1);
+ tm = gmtime(&when);
+ printf("iter %x:%x entry #%d : nr %d @ %04d-%02d-%02d %02d:%02d:%02d duration %d location %s ",
+ iter->stamp, iter->user_data, idx, nr,
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ duration, location);
dive = get_dive(idx);
if (dive)
printf("tripflag %d\n", dive->tripflag);
@@ -82,6 +97,7 @@ static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
static void dump_model(GtkListStore *store)
{
gtk_tree_model_foreach(GTK_TREE_MODEL(store), dump_model_entry, NULL);
+ printf("\n---\n\n");
}
#endif
@@ -116,7 +132,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx)
return;
if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath))
gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
- gtk_tree_model_get(GTK_TREE_MODEL(model), iter, DIVE_INDEX, diveidx, -1);
+ gtk_tree_model_get(model, iter, DIVE_INDEX, diveidx, -1);
}
}
@@ -125,7 +141,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx)
void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
{
GtkTreeIter child;
- GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
+ GtkTreeModel *model = MODEL(dive_list);
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
if (!gtk_tree_model_iter_children(model, &child, iter))
@@ -169,7 +185,7 @@ static int selected_children(GtkTreeModel *model, GtkTreeIter *iter)
shows up as selected too */
void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
{
- GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
+ GtkTreeModel *model = MODEL(dive_list);
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
if (selected_children(model, iter))
@@ -253,7 +269,7 @@ static void select_dive_group(GtkTreeModel *model, GtkTreeSelection *selection,
*/
static void check_selection_cb(GtkTreeIter *iter, GtkTreeSelection *selection)
{
- GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
+ GtkTreeModel *model = MODEL(dive_list);
struct dive *dive;
int idx, gtk_selected;
@@ -449,13 +465,20 @@ static void nr_data_func(GtkTreeViewColumn *col,
{
int idx, nr;
char buffer[40];
+ struct dive *dive;
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1);
- if (idx < 0)
+ if (idx < 0) {
*buffer = '\0';
- else
- snprintf(buffer, sizeof(buffer), "%d", nr);
- g_object_set(renderer, "text", buffer, NULL);
+ } else {
+ /* make dives that are not in trips stand out */
+ dive = get_dive(idx);
+ if (!DIVE_IN_TRIP(dive))
+ snprintf(buffer, sizeof(buffer), "<b>%d</b>", nr);
+ else
+ snprintf(buffer, sizeof(buffer), "%d", nr);
+ }
+ g_object_set(renderer, "markup", buffer, NULL);
}
/*
@@ -787,7 +810,7 @@ static void fill_one_dive(struct dive *dive,
GtkTreeIter *iter)
{
char *location, *cylinder, *suit;
- GtkTreeStore *othermodel;
+ GtkTreeModel *othermodel;
get_cylinder(dive, &cylinder);
get_location(dive, &location);
@@ -808,13 +831,13 @@ static void fill_one_dive(struct dive *dive,
free(cylinder);
free(suit);
- if (model == GTK_TREE_MODEL(dive_list.treemodel))
- othermodel = dive_list.listmodel;
+ if (model == TREEMODEL(dive_list))
+ othermodel = LISTMODEL(dive_list);
else
- othermodel = dive_list.treemodel;
- if (othermodel != dive_list.model)
+ othermodel = TREEMODEL(dive_list);
+ if (othermodel != MODEL(dive_list))
/* recursive call */
- gtk_tree_model_foreach(GTK_TREE_MODEL(othermodel), set_one_dive, dive);
+ gtk_tree_model_foreach(othermodel, set_one_dive, dive);
}
static gboolean set_one_dive(GtkTreeModel *model,
@@ -841,7 +864,7 @@ static gboolean set_one_dive(GtkTreeModel *model,
void flush_divelist(struct dive *dive)
{
- GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
+ GtkTreeModel *model = MODEL(dive_list);
gtk_tree_model_foreach(model, set_one_dive, dive);
}
@@ -856,7 +879,7 @@ void set_divelist_font(const char *font)
void update_dive_list_units(void)
{
const char *unit;
- GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
+ GtkTreeModel *model = MODEL(dive_list);
(void) get_depth_units(0, NULL, &unit);
gtk_tree_view_column_set_title(dive_list.depth, unit);
@@ -882,6 +905,28 @@ void update_dive_list_col_visibility(void)
return;
}
+static GList *find_matching_trip(time_t when)
+{
+ GList *trip = dive_trip_list;
+ if (!trip || DIVE_TRIP(trip)->when > when)
+ return NULL;
+ while (trip->next && DIVE_TRIP(trip->next)->when <= when)
+ trip = trip->next;
+ return trip;
+}
+
+static struct dive *create_and_hookup_trip_from_dive(struct dive *dive)
+{
+ struct dive *dive_trip = alloc_dive();
+ dive_trip->when = dive->when;
+ if (dive->location)
+ dive_trip->location = strdup(dive->location);
+ insert_trip(&dive_trip);
+ dive->divetrip = dive_trip;
+ dive->tripflag = IN_TRIP;
+ return dive_trip;
+}
+
static void fill_dive_list(void)
{
int i;
@@ -894,8 +939,8 @@ static void fill_dive_list(void)
/* if we have pre-existing trips, start on the last one */
trip = g_list_last(dive_trip_list);
- treestore = GTK_TREE_STORE(dive_list.treemodel);
- liststore = GTK_TREE_STORE(dive_list.listmodel);
+ treestore = TREESTORE(dive_list);
+ liststore = LISTSTORE(dive_list);
i = dive_table.nr;
while (--i >= 0) {
@@ -924,35 +969,25 @@ static void fill_dive_list(void)
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 = alloc_dive();
- dive_trip_list = insert_trip(dive_trip, dive_trip_list);
- trip = FIND_TRIP(dive_trip, dive_trip_list);
- }
- } else { /* either the dive has a trip or we aren't creating trips */
- if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) {
- GList *last_trip = trip;
- trip = PREV_TRIP(trip, dive_trip_list);
- if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) {
- /* we could get here if there are no trips in the XML file
- * and we aren't creating trips, either.
- * Otherwise we need to create a new trip */
- if (autogroup) {
- dive_trip = alloc_dive();
- dive_trip_list = insert_trip(dive_trip, dive_trip_list);
- trip = FIND_TRIP(dive_trip, dive_trip_list);
- } else {
- /* let's go back to the last valid trip */
- trip = last_trip;
- }
- } else {
- dive_trip = trip->data;
- }
+ 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 (DIVE_IN_TRIP(dive)) {
+ 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;
+ parent_ptr = NULL;
}
- /* update dive_trip time and (if necessary) location */
+ /* update dive as part of dive_trip and
+ * (if necessary) update dive_trip time and location */
if (dive_trip) {
dive->tripflag = IN_TRIP;
- dive_trip->when = dive->when;
+ dive->divetrip = dive_trip;
+ if (dive_trip->when > dive->when)
+ dive_trip->when = dive->when;
if (!dive_trip->location && dive->location)
dive_trip->location = dive->location;
if (dive_trip != last_trip) {
@@ -1007,12 +1042,12 @@ static void fill_dive_list(void)
DIVE_LOCATION, dive_trip->location,
-1);
update_dive_list_units();
- if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dive_list.model), &iter)) {
+ if (gtk_tree_model_get_iter_first(MODEL(dive_list), &iter)) {
GtkTreeSelection *selection;
/* select the last dive (and make sure it's an actual dive that is selected) */
- gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &selected_dive, -1);
- first_leaf(GTK_TREE_MODEL(dive_list.model), &iter, &selected_dive);
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &selected_dive, -1);
+ first_leaf(MODEL(dive_list), &iter, &selected_dive);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
gtk_tree_selection_select_iter(selection, &iter);
}
@@ -1020,8 +1055,8 @@ static void fill_dive_list(void)
void dive_list_update_dives(void)
{
- gtk_tree_store_clear(GTK_TREE_STORE(dive_list.treemodel));
- gtk_tree_store_clear(GTK_TREE_STORE(dive_list.listmodel));
+ gtk_tree_store_clear(TREESTORE(dive_list));
+ gtk_tree_store_clear(LISTSTORE(dive_list));
fill_dive_list();
repaint_dive();
}
@@ -1106,10 +1141,10 @@ static void row_activated_cb(GtkTreeView *tree_view,
int index;
GtkTreeIter iter;
- if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(dive_list.model), &iter, path))
+ if (!gtk_tree_model_get_iter(MODEL(dive_list), &iter, path))
return;
- gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &index, -1);
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &index, -1);
/* a negative index is special for the "group by date" entries */
if (index < 0) {
collapse_expand(tree_view, path);
@@ -1131,11 +1166,39 @@ void add_dive_cb(GtkWidget *menuitem, gpointer data)
free(dive);
}
-void edit_dive_cb(GtkWidget *menuitem, gpointer data)
+void edit_trip_cb(GtkWidget *menuitem, GtkTreePath *path)
+{
+ GtkTreeIter iter;
+ time_t when;
+ struct dive *dive_trip;
+ GList *trip;
+
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_DATE, &when, -1);
+ trip = FIND_TRIP(when);
+ dive_trip = DIVE_TRIP(trip);
+ if (edit_trip(dive_trip))
+ gtk_tree_store_set(STORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1);
+}
+
+void edit_selected_dives_cb(GtkWidget *menuitem, gpointer data)
{
edit_multi_dive_info(NULL);
}
+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);
+
+ edit_multi_dive_info(dive);
+}
+
static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
{
gtk_tree_view_expand_all(tree_view);
@@ -1146,10 +1209,382 @@ static void collapse_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
gtk_tree_view_collapse_all(tree_view);
}
-static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button)
+/* 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;
+
+ 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_LOCATION, &store_dive.location,
+ -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_LOCATION, store_dive.location,
+ -1);
+ 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 time_t (which
+ works regardless of ordering and also with just one child) */
+static void update_trip_timestamp(GtkTreeIter *parent, struct dive *divetrip)
+{
+ GtkTreeIter first_child, last_child;
+ int nr;
+ time_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;
+ time_t old_when, new_when;
+ struct dive *dive, *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 = DIVE_TRIP(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;
+}
+
+static void turn_dive_into_trip(GtkTreePath *path)
+{
+ GtkTreeIter iter, *newiter, newparent;
+ GtkTreePath *treepath;
+ time_t when;
+ char *location;
+ int idx;
+ struct dive *dive;
+
+ /* this is a dive on the top level, insert trip AFTER it, populate its date / location, and
+ * then move the dive below that trip */
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ gtk_tree_store_insert_after(STORE(dive_list), &newparent, NULL, &iter);
+ gtk_tree_model_get(MODEL(dive_list), &iter,
+ DIVE_INDEX, &idx, DIVE_DATE, &when, DIVE_LOCATION, &location, -1);
+ gtk_tree_store_set(STORE(dive_list), &newparent,
+ DIVE_INDEX, -1, DIVE_DATE, when, DIVE_LOCATION, location, -1);
+ free(location);
+ newiter = move_dive_between_trips(&iter, NULL, &newparent, NULL, FALSE);
+ treepath = gtk_tree_model_get_path(MODEL(dive_list), newiter);
+ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath);
+ dive = get_dive(idx);
+ /* we don't need the return value - everything is hooked up in the function */
+ (void)create_and_hookup_trip_from_dive(dive);
+}
+
+/* we know that path is pointing at a dive in a trip and are asked to split this trip into two */
+static void insert_trip_before(GtkTreePath *path)
+{
+ GtkTreeIter iter, prev_iter, parent, newparent, nextsibling;
+ GtkTreePath *treepath, *prev_path;
+ struct dive *dive, *prev_dive, *new_divetrip;
+ int idx, nr, i;
+
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ prev_path = gtk_tree_path_copy(path);
+ if (!gtk_tree_path_prev(prev_path) ||
+ !gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter))
+ return;
+ gtk_tree_model_get_iter(MODEL(dive_list), &prev_iter, prev_path);
+ gtk_tree_model_get(MODEL(dive_list), &prev_iter, DIVE_INDEX, &idx, -1);
+ prev_dive = get_dive(idx);
+ gtk_tree_store_insert_after(STORE(dive_list), &newparent, NULL, &parent);
+ copy_tree_node(&parent, &newparent);
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
+ dive = get_dive(idx);
+ /* make sure that the time_t of the previous divetrip is correct before
+ * inserting a new one */
+ if (dive->when < prev_dive->when)
+ if (prev_dive->divetrip && prev_dive->divetrip->when < prev_dive->when)
+ prev_dive->divetrip->when = prev_dive->when;
+ new_divetrip = create_and_hookup_trip_from_dive(dive);
+
+ /* in order for the data structures to stay consistent we need to walk from
+ * the last child backwards to this one. The easiest way seems to be to do
+ * this with the nth iterator API */
+ nr = gtk_tree_model_iter_n_children(MODEL(dive_list), &parent);
+ for (i = nr - 1; i >= 0; i--) {
+ gtk_tree_model_iter_nth_child(MODEL(dive_list), &nextsibling, &parent, i);
+ treepath = gtk_tree_model_get_path(MODEL(dive_list), &nextsibling);
+ gtk_tree_model_get(MODEL(dive_list), &nextsibling, DIVE_INDEX, &idx, -1);
+ dive = get_dive(idx);
+ dive->divetrip = new_divetrip;
+ if (dive->when < dive->divetrip->when)
+ dive->divetrip->when = dive->when;
+ (void) move_dive_between_trips(&nextsibling, &parent, &newparent, NULL, FALSE);
+ if (gtk_tree_path_compare(path, treepath) == 0)
+ /* we copied the dive we were called with; we are done */
+ break;
+ }
+ treepath = gtk_tree_model_get_path(MODEL(dive_list), &newparent);
+ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath);
+#ifdef DEBUG_TRIP
+ dump_trip_list();
+#endif
+}
+
+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)
+ insert_trip_before(path);
+ else
+ turn_dive_into_trip(path);
+}
+
+static void remove_from_trip(GtkTreePath *path)
+{
+ GtkTreeIter iter, nextiter, *newiter, parent;
+ GtkTreePath *nextpath;
+ struct dive *dive;
+ int idx;
+
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter))
+ return;
+ /* if this isn't the last dive in a trip we simply split the trip
+ in two right after this dive */
+ nextpath = gtk_tree_path_copy(path);
+ gtk_tree_path_next(nextpath);
+ if (gtk_tree_model_get_iter(MODEL(dive_list), &nextiter, nextpath))
+ insert_trip_before(nextpath);
+ /* now move the dive to the top level, as sibling after its former parent */
+ newiter = move_dive_between_trips(&iter, &parent, NULL, &parent, FALSE);
+ gtk_tree_model_get(MODEL(dive_list), newiter, DIVE_INDEX, &idx, -1);
+ dive = get_dive(idx);
+ if (dive->selected) {
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
+ gtk_tree_selection_select_iter(selection, newiter);
+ }
+ /* if this was the last dive on the trip, remove the trip */
+ if (! gtk_tree_model_iter_has_child(MODEL(dive_list), &parent)) {
+ gtk_tree_store_remove(STORE(dive_list), &parent);
+ delete_trip(FIND_TRIP(dive->divetrip->when));
+ free(dive->divetrip);
+ }
+ /* mark the dive as intentionally at the top level */
+ dive->tripflag = NO_TRIP;
+ dive->divetrip = NULL;
+#ifdef DEBUG_TRIP
+ dump_trip_list();
+#endif
+}
+
+static void remove_rowref_from_trip(gpointer data, gpointer user_data)
+{
+ GtkTreeRowReference *rowref = data;
+ GtkTreePath *path = gtk_tree_row_reference_get_path(rowref);
+ if (path)
+ remove_from_trip(path);
+}
+
+static gboolean add_rowref_if_selected(GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ GList **rowref_list = data;
+ int idx;
+ struct dive *dive;
+
+ gtk_tree_model_get(MODEL(dive_list), iter, DIVE_INDEX, &idx, -1);
+ if (idx >=0 ) {
+ dive = get_dive(idx);
+ if (dive->selected) {
+ /* we need to store the Row References as those
+ stay valid across modifications of the model */
+ GtkTreeRowReference *rowref;
+ rowref = gtk_tree_row_reference_new(TREEMODEL(dive_list), path);
+ *rowref_list = g_list_append(*rowref_list, rowref);
+ }
+ }
+ return FALSE; /* continue foreach loop */
+}
+
+static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path)
+{
+ GtkTreeIter iter, parent;
+ struct dive *dive;
+ int idx;
+
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter))
+ return;
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
+ if (idx < 0 )
+ return;
+ dive = get_dive(idx);
+ if (dive->selected) {
+ /* remove all the selected dives
+ since removing the dives from trips changes the model we need to
+ take the extra step of acquiring rowrefs before actually moving dives */
+ GList *rowref_list = NULL;
+ gtk_tree_model_foreach(MODEL(dive_list), add_rowref_if_selected, &rowref_list);
+ /* We need to walk that list backwards as otherwise
+ the newly insered trips below dives that were
+ removed also mess with the validity */
+ rowref_list = g_list_reverse(rowref_list);
+ g_list_foreach(rowref_list, remove_rowref_from_trip, NULL);
+
+ } else {
+ /* just remove the dive the mouse pointer is on */
+ remove_from_trip(path);
+ }
+}
+
+void remove_trip(GtkTreePath *trippath, gboolean force_no_trip)
+{
+ GtkTreeIter newiter, parent, child, *lastiter = &parent;
+ struct dive *dive, *dive_trip = NULL;
+ int idx;
+ GtkTreePath *childpath;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
+
+ /* what a pain - we can't just move the nodes, we have to
+ * create new ones and delete the existing ones instead */
+ gtk_tree_model_get_iter(MODEL(dive_list), &parent, trippath);
+ childpath = gtk_tree_path_copy(trippath);
+ gtk_tree_path_down(childpath);
+ for (;;) {
+ if( ! gtk_tree_model_get_iter(MODEL(dive_list), &child, childpath))
+ break;
+ gtk_tree_store_insert_after(STORE(dive_list), &newiter, NULL, lastiter);
+ copy_tree_node(&child, &newiter);
+ /* we need to track what was selected */
+ gtk_tree_model_get(MODEL(dive_list), &child, DIVE_INDEX, &idx, -1);
+ dive = get_dive(idx);
+ if (dive->selected)
+ gtk_tree_selection_select_iter(selection, &newiter);
+ if (force_no_trip)
+ dive->tripflag = NO_TRIP;
+ else
+ dive->tripflag = TF_NONE;
+ if (!dive_trip)
+ dive_trip = dive->divetrip;
+ dive->divetrip = NULL;
+ /* this removes the child - now childpath points to the next child */
+ gtk_tree_store_remove(STORE(dive_list), &child);
+ lastiter = &newiter;
+ }
+ /* finally, remove the trip */
+ gtk_tree_store_remove(STORE(dive_list), &parent);
+ delete_trip(FIND_TRIP(dive_trip->when));
+ free(dive_trip);
+#ifdef DEBUG_TRIP
+ dump_trip_list();
+#endif
+}
+
+void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath)
+{
+ remove_trip(trippath, TRUE);
+}
+
+void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath)
+{
+ GtkTreePath *prevpath;
+ GtkTreeIter thistripiter, prevtripiter, newiter, iter;
+ GtkTreeModel *tm = MODEL(dive_list);
+ GList *trip, *prevtrip;
+ time_t when;
+
+ /* this only gets called when we are on a trip and there is another trip right before */
+ prevpath = gtk_tree_path_copy(trippath);
+ gtk_tree_path_prev(prevpath);
+ gtk_tree_model_get_iter(tm, &thistripiter, trippath);
+ gtk_tree_model_get(tm, &thistripiter, DIVE_DATE, &when, -1);
+ trip = find_matching_trip(when);
+ gtk_tree_model_get_iter(tm, &prevtripiter, prevpath);
+ gtk_tree_model_get(tm, &prevtripiter, DIVE_DATE, &when, -1);
+ prevtrip = find_matching_trip(when);
+ while (gtk_tree_model_iter_children(tm, &iter, &thistripiter)) {
+ int idx;
+ gtk_tree_store_insert_before(STORE(dive_list), &newiter, &prevtripiter, NULL);
+ idx = copy_tree_node(&iter, &newiter);
+ gtk_tree_store_remove(STORE(dive_list), &iter);
+ get_dive(idx)->divetrip = DIVE_TRIP(prevtrip);
+ }
+ update_trip_timestamp(&prevtripiter, DIVE_TRIP(prevtrip));
+ free(DIVE_TRIP(trip));
+ delete_trip(trip);
+ gtk_tree_store_remove(STORE(dive_list), &thistripiter);
+}
+
+static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button, GdkEventButton *event)
{
GtkWidget *menu, *menuitem, *image;
char editlabel[] = "Edit dives";
+ GtkTreePath *path, *prevpath, *nextpath;
+ GtkTreeIter iter, previter, nextiter;
+ int idx, previdx, nextidx;
+ struct dive *dive;
+
+ if (!gtk_tree_view_get_path_at_pos(tree_view, event->x, event->y, &path, NULL, NULL, NULL))
+ return;
+ gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
+ gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
menu = gtk_menu_new();
menuitem = gtk_image_menu_item_new_with_label("Add dive");
@@ -1157,12 +1592,69 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
g_signal_connect(menuitem, "activate", G_CALLBACK(add_dive_cb), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
- if (amount_selected) {
- if (amount_selected == 1)
- editlabel[strlen(editlabel) - 1] = '\0';
- menuitem = gtk_menu_item_new_with_label(editlabel);
- g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_cb), model);
+
+ if (idx < 0) {
+ /* mouse pointer is on a trip summary entry */
+ menuitem = gtk_menu_item_new_with_label("Edit Trip Summary");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(edit_trip_cb), path);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ prevpath = gtk_tree_path_copy(path);
+ if (gtk_tree_path_prev(prevpath) &&
+ gtk_tree_model_get_iter(MODEL(dive_list), &previter, prevpath)) {
+ gtk_tree_model_get(MODEL(dive_list), &previter, DIVE_INDEX, &previdx, -1);
+ if (previdx < 0) {
+ menuitem = gtk_menu_item_new_with_label("Merge trip with trip above");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), path);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ }
+ }
+ nextpath = gtk_tree_path_copy(path);
+ gtk_tree_path_next(nextpath);
+ if (gtk_tree_model_get_iter(MODEL(dive_list), &nextiter, nextpath)) {
+ gtk_tree_model_get(MODEL(dive_list), &nextiter, DIVE_INDEX, &nextidx, -1);
+ if (nextidx < 0) {
+ menuitem = gtk_menu_item_new_with_label("Merge trip with trip below");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), nextpath);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ }
+ }
+ menuitem = gtk_menu_item_new_with_label("Remove Trip");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(remove_trip_cb), path);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ } else {
+ dive = get_dive(idx);
+ /* if we right click on selected dive(s), edit those */
+ if (dive->selected) {
+ if (amount_selected == 1)
+ editlabel[strlen(editlabel) - 1] = '\0';
+ 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 {
+ 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);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ }
+ /* 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);
+
+ if (depth == 1 || indices[1] > 0) {
+ menuitem = gtk_menu_item_new_with_label("Add new trip above");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(insert_trip_before_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");
+ else
+ menuitem = gtk_menu_item_new_with_label("Remove dive from trip");
+ g_signal_connect(menuitem, "activate", G_CALLBACK(remove_from_trip_cb), path);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ }
+ }
}
menuitem = gtk_menu_item_new_with_label("Expand all");
g_signal_connect(menuitem, "activate", G_CALLBACK(expand_all_cb), tree_view);
@@ -1178,14 +1670,14 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
static void popup_menu_cb(GtkTreeView *tree_view, gpointer userdata)
{
- popup_divelist_menu(tree_view, GTK_TREE_MODEL(dive_list.model), 0);
+ popup_divelist_menu(tree_view, MODEL(dive_list), 0, NULL);
}
static gboolean button_press_cb(GtkWidget *treeview, GdkEventButton *event, gpointer userdata)
{
/* Right-click? Bring up the menu */
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
- popup_divelist_menu(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(dive_list.model), 3);
+ popup_divelist_menu(GTK_TREE_VIEW(treeview), MODEL(dive_list), 3, event);
return TRUE;
}
return FALSE;
@@ -1276,9 +1768,9 @@ static void sort_column_change_cb(GtkTreeSortable *treeview, gpointer data)
if (dive_list.model != currentmodel) {
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
- gtk_tree_view_set_model(GTK_TREE_VIEW(dive_list.tree_view), GTK_TREE_MODEL(dive_list.model));
+ gtk_tree_view_set_model(GTK_TREE_VIEW(dive_list.tree_view), MODEL(dive_list));
update_column_and_order(colid);
- gtk_tree_model_foreach(GTK_TREE_MODEL(dive_list.model), set_selected, selection);
+ gtk_tree_model_foreach(MODEL(dive_list), set_selected, selection);
} else {
if (order != sortorder[colid]) {
update_column_and_order(colid);
@@ -1293,7 +1785,7 @@ GtkWidget *dive_list_create(void)
dive_list.listmodel = gtk_tree_store_new(DIVELIST_COLUMNS,
G_TYPE_INT, /* index */
G_TYPE_INT, /* nr */
- G_TYPE_INT, /* Date */
+ G_TYPE_LONG, /* Date */
G_TYPE_INT, /* Star rating */
G_TYPE_INT, /* Depth */
G_TYPE_INT, /* Duration */
@@ -1309,7 +1801,7 @@ GtkWidget *dive_list_create(void)
dive_list.treemodel = gtk_tree_store_new(DIVELIST_COLUMNS,
G_TYPE_INT, /* index */
G_TYPE_INT, /* nr */
- G_TYPE_INT, /* Date */
+ G_TYPE_LONG, /* Date */
G_TYPE_INT, /* Star rating */
G_TYPE_INT, /* Depth */
G_TYPE_INT, /* Duration */
@@ -1323,7 +1815,7 @@ GtkWidget *dive_list_create(void)
G_TYPE_STRING /* Location */
);
dive_list.model = dive_list.treemodel;
- dive_list.tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dive_list.model));
+ dive_list.tree_view = gtk_tree_view_new_with_model(TREEMODEL(dive_list));
set_divelist_font(divelist_font);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
@@ -1383,3 +1875,26 @@ int unsaved_changes()
{
return dive_list.changed;
}
+
+void remove_autogen_trips()
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ time_t when;
+ int idx;
+ GList *trip;
+
+ /* start with the first top level entry and walk all of them */
+ path = gtk_tree_path_new_from_string("0");
+ while(gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path)) {
+ gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1);
+ if (idx < 0) {
+ trip = FIND_TRIP(when);
+ if (DIVE_TRIP(trip)->tripflag == IN_TRIP) { /* this was autogen */
+ remove_trip(path, FALSE);
+ continue;
+ }
+ }
+ gtk_tree_path_next(path);
+ }
+}