summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dive.h46
-rw-r--r--divelist.c647
-rw-r--r--divelist.h1
-rw-r--r--dives/test21.xml2
-rw-r--r--dives/test22.xml2
-rw-r--r--dives/test23.xml9
-rw-r--r--gtk-gui.c18
-rw-r--r--info.c62
-rw-r--r--parse-xml.c13
-rw-r--r--save-xml.c4
10 files changed, 707 insertions, 97 deletions
diff --git a/dive.h b/dive.h
index dffe75325..29814c34e 100644
--- a/dive.h
+++ b/dive.h
@@ -241,6 +241,7 @@ extern const char *tripflag_names[NUM_TRIPFLAGS];
struct dive {
int number;
tripflag_t tripflag;
+ struct dive *divetrip;
int selected;
time_t when;
char *location;
@@ -270,49 +271,63 @@ extern gboolean autogroup;
#define UNGROUPED_DIVE(_dive) ((_dive)->tripflag == NO_TRIP)
#define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP)
-#define NEXT_TRIP(_entry, _list) ((_entry) ? g_list_next(_entry) : (_list))
-#define PREV_TRIP(_entry, _list) ((_entry) ? g_list_previous(_entry) : g_list_last(_list))
+#define NEXT_TRIP(_entry) ((_entry) ? g_list_next(_entry) : (dive_trip_list))
+#define PREV_TRIP(_entry) ((_entry) ? g_list_previous(_entry) : g_list_last(dive_trip_list))
#define DIVE_TRIP(_trip) ((struct dive *)(_trip)->data)
#define DIVE_FITS_TRIP(_dive, _dive_trip) ((_dive_trip)->when - TRIP_THRESHOLD <= (_dive)->when)
+/* compare two dives by when they happened */
static inline int dive_date_cmp(gconstpointer _a, gconstpointer _b) {
- return ((struct dive *)(_a))->when - ((struct dive *)(_b))->when;
+ return ((struct dive *)_a)->when - ((struct dive *)_b)->when;
}
-#define FIND_TRIP(_trip, _list) g_list_find_custom((_list), (_trip), dive_date_cmp)
+/* returns 0 if the dive happened exactly at time */
+static inline int dive_when_find(gconstpointer _dive, gconstpointer _time) {
+ return ((struct dive *)_dive)->when != (time_t) _time;
+}
+
+#define FIND_TRIP(_when) g_list_find_custom(dive_trip_list, (gconstpointer)(_when), dive_when_find)
#ifdef DEBUG_TRIP
static void dump_trip_list(void)
{
GList *p = NULL;
int i=0;
- while ((p = NEXT_TRIP(p, dive_trip_list))) {
+ while ((p = NEXT_TRIP(p))) {
struct tm *tm = gmtime(&DIVE_TRIP(p)->when);
- printf("trip %d to \"%s\" on %04u-%02u-%02u\n", ++i, DIVE_TRIP(p)->location,
- tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday);
+ printf("trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u\n", ++i, DIVE_TRIP(p)->location,
+ tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
printf("-----\n");
}
#endif
-/* insert the trip into the list - but ensure you don't have two trips
- * for the same date; but if you have, make sure you don't keep the
- * one with less information */
-static inline GList *insert_trip(struct dive *_trip, GList *_list)
+/* insert the trip into the dive_trip_list - but ensure you don't have
+ * two trips for the same date; but if you have, make sure you don't
+ * keep the one with less information */
+static void inline insert_trip(struct dive **trip)
{
- GList *result = FIND_TRIP(_trip, _list);
+ struct dive *dive_trip = *trip;
+ GList *result = FIND_TRIP(dive_trip->when);
if (result) {
if (! DIVE_TRIP(result)->location)
- DIVE_TRIP(result)->location = _trip->location;
+ DIVE_TRIP(result)->location = dive_trip->location;
+ *trip = DIVE_TRIP(result);
} else {
- result = g_list_insert_sorted((_list), (_trip), dive_date_cmp);
+ dive_trip_list = g_list_insert_sorted(dive_trip_list, dive_trip, dive_date_cmp);
}
#ifdef DEBUG_TRIP
dump_trip_list();
#endif
- return result;
}
+static inline void delete_trip(GList *trip)
+{
+ dive_trip_list = g_list_delete_link(dive_trip_list, trip);
+#ifdef DEBUG_TRIP
+ dump_trip_list();
+#endif
+}
/*
* We keep our internal data in well-specified units, but
* the input and output may come in some random format. This
@@ -421,6 +436,7 @@ extern void remember_event(const char *eventname);
extern void evn_foreach(void (*callback)(const char *, int *, void *), void *data);
extern int add_new_dive(struct dive *dive);
+extern gboolean edit_trip(struct dive *trip);
extern int edit_dive_info(struct dive *dive);
extern int edit_multi_dive_info(struct dive *single_dive);
extern void dive_list_update_dives(void);
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);
+ }
+}
diff --git a/divelist.h b/divelist.h
index c170941db..45c1a18f8 100644
--- a/divelist.h
+++ b/divelist.h
@@ -10,4 +10,5 @@ extern void flush_divelist(struct dive *);
extern void update_cylinder_related_info(struct dive *);
extern void mark_divelist_changed(int);
extern int unsaved_changes(void);
+extern void remove_autogen_trips(void);
#endif
diff --git a/dives/test21.xml b/dives/test21.xml
index 5f5f6c981..ce6b82f35 100644
--- a/dives/test21.xml
+++ b/dives/test21.xml
@@ -1,6 +1,6 @@
<dives>
<program name='subsurface' version='1'></program>
-<trip date='2011-12-02' />
+<trip date='2011-12-02' time='14:00:00' />
<dive number='20' tripflag='INTRIP' date='2011-12-02' time='14:00:00' duration='30:00 min'>
<depth max='20.0 m' mean='15.0 m' />
<location>20th test dive - this should be in a trip with same location</location>
diff --git a/dives/test22.xml b/dives/test22.xml
index a61032327..e8112287d 100644
--- a/dives/test22.xml
+++ b/dives/test22.xml
@@ -1,6 +1,6 @@
<dives>
<program name='subsurface' version='1'></program>
-<trip date='2011-12-02' location='trip location' />
+<trip date='2011-12-02' location='trip location' time='15:00:00' />
<dive number='21' tripflag='INTRIP' date='2011-12-02' time='15:00:00' duration='30:00 min'>
<depth max='20.0 m' mean='15.0 m' />
<location>21st test dive - this should be in a trip with a trip location</location>
diff --git a/dives/test23.xml b/dives/test23.xml
index c61ad2db9..defdfdd90 100644
--- a/dives/test23.xml
+++ b/dives/test23.xml
@@ -1,7 +1,12 @@
<dives>
<program name='subsurface' version='1'></program>
-<trip date='2011-12-02' location='trip location' />
-<dive number='22' tripflag='NOTRIP' date='2011-12-09' time='6:00:00' duration='30:00 min'>
+<trip date='2011-12-02' time='6:00:00' location='trip location' />
+<dive number='23' tripflag='INTRIP' date='2011-12-02' time='6:00:00' duration='30:00 min'>
+ <depth max='20.0 m' mean='15.0 m' />
+ <location>23rd test dive - this should be in a trip</location>
+ <notes>We are testing that the NOTRIP flag works</notes>
+</dive>
+<dive number='22' tripflag='NOTRIP' date='2011-12-03' time='7:00:00' duration='30:00 min'>
<depth max='20.0 m' mean='15.0 m' />
<location>22nd test dive - this should not be in a trip</location>
<notes>We are testing that the NOTRIP flag works</notes>
diff --git a/gtk-gui.c b/gtk-gui.c
index 7db777ab9..a2f130ac2 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -634,6 +634,14 @@ static void selectevents_dialog(GtkWidget *w, gpointer data)
gtk_widget_destroy(dialog);
}
+static void autogroup_cb(GtkWidget *w, gpointer data)
+{
+ autogroup = !autogroup;
+ if (! autogroup)
+ remove_autogen_trips();
+ dive_list_update_dives();
+}
+
static void renumber_dialog(GtkWidget *w, gpointer data)
{
int result;
@@ -757,10 +765,15 @@ static GtkActionEntry menu_items[] = {
{ "ViewProfile", NULL, "Profile", CTRLCHAR "2", NULL, G_CALLBACK(view_profile) },
{ "ViewInfo", NULL, "Info", CTRLCHAR "3", NULL, G_CALLBACK(view_info) },
{ "ViewThree", NULL, "Three", CTRLCHAR "4", NULL, G_CALLBACK(view_three) },
- { "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom) },
};
static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
+static GtkToggleActionEntry toggle_items[] = {
+ { "Autogroup", NULL, "Autogroup", NULL, NULL, G_CALLBACK(autogroup_cb), FALSE },
+ { "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom), FALSE },
+};
+static gint ntoggle_items = sizeof (toggle_items) / sizeof (toggle_items[0]);
+
static const gchar* ui_string = " \
<ui> \
<menubar name=\"MainMenu\"> \
@@ -779,6 +792,7 @@ static const gchar* ui_string = " \
<menuitem name=\"Add Dive\" action=\"AddDive\" /> \
<separator name=\"Separator\"/> \
<menuitem name=\"Renumber\" action=\"Renumber\" /> \
+ <menuitem name=\"Autogroup\" action=\"Autogroup\" /> \
<menuitem name=\"Toggle Zoom\" action=\"ToggleZoom\" /> \
<menu name=\"View\" action=\"ViewMenuAction\"> \
<menuitem name=\"List\" action=\"ViewList\" /> \
@@ -801,6 +815,8 @@ static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager)
{
GtkActionGroup *action_group = gtk_action_group_new("Menu");
gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
+ toggle_items[0].is_active = autogroup;
+ gtk_action_group_add_toggle_actions(action_group, toggle_items, ntoggle_items, 0);
gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
GError* error = 0;
diff --git a/info.c b/info.c
index d9379ac68..3efb40cf8 100644
--- a/info.c
+++ b/info.c
@@ -415,6 +415,24 @@ static void save_dive_info_changes(struct dive *dive, struct dive *master, struc
}
}
+static void dive_trip_widget(GtkWidget *box, struct dive *trip, struct dive_info *info)
+{
+ GtkWidget *hbox, *label;
+ char buffer[80] = "Edit trip summary";
+
+ label = gtk_label_new(buffer);
+ gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0);
+
+ info->location = text_entry(box, "Location", location_list, trip->location);
+
+ hbox = gtk_hbox_new(FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0);
+
+ info->notes = text_view(box, "Notes", READ_WRITE);
+ if (trip->notes && *trip->notes)
+ gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), trip->notes, -1);
+}
+
static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info, gboolean multi)
{
GtkWidget *hbox, *label, *frame, *equipment;
@@ -489,7 +507,49 @@ void update_equipment_data(struct dive *dive, struct dive *master)
memcpy(dive->weightsystem, master->weightsystem, WS_BYTES);
}
-/* A negative index means "all selected" */
+gboolean edit_trip(struct dive *trip)
+{
+ GtkWidget *dialog, *vbox;
+ int success;
+ gboolean changed = FALSE;
+ char *old_text, *new_text;
+ struct dive_info info;
+
+ memset(&info, 0, sizeof(struct dive_info));
+ dialog = gtk_dialog_new_with_buttons("Edit Trip Info",
+ GTK_WINDOW(main_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ NULL);
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ dive_trip_widget(vbox, trip, &info);
+ gtk_widget_show_all(dialog);
+ success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT;
+ if (success) {
+ /* we need to store the edited location and notes */
+ new_text = get_combo_box_entry_text(info.location, &trip->location, trip->location);
+ if (new_text) {
+ add_location(new_text);
+ changed = TRUE;
+ }
+ if (info.notes) {
+ old_text = trip->notes;
+ trip->notes = get_text(info.notes);
+ if (text_changed(old_text, trip->notes))
+ changed = TRUE;
+ if (old_text)
+ g_free(old_text);
+ }
+ if (changed) {
+ mark_divelist_changed(TRUE);
+ flush_divelist(trip);
+ }
+ }
+ gtk_widget_destroy(dialog);
+ return changed;
+}
+
int edit_multi_dive_info(struct dive *single_dive)
{
int success;
diff --git a/parse-xml.c b/parse-xml.c
index 59e9278ad..1c4db7d9d 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -39,11 +39,6 @@ void record_dive(struct dive *dive)
dive_table.nr = nr+1;
}
-void record_trip(struct dive *trip)
-{
- dive_trip_list = insert_trip(trip, dive_trip_list);
-}
-
static void delete_dive_renumber(struct dive **dives, int i, int nr)
{
struct dive *dive = dives[i];
@@ -1165,10 +1160,10 @@ static void try_to_fill_trip(struct dive **divep, const char *name, char *buf)
struct dive *dive = *divep;
- if (MATCH(".date", divedate, &dive->when)) {
- dive->when = utc_mktime(&cur_tm);
+ if (MATCH(".date", divedate, &dive->when))
+ return;
+ if (MATCH(".time", divetime, &dive->when))
return;
- }
if (MATCH(".location", utf8_string, &dive->location))
return;
if (MATCH(".notes", utf8_string, &dive->notes))
@@ -1213,7 +1208,7 @@ static void trip_end(void)
{
if (!cur_trip)
return;
- record_trip(cur_trip);
+ insert_trip(&cur_trip);
cur_trip = NULL;
}
diff --git a/save-xml.c b/save-xml.c
index b797475e5..3bea2adfa 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -291,6 +291,8 @@ static void save_trip(FILE *f, struct dive *trip)
fprintf(f, "<trip");
fprintf(f, " date='%04u-%02u-%02u'",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
+ fprintf(f, " time='%02u:%02u:%02u'",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
if (trip->location)
show_utf8(f, trip->location, " location=\'","\'", 1);
fprintf(f, " />\n");
@@ -341,7 +343,7 @@ void save_dives(const char *filename)
fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION);
/* save the trips */
- while ((trip = NEXT_TRIP(trip, dive_trip_list)) != 0)
+ while ((trip = NEXT_TRIP(trip)) != NULL)
save_trip(f, trip->data);
/* save the dives */