diff options
Diffstat (limited to 'divelist.c')
-rw-r--r-- | divelist.c | 2349 |
1 files changed, 50 insertions, 2299 deletions
diff --git a/divelist.c b/divelist.c index 198e2d643..f574a31fd 100644 --- a/divelist.c +++ b/divelist.c @@ -1,14 +1,36 @@ /* divelist.c */ -/* this creates the UI for the dive list - - * controlled through the following interfaces: +/* core logic for the dive list - + * accessed through the following interfaces: * - * void flush_divelist(struct dive *dive) - * GtkWidget dive_list_create(void) - * void dive_list_update_dives(void) - * void update_dive_list_units(void) - * void set_divelist_font(const char *font) + * dive_trip_t *dive_trip_list; + * unsigned int amount_selected; + * void dump_selection(void) + * dive_trip_t *find_trip_by_idx(int idx) + * int trip_has_selected_dives(dive_trip_t *trip) + * void get_dive_gas(struct dive *dive, int *o2_p, int *he_p, int *o2low_p) + * int total_weight(struct dive *dive) + * int get_divenr(struct dive *dive) + * double init_decompression(struct dive *dive) + * void update_cylinder_related_info(struct dive *dive) + * void get_location(struct dive *dive, char **str) + * void get_cylinder(struct dive *dive, char **str) + * void get_suit(struct dive *dive, char **str) + * void dump_trip_list(void) + * dive_trip_t *find_matching_trip(timestamp_t when) + * void insert_trip(dive_trip_t **dive_trip_p) + * void remove_dive_from_trip(struct dive *dive) + * void add_dive_to_trip(struct dive *dive, dive_trip_t *trip) + * dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) + * void autogroup_dives(void) + * void clear_trip_indexes(void) + * void delete_single_dive(int idx) + * void add_single_dive(int idx, struct dive *dive) + * void merge_dive_index(int i, struct dive *a) + * void select_dive(int idx) + * void deselect_dive(int idx) * void mark_divelist_changed(int changed) * int unsaved_changes() + * void remove_autogen_trips() */ #include <unistd.h> #include <stdio.h> @@ -25,99 +47,16 @@ #include <libxslt/transform.h> #endif -#include "divelist.h" #include "dive.h" +#include "divelist.h" #include "display.h" -#include "display-gtk.h" #include "webservice.h" -#include <gdk-pixbuf/gdk-pixdata.h> -#include "satellite.h" - -struct DiveList { - GtkWidget *tree_view; - GtkWidget *container_widget; - GtkTreeStore *model, *listmodel, *treemodel; - GtkTreeViewColumn *nr, *date, *stars, *depth, *duration, *location; - GtkTreeViewColumn *temperature, *cylinder, *totalweight, *suit, *nitrox, *sac, *otu, *maxcns; - int changed; -}; - -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) +static short dive_list_changed = FALSE; dive_trip_t *dive_trip_list; -gboolean autogroup = FALSE; -static gboolean in_set_cursor = FALSE; -static gboolean set_selected(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer data); - -/* - * The dive list has the dive data in both string format (for showing) - * and in "raw" format (for sorting purposes) - */ -enum { - DIVE_INDEX = 0, - DIVE_NR, /* int: dive->nr */ - DIVE_DATE, /* timestamp_t: dive->when */ - DIVE_RATING, /* int: 0-5 stars */ - DIVE_DEPTH, /* int: dive->maxdepth in mm */ - DIVE_DURATION, /* int: in seconds */ - DIVE_TEMPERATURE, /* int: in mkelvin */ - DIVE_TOTALWEIGHT, /* int: in grams */ - DIVE_SUIT, /* "wet, 3mm" */ - DIVE_CYLINDER, - DIVE_NITROX, /* int: dummy */ - DIVE_SAC, /* int: in ml/min */ - DIVE_OTU, /* int: in OTUs */ - DIVE_MAXCNS, /* int: in % */ - DIVE_LOCATION, /* "2nd Cathedral, Lanai" */ - DIVE_LOC_ICON, /* pixbuf for gps icon */ - DIVELIST_COLUMNS -}; - -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) -{ - char *location; - int idx, nr, duration; - struct dive *dive; - timestamp_t when; - struct tm tm; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DATE, &when, - DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1); - utc_mkdate(when, &tm); - 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); - else - printf("without matching dive\n"); - - free(location); - - return FALSE; -} -static void dump_model(GtkListStore *store) -{ - gtk_tree_model_foreach(GTK_TREE_MODEL(store), dump_model_entry, NULL); - printf("\n---\n\n"); -} -#endif +unsigned int amount_selected; #if DEBUG_SELECTION_TRACKING void dump_selection(void) @@ -134,44 +73,7 @@ void dump_selection(void) } #endif -/* when subsurface starts we want to have the last dive selected. So we simply - walk to the first leaf (and skip the summary entries - which have negative - DIVE_INDEX) */ -static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) -{ - GtkTreeIter parent; - GtkTreePath *tpath; - - while (*diveidx < 0) { - memcpy(&parent, iter, sizeof(parent)); - tpath = gtk_tree_model_get_path(model, &parent); - if (!gtk_tree_model_iter_children(model, iter, &parent)) { - /* we should never have a parent without child */ - gtk_tree_path_free(tpath); - 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_path_free(tpath); - gtk_tree_model_get(model, iter, DIVE_INDEX, diveidx, -1); - } -} - -static struct dive *dive_from_path(GtkTreePath *path) -{ - GtkTreeIter iter; - int idx; - - if (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); - } else { - return NULL; - } - -} - -static dive_trip_t *find_trip_by_idx(int idx) +dive_trip_t *find_trip_by_idx(int idx) { dive_trip_t *trip = dive_trip_list; @@ -186,48 +88,7 @@ static dive_trip_t *find_trip_by_idx(int idx) return NULL; } -static int get_path_index(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 idx; -} - -/* make sure that if we expand a summary row that is selected, the children show - up as selected, too */ -static void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) -{ - GtkTreeIter child; - GtkTreeModel *model = MODEL(dive_list); - GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - dive_trip_t *trip; - - trip = find_trip_by_idx(get_path_index(path)); - if (!trip) - return; - - trip->expanded = 1; - if (!gtk_tree_model_iter_children(model, &child, iter)) - return; - - do { - int idx; - struct dive *dive; - - gtk_tree_model_get(model, &child, DIVE_INDEX, &idx, -1); - dive = get_dive(idx); - - if (dive->selected) - gtk_tree_selection_select_iter(selection, &child); - else - gtk_tree_selection_unselect_iter(selection, &child); - } while (gtk_tree_model_iter_next(model, &child)); -} - -static int trip_has_selected_dives(dive_trip_t *trip) +int trip_has_selected_dives(dive_trip_t *trip) { struct dive *dive; for (dive = trip->dives; dive; dive = dive->next) { @@ -237,216 +98,6 @@ static int trip_has_selected_dives(dive_trip_t *trip) return 0; } -/* Make sure that if we collapse a summary row with any selected children, the row - shows up as selected too */ -static void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) -{ - dive_trip_t *trip; - GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - - trip = find_trip_by_idx(get_path_index(path)); - if (!trip) - return; - - trip->expanded = 0; - if (trip_has_selected_dives(trip)) { - gtk_tree_selection_select_iter(selection, iter); - trip->selected = 1; - } -} - -const char *star_strings[] = { - ZERO_STARS, - ONE_STARS, - TWO_STARS, - THREE_STARS, - FOUR_STARS, - FIVE_STARS -}; - -static void star_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int nr_stars, idx; - char buffer[40]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_RATING, &nr_stars, -1); - if (idx < 0) { - *buffer = '\0'; - } else { - if (nr_stars < 0 || nr_stars > 5) - nr_stars = 0; - snprintf(buffer, sizeof(buffer), "%s", star_strings[nr_stars]); - } - g_object_set(renderer, "text", buffer, NULL); -} - -static void date_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int idx, nr; - struct tm tm; - timestamp_t when; - /* this should be enought for most languages. if not increase the value. */ - char buffer[256]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1); - nr = gtk_tree_model_iter_n_children(model, iter); - - utc_mkdate(when, &tm); - if (idx < 0) { - snprintf(buffer, sizeof(buffer), - /*++GETTEXT 60 char buffer weekday, monthname, day of month, year, nr dives */ - ngettext("Trip %1$s, %2$s %3$d, %4$d (%5$d dive)", - "Trip %1$s, %2$s %3$d, %4$d (%5$d dives)", nr), - weekday(tm.tm_wday), - monthname(tm.tm_mon), - tm.tm_mday, tm.tm_year + 1900, - nr); - } else { - snprintf(buffer, sizeof(buffer), - /*++GETTEXT 60 char buffer weekday, monthname, day of month, year, hour:min */ - _("%1$s, %2$s %3$d, %4$d %5$02d:%6$02d"), - weekday(tm.tm_wday), - monthname(tm.tm_mon), - tm.tm_mday, tm.tm_year + 1900, - tm.tm_hour, tm.tm_min); - } - g_object_set(renderer, "text", buffer, NULL); -} - -static void depth_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int depth, integer, frac, len, idx; - char buffer[40]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DEPTH, &depth, -1); - - if (idx < 0) { - *buffer = '\0'; - } else { - switch (prefs.units.length) { - case METERS: - /* To tenths of meters */ - depth = (depth + 49) / 100; - integer = depth / 10; - frac = depth % 10; - if (integer < 20) - break; - if (frac >= 5) - integer++; - frac = -1; - break; - case FEET: - integer = mm_to_feet(depth) + 0.5; - frac = -1; - break; - default: - return; - } - len = snprintf(buffer, sizeof(buffer), "%d", integer); - if (frac >= 0) - len += snprintf(buffer+len, sizeof(buffer)-len, ".%d", frac); - } - g_object_set(renderer, "text", buffer, NULL); -} - -static void duration_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - unsigned int sec; - int idx; - char buffer[40]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DURATION, &sec, -1); - if (idx < 0) - *buffer = '\0'; - else - snprintf(buffer, sizeof(buffer), "%d:%02d", sec / 60, sec % 60); - - g_object_set(renderer, "text", buffer, NULL); -} - -static void temperature_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int value, idx; - char buffer[80]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_TEMPERATURE, &value, -1); - - *buffer = 0; - if (idx >= 0 && value) { - double deg; - switch (prefs.units.temperature) { - case CELSIUS: - deg = mkelvin_to_C(value); - break; - case FAHRENHEIT: - deg = mkelvin_to_F(value); - break; - default: - return; - } - snprintf(buffer, sizeof(buffer), "%.1f", deg); - } - - g_object_set(renderer, "text", buffer, NULL); -} - -static void gpsicon_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int idx; - GdkPixbuf *icon; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_LOC_ICON, &icon, -1); - g_object_set(renderer, "pixbuf", icon, NULL); -} - -static void nr_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - 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) { - *buffer = '\0'; - } 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); -} - /* * Get "maximal" dive gas for a dive. * Rules: @@ -454,7 +105,7 @@ static void nr_data_func(GtkTreeViewColumn *col, * - Nitrox trumps air (even if hypoxic) * These are the same rules as the inter-dive sorting rules. */ -static void get_dive_gas(struct dive *dive, int *o2_p, int *he_p, int *o2low_p) +void get_dive_gas(struct dive *dive, int *o2_p, int *he_p, int *o2low_p) { int i; int maxo2 = -1, maxhe = -1, mino2 = 1000; @@ -535,165 +186,6 @@ int total_weight(struct dive *dive) return total_grams; } -static void weight_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int indx, decimals; - double value; - char buffer[80]; - struct dive *dive; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &indx, -1); - dive = get_dive(indx); - value = get_weight_units(total_weight(dive), &decimals, NULL); - if (value == 0.0) - *buffer = '\0'; - else - snprintf(buffer, sizeof(buffer), "%.*f", decimals, value); - - g_object_set(renderer, "text", buffer, NULL); -} - -static gint nitrox_sort_func(GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data) -{ - int index_a, index_b; - struct dive *a, *b; - int a_o2, b_o2; - int a_he, b_he; - int a_o2low, b_o2low; - - gtk_tree_model_get(model, iter_a, DIVE_INDEX, &index_a, -1); - gtk_tree_model_get(model, iter_b, DIVE_INDEX, &index_b, -1); - a = get_dive(index_a); - b = get_dive(index_b); - get_dive_gas(a, &a_o2, &a_he, &a_o2low); - get_dive_gas(b, &b_o2, &b_he, &b_o2low); - - /* Sort by Helium first, O2 second */ - if (a_he == b_he) { - if (a_o2 == b_o2) - return a_o2low - b_o2low; - return a_o2 - b_o2; - } - return a_he - b_he; -} - -#define UTF8_ELLIPSIS "\xE2\x80\xA6" - -static void nitrox_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int idx, o2, he, o2low; - char buffer[80]; - struct dive *dive; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - *buffer = '\0'; - goto exit; - } - dive = get_dive(idx); - get_dive_gas(dive, &o2, &he, &o2low); - o2 = (o2 + 5) / 10; - he = (he + 5) / 10; - o2low = (o2low + 5) / 10; - - if (he) - snprintf(buffer, sizeof(buffer), "%d/%d", o2, he); - else if (o2) - if (o2 == o2low) - snprintf(buffer, sizeof(buffer), "%d", o2); - else - snprintf(buffer, sizeof(buffer), "%d" UTF8_ELLIPSIS "%d", o2low, o2); - else - strcpy(buffer, _("air")); -exit: - g_object_set(renderer, "text", buffer, NULL); -} - -/* Render the SAC data (integer value of "ml / min") */ -static void sac_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int value, idx; - const char *fmt; - char buffer[16]; - double sac; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_SAC, &value, -1); - - if (idx < 0 || !value) { - *buffer = '\0'; - goto exit; - } - - sac = value / 1000.0; - switch (prefs.units.volume) { - case LITER: - fmt = "%4.1f"; - break; - case CUFT: - fmt = "%4.2f"; - sac = ml_to_cuft(sac * 1000); - break; - } - snprintf(buffer, sizeof(buffer), fmt, sac); -exit: - g_object_set(renderer, "text", buffer, NULL); -} - -/* Render the OTU data (integer value of "OTU") */ -static void otu_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int value, idx; - char buffer[16]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_OTU, &value, -1); - - if (idx < 0 || !value) - *buffer = '\0'; - else - snprintf(buffer, sizeof(buffer), "%d", value); - - g_object_set(renderer, "text", buffer, NULL); -} - -/* Render the CNS data (in full %) */ -static void cns_data_func(GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - int value, idx; - char buffer[16]; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_MAXCNS, &value, -1); - - if (idx < 0 || !value) - *buffer = '\0'; - else - snprintf(buffer, sizeof(buffer), "%d%%", value); - - g_object_set(renderer, "text", buffer, NULL); -} - static int active_o2(struct dive *dive, struct divecomputer *dc, duration_t time) { int o2permille = dive->cylinder[0].gasmix.o2.permille; @@ -806,7 +298,7 @@ static void add_dive_to_deco(struct dive *dive) } } -static int get_divenr(struct dive *dive) +int get_divenr(struct dive *dive) { int divenr = -1; while (++divenr < dive_table.nr && get_dive(divenr) != dive) @@ -913,157 +405,27 @@ static void get_string(char **str, const char *s) *str = n; } -static void get_location(struct dive *dive, char **str) +void get_location(struct dive *dive, char **str) { get_string(str, dive->location); } -static void get_cylinder(struct dive *dive, char **str) +void get_cylinder(struct dive *dive, char **str) { get_string(str, dive->cylinder[0].type.description); } -static void get_suit(struct dive *dive, char **str) +void get_suit(struct dive *dive, char **str) { get_string(str, dive->suit); } -GdkPixbuf *get_gps_icon(void) -{ - return gdk_pixbuf_from_pixdata(&satellite_pixbuf, TRUE, NULL); -} - -static GdkPixbuf *get_gps_icon_for_dive(struct dive *dive) -{ - if (dive_has_gps_location(dive)) - return get_gps_icon(); - else - return NULL; -} - -/* - * Set up anything that could have changed due to editing - * of dive information; we need to do this for both models, - * so we simply call set_one_dive again with the non-current model - */ -/* forward declaration for recursion */ -static gboolean set_one_dive(GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data); - -static void fill_one_dive(struct dive *dive, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - char *location, *cylinder, *suit; - GtkTreeModel *othermodel; - GdkPixbuf *icon; - - get_cylinder(dive, &cylinder); - get_location(dive, &location); - get_suit(dive, &suit); - icon = get_gps_icon_for_dive(dive); - gtk_tree_store_set(GTK_TREE_STORE(model), iter, - DIVE_NR, dive->number, - DIVE_LOCATION, location, - DIVE_LOC_ICON, icon, - DIVE_CYLINDER, cylinder, - DIVE_RATING, dive->rating, - DIVE_SAC, dive->sac, - DIVE_OTU, dive->otu, - DIVE_MAXCNS, dive->maxcns, - DIVE_TOTALWEIGHT, total_weight(dive), - DIVE_SUIT, suit, - -1); - - if (icon) - g_object_unref(icon); - free(location); - free(cylinder); - free(suit); - - if (model == TREEMODEL(dive_list)) - othermodel = LISTMODEL(dive_list); - else - othermodel = TREEMODEL(dive_list); - if (othermodel != MODEL(dive_list)) - /* recursive call */ - gtk_tree_model_foreach(othermodel, set_one_dive, dive); -} - -static gboolean set_one_dive(GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - int idx; - struct dive *dive; - - /* Get the dive number */ - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - if (idx < 0) - return FALSE; - dive = get_dive(idx); - if (!dive) - return TRUE; - if (data && dive != data) - return FALSE; - - fill_one_dive(dive, model, iter); - return dive == data; -} - -void flush_divelist(struct dive *dive) -{ - GtkTreeModel *model = MODEL(dive_list); - - gtk_tree_model_foreach(model, set_one_dive, dive); -} - -void set_divelist_font(const char *font) -{ - PangoFontDescription *font_desc = pango_font_description_from_string(font); - gtk_widget_modify_font(dive_list.tree_view, font_desc); - pango_font_description_free(font_desc); -} - -void update_dive_list_units(void) -{ - const char *unit; - GtkTreeModel *model = MODEL(dive_list); - - (void) get_depth_units(0, NULL, &unit); - gtk_tree_view_column_set_title(dive_list.depth, unit); - - (void) get_temp_units(0, &unit); - gtk_tree_view_column_set_title(dive_list.temperature, unit); - - (void) get_weight_units(0, NULL, &unit); - gtk_tree_view_column_set_title(dive_list.totalweight, unit); - - gtk_tree_model_foreach(model, set_one_dive, NULL); -} - -void update_dive_list_col_visibility(void) -{ - gtk_tree_view_column_set_visible(dive_list.cylinder, prefs.visible_cols.cylinder); - gtk_tree_view_column_set_visible(dive_list.temperature, prefs.visible_cols.temperature); - gtk_tree_view_column_set_visible(dive_list.totalweight, prefs.visible_cols.totalweight); - gtk_tree_view_column_set_visible(dive_list.suit, prefs.visible_cols.suit); - gtk_tree_view_column_set_visible(dive_list.nitrox, prefs.visible_cols.nitrox); - gtk_tree_view_column_set_visible(dive_list.sac, prefs.visible_cols.sac); - gtk_tree_view_column_set_visible(dive_list.otu, prefs.visible_cols.otu); - gtk_tree_view_column_set_visible(dive_list.maxcns, prefs.visible_cols.maxcns); - return; -} - /* * helper functions for dive_trip handling */ #ifdef DEBUG_TRIP -static void dump_trip_list(void) +void dump_trip_list(void) { dive_trip_t *trip; int i=0; @@ -1086,7 +448,7 @@ static void dump_trip_list(void) #endif /* this finds the last trip that at or before the time given */ -static dive_trip_t *find_matching_trip(timestamp_t when) +dive_trip_t *find_matching_trip(timestamp_t when) { dive_trip_t *trip = dive_trip_list; @@ -1181,7 +543,7 @@ static void find_new_trip_start_time(dive_trip_t *trip) trip->when = when; } -static void remove_dive_from_trip(struct dive *dive) +void remove_dive_from_trip(struct dive *dive) { struct dive *next, **pprev; dive_trip_t *trip = dive->divetrip; @@ -1226,7 +588,7 @@ void add_dive_to_trip(struct dive *dive, dive_trip_t *trip) trip->when = dive->when; } -static dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) +dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) { dive_trip_t *dive_trip = calloc(sizeof(dive_trip_t),1); dive_trip->when = dive->when; @@ -1242,7 +604,7 @@ static dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) /* * Walk the dives from the oldest dive, and see if we can autogroup them */ -static void autogroup_dives(void) +void autogroup_dives(void) { int i; struct dive *dive, *lastdive = NULL; @@ -1280,7 +642,7 @@ static void autogroup_dives(void) #endif } -static void clear_trip_indexes(void) +void clear_trip_indexes(void) { dive_trip_t *trip; @@ -1288,571 +650,6 @@ static void clear_trip_indexes(void) trip->index = 0; } -/* Select the iter asked for, and set the keyboard focus on it */ -static void go_to_iter(GtkTreeSelection *selection, GtkTreeIter *iter); -static void fill_dive_list(void) -{ - int i, trip_index = 0; - GtkTreeIter iter, parent_iter, lookup, *parent_ptr = NULL; - GtkTreeStore *liststore, *treestore; - GdkPixbuf *icon; - - /* Do we need to create any dive groups automatically? */ - if (autogroup) - autogroup_dives(); - - treestore = TREESTORE(dive_list); - liststore = LISTSTORE(dive_list); - - clear_trip_indexes(); - - i = dive_table.nr; - while (--i >= 0) { - struct dive *dive = get_dive(i); - dive_trip_t *trip = dive->divetrip; - - if (!trip) { - parent_ptr = NULL; - } else if (!trip->index) { - trip->index = ++trip_index; - - /* Create new trip entry */ - gtk_tree_store_append(treestore, &parent_iter, NULL); - parent_ptr = &parent_iter; - - /* a duration of 0 (and negative index) identifies a group */ - gtk_tree_store_set(treestore, parent_ptr, - DIVE_INDEX, -trip_index, - DIVE_DATE, trip->when, - DIVE_LOCATION, trip->location, - DIVE_DURATION, 0, - -1); - } else { - int idx, ok; - GtkTreeModel *model = TREEMODEL(dive_list); - - parent_ptr = NULL; - ok = gtk_tree_model_get_iter_first(model, &lookup); - while (ok) { - gtk_tree_model_get(model, &lookup, DIVE_INDEX, &idx, -1); - if (idx == -trip->index) { - parent_ptr = &lookup; - break; - } - ok = gtk_tree_model_iter_next(model, &lookup); - } - } - - /* store dive */ - update_cylinder_related_info(dive); - gtk_tree_store_append(treestore, &iter, parent_ptr); - icon = get_gps_icon_for_dive(dive); - gtk_tree_store_set(treestore, &iter, - DIVE_INDEX, i, - DIVE_NR, dive->number, - DIVE_DATE, dive->when, - DIVE_DEPTH, dive->maxdepth, - DIVE_DURATION, dive->duration.seconds, - DIVE_LOCATION, dive->location, - DIVE_LOC_ICON, icon, - DIVE_RATING, dive->rating, - DIVE_TEMPERATURE, dive->watertemp.mkelvin, - DIVE_SAC, 0, - -1); - if (icon) - g_object_unref(icon); - gtk_tree_store_append(liststore, &iter, NULL); - gtk_tree_store_set(liststore, &iter, - DIVE_INDEX, i, - DIVE_NR, dive->number, - DIVE_DATE, dive->when, - DIVE_DEPTH, dive->maxdepth, - DIVE_DURATION, dive->duration.seconds, - DIVE_LOCATION, dive->location, - DIVE_LOC_ICON, icon, - DIVE_RATING, dive->rating, - DIVE_TEMPERATURE, dive->watertemp.mkelvin, - DIVE_TOTALWEIGHT, 0, - DIVE_SUIT, dive->suit, - DIVE_SAC, 0, - -1); - } - - update_dive_list_units(); - if (amount_selected == 0 && 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(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)); - go_to_iter(selection, &iter); - } -} - -static void restore_tree_state(void); - -void dive_list_update_dives(void) -{ - dive_table.preexisting = dive_table.nr; - gtk_tree_store_clear(TREESTORE(dive_list)); - gtk_tree_store_clear(LISTSTORE(dive_list)); - fill_dive_list(); - restore_tree_state(); - repaint_dive(); -} - -static gint dive_nr_sort(GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data) -{ - int idx_a, idx_b; - timestamp_t when_a, when_b; - struct dive *a, *b; - dive_trip_t *tripa = NULL, *tripb = NULL; - - gtk_tree_model_get(model, iter_a, DIVE_INDEX, &idx_a, DIVE_DATE, &when_a, -1); - gtk_tree_model_get(model, iter_b, DIVE_INDEX, &idx_b, DIVE_DATE, &when_b, -1); - - if (idx_a < 0) { - a = NULL; - tripa = find_trip_by_idx(idx_a); - } else { - a = get_dive(idx_a); - if (a) - tripa = a->divetrip; - } - - if (idx_b < 0) { - b = NULL; - tripb = find_trip_by_idx(idx_b); - } else { - b = get_dive(idx_b); - if (b) - tripb = b->divetrip; - } - - /* - * Compare dive dates within the same trip (or when there - * are no trips involved at all). But if we have two - * different trips use the trip dates for comparison - */ - if (tripa != tripb) { - if (tripa) - when_a = tripa->when; - if (tripb) - when_b = tripb->when; - } - return when_a - when_b; -} - - -static struct divelist_column { - const char *header; - data_func_t data; - sort_func_t sort; - unsigned int flags; - int *visible; -} dl_column[] = { - [DIVE_NR] = { "#", nr_data_func, dive_nr_sort, ALIGN_RIGHT }, - [DIVE_DATE] = { N_("Date"), date_data_func, NULL, ALIGN_LEFT }, - [DIVE_RATING] = { UTF8_BLACKSTAR, star_data_func, NULL, ALIGN_LEFT }, - [DIVE_DEPTH] = { N_("ft"), depth_data_func, NULL, ALIGN_RIGHT }, - [DIVE_DURATION] = { N_("min"), duration_data_func, NULL, ALIGN_RIGHT }, - [DIVE_TEMPERATURE] = { UTF8_DEGREE "F", temperature_data_func, NULL, ALIGN_RIGHT, &prefs.visible_cols.temperature }, - [DIVE_TOTALWEIGHT] = { N_("lbs"), weight_data_func, NULL, ALIGN_RIGHT, &prefs.visible_cols.totalweight }, - [DIVE_SUIT] = { N_("Suit"), NULL, NULL, ALIGN_LEFT, &prefs.visible_cols.suit }, - [DIVE_CYLINDER] = { N_("Cyl"), NULL, NULL, 0, &prefs.visible_cols.cylinder }, - [DIVE_NITROX] = { "O" UTF8_SUBSCRIPT_2 "%", nitrox_data_func, nitrox_sort_func, 0, &prefs.visible_cols.nitrox }, - [DIVE_SAC] = { N_("SAC"), sac_data_func, NULL, 0, &prefs.visible_cols.sac }, - [DIVE_OTU] = { N_("OTU"), otu_data_func, NULL, 0, &prefs.visible_cols.otu }, - [DIVE_MAXCNS] = { N_("maxCNS"), cns_data_func, NULL, 0, &prefs.visible_cols.maxcns }, - [DIVE_LOCATION] = { N_("Location"), NULL, NULL, ALIGN_LEFT }, -}; - - -static GtkTreeViewColumn *divelist_column(struct DiveList *dl, struct divelist_column *col) -{ - int index = col - &dl_column[0]; - const char *title = _(col->header); - data_func_t data_func = col->data; - sort_func_t sort_func = col->sort; - unsigned int flags = col->flags; - int *visible = col->visible; - GtkWidget *tree_view = dl->tree_view; - GtkTreeStore *treemodel = dl->treemodel; - GtkTreeStore *listmodel = dl->listmodel; - GtkTreeViewColumn *ret; - - if (visible && !*visible) - flags |= INVISIBLE; - ret = tree_view_column(tree_view, index, title, data_func, flags); - if (sort_func) { - /* the sort functions are needed in the corresponding models */ - if (index == DIVE_NR) - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(treemodel), index, sort_func, NULL, NULL); - else - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(listmodel), index, sort_func, NULL, NULL); - } - return ret; -} - -/* - * This is some crazy crap. The only way to get default focus seems - * to be to grab focus as the widget is being shown the first time. - */ -static void realize_cb(GtkWidget *tree_view, gpointer userdata) -{ - gtk_widget_grab_focus(tree_view); -} - -/* - * Double-clicking on a group entry will expand a collapsed group - * and vice versa. - */ -static void collapse_expand(GtkTreeView *tree_view, GtkTreePath *path) -{ - if (!gtk_tree_view_row_expanded(tree_view, path)) - gtk_tree_view_expand_row(tree_view, path, FALSE); - else - gtk_tree_view_collapse_row(tree_view, path); - -} - -/* Double-click on a dive list */ -static void row_activated_cb(GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - gpointer userdata) -{ - int index; - GtkTreeIter iter; - - if (!gtk_tree_model_get_iter(MODEL(dive_list), &iter, path)) - return; - - 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); - return; - } - edit_dive_info(get_dive(index), FALSE); -} - -void add_dive_cb(GtkWidget *menuitem, gpointer data) -{ - struct dive *dive; - - dive = alloc_dive(); - if (add_new_dive(dive)) { - record_dive(dive); - report_dives(TRUE, FALSE); - return; - } - free(dive); -} - -static void edit_trip_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - int idx; - GtkTreeIter iter; - dive_trip_t *dive_trip; - - gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); - gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); - dive_trip = find_trip_by_idx(idx); - if (edit_trip(dive_trip)) - gtk_tree_store_set(STORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1); -} - -static void edit_selected_dives_cb(GtkWidget *menuitem, gpointer data) -{ - edit_multi_dive_info(NULL); -} - -static void edit_dive_from_path_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - struct dive *dive = dive_from_path(path); - - edit_multi_dive_info(dive); -} - -static void edit_dive_when_cb(GtkWidget *menuitem, struct dive *dive) -{ - GtkWidget *dialog, *cal, *h, *m, *timehbox; - timestamp_t when; - - guint yval, mval, dval; - int success; - struct tm tm; - - if (!dive) - return; - - when = dive->when; - utc_mkdate(when, &tm); - dialog = create_date_time_widget(&tm, &cal, &h, &m, &timehbox); - - gtk_widget_show_all(dialog); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - if (!success) { - gtk_widget_destroy(dialog); - return; - } - memset(&tm, 0, sizeof(tm)); - gtk_calendar_get_date(GTK_CALENDAR(cal), &yval, &mval, &dval); - tm.tm_year = yval; - tm.tm_mon = mval; - tm.tm_mday = dval; - tm.tm_hour = gtk_spin_button_get_value(GTK_SPIN_BUTTON(h)); - tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(m)); - - gtk_widget_destroy(dialog); - when = utc_mktime(&tm); - if (dive->when != when) { - /* if this is the only dive in the trip, just change the trip time */ - if (dive->divetrip && dive->divetrip->nrdives == 1) - dive->divetrip->when = when; - /* if this is suddenly before the start of the trip, remove it from the trip */ - else if (dive->divetrip && dive->divetrip->when > when) - remove_dive_from_trip(dive); - else if (find_matching_trip(when) != dive->divetrip) - remove_dive_from_trip(dive); - dive->when = when; - mark_divelist_changed(TRUE); - report_dives(FALSE, FALSE); - dive_list_update_dives(); - } -} - -#if HAVE_OSM_GPS_MAP -static void show_gps_location_cb(GtkWidget *menuitem, struct dive *dive) -{ - show_gps_location(dive, NULL); -} -#endif - -gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data) -{ -#if HAVE_OSM_GPS_MAP - GtkTreePath *path = NULL; - GtkTreeIter iter; - GtkTreeViewColumn *col; - int idx; - struct dive *dive; - - /* left click ? */ - if (event->button == 1 && - gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dive_list.tree_view), event->x, event->y, &path, &col, NULL, NULL)) { - /* is it the icon column ? (we passed the correct column in when registering the callback) */ - if (col == data) { - 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 && dive_has_gps_location(dive)) - show_gps_location(dive, NULL); - } - if (path) - gtk_tree_path_free(path); - } -#endif - /* keep processing the click */ - return FALSE; -} - -static void save_as_cb(GtkWidget *menuitem, struct dive *dive) -{ - GtkWidget *dialog; - char *filename = NULL; - - dialog = gtk_file_chooser_dialog_new(_("Save File As"), - GTK_WINDOW(main_window), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - } - gtk_widget_destroy(dialog); - - if (filename){ - save_dives_logic(filename, TRUE); - g_free(filename); - } -} - -static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view) -{ - gtk_tree_view_expand_all(tree_view); -} - -static void collapse_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view) -{ - gtk_tree_view_collapse_all(tree_view); -} - -/* Move a top-level dive into the trip above it */ -static void merge_dive_into_trip_above_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - int idx; - struct dive *dive; - dive_trip_t *trip; - - idx = get_path_index(path); - dive = get_dive(idx); - - /* Needs to be a dive, and at the top level */ - if (!dive || dive->divetrip) - return; - - /* Find the "trip above". */ - for (;;) { - if (!gtk_tree_path_prev(path)) - return; - idx = get_path_index(path); - trip = find_trip_by_idx(idx); - if (trip) - break; - } - - add_dive_to_trip(dive, trip); - if (dive->selected) { - for_each_dive(idx, dive) { - if (!dive->selected) - continue; - add_dive_to_trip(dive, trip); - } - } - - trip->expanded = 1; - dive_list_update_dives(); - mark_divelist_changed(TRUE); -} - -static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - int idx; - struct dive *dive; - dive_trip_t *trip; - - idx = get_path_index(path); - dive = get_dive(idx); - if (!dive) - return; - trip = create_and_hookup_trip_from_dive(dive); - if (dive->selected) { - for_each_dive(idx, dive) { - if (!dive->selected) - continue; - add_dive_to_trip(dive, trip); - } - } - trip->expanded = 1; - dive_list_update_dives(); - mark_divelist_changed(TRUE); -} - -static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - struct dive *dive; - int idx; - - idx = get_path_index(path); - if (idx < 0) - return; - dive = get_dive(idx); - - if (dive->selected) { - /* remove all the selected dives */ - for_each_dive(idx, dive) { - if (!dive->selected) - continue; - remove_dive_from_trip(dive); - } - } else { - /* just remove the dive the mouse pointer is on */ - remove_dive_from_trip(dive); - } - dive_list_update_dives(); - mark_divelist_changed(TRUE); -} - -static void remove_trip(GtkTreePath *trippath) -{ - int idx, i; - dive_trip_t *trip; - struct dive *dive; - - idx = get_path_index(trippath); - trip = find_trip_by_idx(idx); - if (!trip) - return; - - for_each_dive(i, dive) { - if (dive->divetrip != trip) - continue; - remove_dive_from_trip(dive); - } - - dive_list_update_dives(); - -#ifdef DEBUG_TRIP - dump_trip_list(); -#endif -} - -static void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) -{ - int success; - GtkWidget *dialog; - - dialog = gtk_dialog_new_with_buttons(_("Remove Trip"), - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - gtk_widget_show_all(dialog); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - gtk_widget_destroy(dialog); - if (!success) - return; - - remove_trip(trippath); - mark_divelist_changed(TRUE); -} - -static void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath) -{ - GtkTreePath *prevpath; - GtkTreeIter thistripiter, prevtripiter; - GtkTreeModel *tm = MODEL(dive_list); - dive_trip_t *thistrip, *prevtrip; - timestamp_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); - thistrip = 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); - /* move dives from trip */ - assert(thistrip != prevtrip); - while (thistrip->dives) - add_dive_to_trip(thistrip->dives, prevtrip); - dive_list_update_dives(); - mark_divelist_changed(TRUE); -} - /* this implements the mechanics of removing the dive from the table, * but doesn't deal with updating dive trips, etc */ void delete_single_dive(int idx) @@ -1895,300 +692,7 @@ void add_single_dive(int idx, struct dive *dive) } } -static gboolean restore_node_state(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) -{ - int idx; - struct dive *dive; - dive_trip_t *trip; - GtkTreeView *tree_view = GTK_TREE_VIEW(dive_list.tree_view); - GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - trip = find_trip_by_idx(idx); - if (trip && trip->expanded) - gtk_tree_view_expand_row(tree_view, path, FALSE); - if (trip && trip->selected) - gtk_tree_selection_select_iter(selection, iter); - } else { - dive = get_dive(idx); - if (dive && dive->selected) - gtk_tree_selection_select_iter(selection, iter); - } - /* continue foreach */ - return FALSE; -} - -/* restore expanded and selected state */ -static void restore_tree_state(void) -{ - gtk_tree_model_foreach(MODEL(dive_list), restore_node_state, NULL); -} - -/* called when multiple dives are selected and one of these is right-clicked for delete */ -static void delete_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - int i; - struct dive *dive; - int success; - GtkWidget *dialog; - char *dialog_title; - - if (!amount_selected) - return; - if (amount_selected == 1) - dialog_title = _("Delete dive"); - else - dialog_title = _("Delete dives"); - - dialog = gtk_dialog_new_with_buttons(dialog_title, - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - gtk_widget_show_all(dialog); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - gtk_widget_destroy(dialog); - if (!success) - return; - - /* walk the dive list in chronological order */ - for (i = 0; i < dive_table.nr; i++) { - dive = get_dive(i); - if (!dive) - continue; - if (!dive->selected) - continue; - /* now remove the dive from the table and free it. also move the iterator back, - * so that we don't skip a dive */ - delete_single_dive(i); - i--; - } - dive_list_update_dives(); - - /* if no dives are selected at this point clear the display widgets */ - if (!amount_selected) { - selected_dive = 0; - process_selected_dives(); - clear_stats_widgets(); - clear_equipment_widgets(); - show_dive_info(NULL); - } - 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) -{ - int idx; - GtkTreeIter iter; - int success; - GtkWidget *dialog; - - dialog = gtk_dialog_new_with_buttons(_("Delete dive"), - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - gtk_widget_show_all(dialog); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - gtk_widget_destroy(dialog); - if (!success) - return; - - if (!gtk_tree_model_get_iter(MODEL(dive_list), &iter, path)) - return; - gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); - delete_single_dive(idx); - dive_list_update_dives(); - mark_divelist_changed(TRUE); -} - -#if defined(LIBZIP) && defined(XSLT) -static void export_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - int i; - struct dive *dive; - FILE *f; - char filename[PATH_MAX], *tempfile; - size_t streamsize; - char *membuf; - xmlDoc *doc; - xsltStylesheetPtr xslt = NULL; - xmlDoc *transformed; - struct zip_source *s[dive_table.nr]; - struct zip *zip; - const gchar *tmpdir = g_get_tmp_dir(); - - /* - * Creating a temporary .DLD file to be eventually uploaded to - * divelogs.de. I wonder if this could be done in-memory. - */ - tempfile = g_build_filename(tmpdir, "export.DLD-XXXXXX", NULL); - int fd = g_mkstemp(tempfile); - if (fd != -1) - close(fd); - zip = zip_open(tempfile, ZIP_CREATE, NULL); - - if (!zip) - return; - - if (!amount_selected) - return; - - /* walk the dive list in chronological order */ - for (i = 0; i < dive_table.nr; i++) { - - dive = get_dive(i); - if (!dive) - continue; - if (!dive->selected) - continue; - - f = tmpfile(); - if (!f) - return; - save_dive(f, dive); - fseek(f, 0, SEEK_END); - streamsize = ftell(f); - rewind(f); - membuf = malloc(streamsize + 1); - if (!membuf || !fread(membuf, streamsize, 1, f)) - return; - membuf[streamsize] = 0; - fclose(f); - - /* - * Parse the memory buffer into XML document and - * transform it to divelogs.de format, finally dumping - * the XML into a character buffer. - */ - doc = xmlReadMemory(membuf, strlen(membuf), "divelog", NULL, 0); - if (!doc) - continue; - - free((void *)membuf); - xslt = get_stylesheet("divelogs-export.xslt"); - if (!xslt) - return; - transformed = xsltApplyStylesheet(xslt, doc, NULL); - xsltFreeStylesheet(xslt); - xmlDocDumpMemory(transformed, (xmlChar **) &membuf, (int *)&streamsize); - xmlFreeDoc(doc); - xmlFreeDoc(transformed); - - /* - * Save the XML document into a zip file. - */ - snprintf(filename, PATH_MAX, "%d.xml", i + 1); - s[i] = zip_source_buffer(zip, membuf, streamsize, 1); - if (s[i]) { - int64_t ret = zip_add(zip, filename, s[i]); - if (ret == -1) - fprintf(stderr, "failed to include dive %d\n", i); - } - } - zip_close(zip); - if (divelogde_upload(tempfile)) - g_unlink(tempfile); - else - fprintf(stderr,"upload of %s failed\n", tempfile); - g_free(tempfile); -} -#endif - -#if defined(XSLT) -static void export_dives_uddf(const gboolean selected) -{ - FILE *f; - char *filename = NULL; - size_t streamsize; - char *membuf; - xmlDoc *doc; - xsltStylesheetPtr xslt = NULL; - xmlDoc *transformed; - GtkWidget *dialog; - - dialog = gtk_file_chooser_dialog_new(_("Export As UDDF File"), - GTK_WINDOW(main_window), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - } - gtk_widget_destroy(dialog); - - if (!filename) - return; - - /* Save XML to file and convert it into a memory buffer */ - save_dives_logic(filename, selected); - f = fopen(filename, "r"); - fseek(f, 0, SEEK_END); - streamsize = ftell(f); - rewind(f); - - membuf = malloc(streamsize + 1); - if (!membuf || !fread(membuf, streamsize, 1, f)) { - fprintf(stderr, "Failed to read memory buffer\n"); - return; - } - membuf[streamsize] = 0; - fclose(f); - g_unlink(filename); - - /* - * Parse the memory buffer into XML document and - * transform it to UDDF format, finally dumping - * the XML into a character buffer. - */ - doc = xmlReadMemory(membuf, strlen(membuf), "divelog", NULL, 0); - if (!doc) { - fprintf(stderr, "Failed to read XML memory\n"); - return; - } - free((void *)membuf); - - /* Convert to UDDF format */ - xslt = get_stylesheet("uddf-export.xslt"); - if (!xslt) { - fprintf(stderr, "Failed to open UDDF conversion stylesheet\n"); - return; - } - transformed = xsltApplyStylesheet(xslt, doc, NULL); - xsltFreeStylesheet(xslt); - xmlFreeDoc(doc); - - /* Write the transformed XML to file */ - f = g_fopen(filename, "w"); - xmlDocFormatDump(f, transformed, 1); - xmlFreeDoc(transformed); - - fclose(f); - g_free(filename); -} - -static void export_selected_dives_uddf_cb(GtkWidget *menuitem, GtkTreePath *path) -{ - export_dives_uddf(TRUE); -} - -void export_all_dives_uddf_cb() -{ - export_dives_uddf(FALSE); -} -#endif - -static void merge_dive_index(int i, struct dive *a) +void merge_dive_index(int i, struct dive *a) { struct dive *b = get_dive(i+1); struct dive *res; @@ -2205,369 +709,7 @@ static void merge_dive_index(int i, struct dive *a) 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 *a, *b; - GtkWidget *menuitem; - - /* The other selected dive must be next to it.. */ - a = get_dive(idx); - b = get_dive(idx+1); - if (!b || !b->selected) { - b = a; - a = get_dive(idx-1); - if (!a || !a->selected) - return; - } - - /* .. and they had better be in the same dive trip */ - if (a->divetrip != b->divetrip) - return; - - /* .. and if the surface interval is excessive, you must be kidding us */ - if (b->when > a->when + a->duration.seconds + 30*60) - 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; - char editplurallabel[] = N_("Edit dives"); - char editsinglelabel[] = N_("Edit dive"); - char *editlabel; - char deleteplurallabel[] = N_("Delete dives"); - char deletesinglelabel[] = N_("Delete dive"); - char *deletelabel; -#if defined(XSLT) - char exportuddflabel[] = N_("Export dive(s) to UDDF"); -#endif -#if defined(LIBZIP) && defined(XSLT) - char exportlabel[] = N_("Export dive(s)"); -#endif - GtkTreePath *path, *prevpath, *nextpath; - GtkTreeIter iter, previter, nextiter; - int idx, previdx, nextidx; - struct dive *dive; - - if (!event || !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")); - image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU); - 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 (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 or delete those */ - if (dive->selected) { - if (amount_selected == 1) { - deletelabel = _(deletesinglelabel); - editlabel = _(editsinglelabel); - menuitem = gtk_menu_item_new_with_label(_("Edit dive date/time")); - g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_when_cb), dive); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - } else { - deletelabel = _(deleteplurallabel); - editlabel = _(editplurallabel); - } - menuitem = gtk_menu_item_new_with_label(_("Save as")); - g_signal_connect(menuitem, "activate", G_CALLBACK(save_as_cb), dive); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - menuitem = gtk_menu_item_new_with_label(deletelabel); - g_signal_connect(menuitem, "activate", G_CALLBACK(delete_selected_dives_cb), path); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - -#if defined(LIBZIP) && defined(XSLT) - menuitem = gtk_menu_item_new_with_label(exportlabel); - g_signal_connect(menuitem, "activate", G_CALLBACK(export_selected_dives_cb), path); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); -#endif - -#if defined(XSLT) - menuitem = gtk_menu_item_new_with_label(exportuddflabel); - g_signal_connect(menuitem, "activate", G_CALLBACK(export_selected_dives_uddf_cb), path); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); -#endif - - 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 { - menuitem = gtk_menu_item_new_with_label(_("Edit dive date/time")); - g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_when_cb), dive); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - deletelabel = _(deletesinglelabel); - menuitem = gtk_menu_item_new_with_label(deletelabel); - g_signal_connect(menuitem, "activate", G_CALLBACK(delete_dive_cb), path); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - editlabel = _(editsinglelabel); - 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); - } -#if HAVE_OSM_GPS_MAP - /* Only offer to show on map if it has a location. */ - if (dive_has_gps_location(dive)) { - menuitem = gtk_menu_item_new_with_label(_("Show in map")); - g_signal_connect(menuitem, "activate", G_CALLBACK(show_gps_location_cb), dive); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - } -#endif - /* only offer trip editing options when we are displaying the tree model */ - if (dive_list.model == dive_list.treemodel) { - 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(_("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")); - 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); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - menuitem = gtk_menu_item_new_with_label(_("Collapse all")); - g_signal_connect(menuitem, "activate", G_CALLBACK(collapse_all_cb), tree_view); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - gtk_widget_show_all(menu); - - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, - button, gtk_get_current_event_time()); -} - -static void popup_menu_cb(GtkTreeView *tree_view, gpointer userdata) -{ - 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), MODEL(dive_list), 3, event); - return TRUE; - } - return FALSE; -} - -/* make sure 'path' is shown in the divelist widget; since set_cursor changes the - * selection to be only 'path' we need to let our selection handling callbacks know - * that we didn't really mean this */ -static void scroll_to_path(GtkTreePath *path) -{ - GtkTreeSelection *selection; - - gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), path); - gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(dive_list.tree_view), path, NULL, FALSE, 0, 0); - in_set_cursor = TRUE; - gtk_tree_view_set_cursor(GTK_TREE_VIEW(dive_list.tree_view), path, NULL, FALSE); - in_set_cursor = FALSE; - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - gtk_tree_model_foreach(MODEL(dive_list), set_selected, selection); - -} - -/* we need to have a temporary copy of the selected dives while - switching model as the selection_cb function keeps getting called - when gtk_tree_selection_select_path is called. We also need to - keep copies of the sort order so we can restore that as well after - switching models. */ -static gboolean second_call = FALSE; -static GtkSortType sortorder[] = { [0 ... DIVELIST_COLUMNS - 1] = GTK_SORT_DESCENDING, }; -static int lastcol = DIVE_NR; - -/* Check if this dive was selected previously and select it again in the new model; - * This is used after we switch models to maintain consistent selections. - * We always return FALSE to iterate through all dives */ -static gboolean set_selected(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer data) -{ - GtkTreeSelection *selection = GTK_TREE_SELECTION(data); - int idx, selected; - struct dive *dive; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - /* this is a trip - restore its state */ - dive_trip_t *trip = find_trip_by_idx(idx); - if (trip && trip->expanded) - gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), path); - if (trip && trip->selected) - gtk_tree_selection_select_path(selection, path); - } else { - dive = get_dive(idx); - selected = dive && dive->selected; - if (selected) { - gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), path); - gtk_tree_selection_select_path(selection, path); - } - } - return FALSE; -} - -static gboolean scroll_to_this(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer data) -{ - int idx; - struct dive *dive; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - dive = get_dive(idx); - if (dive == current_dive) { - scroll_to_path(path); - return TRUE; - } - return FALSE; -} - -static void scroll_to_current(GtkTreeModel *model) -{ - if (current_dive) - gtk_tree_model_foreach(model, scroll_to_this, current_dive); -} - -static void update_column_and_order(int colid) -{ - /* Careful: the index into treecolumns is off by one as we don't have a - tree_view column for DIVE_INDEX */ - GtkTreeViewColumn **treecolumns = &dive_list.nr; - - /* this will trigger a second call into sort_column_change_cb, - so make sure we don't start an infinite recursion... */ - second_call = TRUE; - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dive_list.model), colid, sortorder[colid]); - gtk_tree_view_column_set_sort_order(treecolumns[colid - 1], sortorder[colid]); - second_call = FALSE; - scroll_to_current(GTK_TREE_MODEL(dive_list.model)); -} - -/* If the sort column is nr (default), show the tree model. - For every other sort column only show the list model. - If the model changed, inform the new model of the chosen sort column and make - sure the same dives are still selected. - - The challenge with this function is that once we change the model - we also need to change the sort column again (as it was changed in - the other model) and that causes this function to be called - recursively - so we need to catch that. -*/ -static void sort_column_change_cb(GtkTreeSortable *treeview, gpointer data) -{ - int colid; - GtkSortType order; - GtkTreeStore *currentmodel = dive_list.model; - - gtk_widget_grab_focus(dive_list.tree_view); - if (second_call) - return; - - gtk_tree_sortable_get_sort_column_id(treeview, &colid, &order); - if (colid == lastcol) { - /* we just changed sort order */ - sortorder[colid] = order; - return; - } else { - lastcol = colid; - } - if (colid == DIVE_NR) - dive_list.model = dive_list.treemodel; - else - dive_list.model = dive_list.listmodel; - 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), MODEL(dive_list)); - update_column_and_order(colid); - gtk_tree_model_foreach(MODEL(dive_list), set_selected, selection); - } else { - if (order != sortorder[colid]) { - update_column_and_order(colid); - } - } -} - -static void select_dive(int idx) +void select_dive(int idx) { struct dive *dive = get_dive(idx); if (dive && !dive->selected) { @@ -2577,7 +719,7 @@ static void select_dive(int idx) } } -static void deselect_dive(int idx) +void deselect_dive(int idx) { struct dive *dive = get_dive(idx); if (dive && dive->selected) { @@ -2602,266 +744,14 @@ static void deselect_dive(int idx) } } -static gboolean modify_selection_cb(GtkTreeSelection *selection, GtkTreeModel *model, - GtkTreePath *path, gboolean was_selected, gpointer userdata) -{ - int idx; - GtkTreeIter iter; - - if (!was_selected || in_set_cursor) - return TRUE; - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_get(model, &iter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - int i; - struct dive *dive; - dive_trip_t *trip = find_trip_by_idx(idx); - if (!trip) - return TRUE; - - trip->selected = 0; - /* If this is expanded, let the gtk selection happen for each dive under it */ - if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), path)) - return TRUE; - /* Otherwise, consider each dive under it deselected */ - for_each_dive(i, dive) { - if (dive->divetrip == trip) - deselect_dive(i); - } - } else { - deselect_dive(idx); - } - return TRUE; -} - -/* This gets called for each selected entry after a selection has changed */ -static void entry_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) -{ - int idx; - - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - int i; - struct dive *dive; - dive_trip_t *trip = find_trip_by_idx(idx); - - if (!trip) - return; - trip->selected = 1; - - /* If this is expanded, let the gtk selection happen for each dive under it */ - if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), path)) { - trip->fixup = 1; - return; - } - - /* Otherwise, consider each dive under it selected */ - for_each_dive(i, dive) { - if (dive->divetrip == trip) - select_dive(i); - } - trip->fixup = 0; - } else { - select_dive(idx); - } -} - -static void update_gtk_selection(GtkTreeSelection *selection, GtkTreeModel *model) -{ - GtkTreeIter iter; - - if (!gtk_tree_model_get_iter_first(model, &iter)) - return; - do { - GtkTreeIter child; - - if (!gtk_tree_model_iter_children(model, &child, &iter)) - continue; - - do { - int idx; - struct dive *dive; - dive_trip_t *trip; - - gtk_tree_model_get(model, &child, DIVE_INDEX, &idx, -1); - dive = get_dive(idx); - if (!dive || !dive->selected) - break; - trip = dive->divetrip; - if (!trip) - break; - gtk_tree_selection_select_iter(selection, &child); - } while (gtk_tree_model_iter_next(model, &child)); - } while (gtk_tree_model_iter_next(model, &iter)); -} - -/* this is called when gtk thinks that the selection has changed */ -static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model) -{ - int i, fixup; - struct dive *dive; - - gtk_tree_selection_selected_foreach(selection, entry_selected, model); - - /* - * Go through all the dives, if there is a trip that is selected but no - * dives under it are selected, force-select all the dives - */ - - /* First, clear "fixup" for any trip that has selected dives */ - for_each_dive(i, dive) { - dive_trip_t *trip = dive->divetrip; - if (!trip || !trip->fixup) - continue; - if (dive->selected || !trip->selected) - trip->fixup = 0; - } - - /* - * Ok, not fixup is only set for trips that are selected - * but have no selected dives in them. Select all dives - * for such trips. - */ - fixup = 0; - for_each_dive(i, dive) { - dive_trip_t *trip = dive->divetrip; - if (!trip || !trip->fixup) - continue; - fixup = 1; - select_dive(i); - } - - /* - * Ok, we did a forced selection of dives, now we need to update the gtk - * view of what is selected too.. - */ - if (fixup) - update_gtk_selection(selection, model); - -#if DEBUG_SELECTION_TRACKING - dump_selection(); -#endif - - process_selected_dives(); - repaint_dive(); -} - -GtkWidget *dive_list_create(void) -{ - GtkTreeSelection *selection; - - dive_list.listmodel = gtk_tree_store_new(DIVELIST_COLUMNS, - G_TYPE_INT, /* index */ - G_TYPE_INT, /* nr */ - G_TYPE_INT64, /* Date */ - G_TYPE_INT, /* Star rating */ - G_TYPE_INT, /* Depth */ - G_TYPE_INT, /* Duration */ - G_TYPE_INT, /* Temperature */ - G_TYPE_INT, /* Total weight */ - G_TYPE_STRING, /* Suit */ - G_TYPE_STRING, /* Cylinder */ - G_TYPE_INT, /* Nitrox */ - G_TYPE_INT, /* SAC */ - G_TYPE_INT, /* OTU */ - G_TYPE_INT, /* MAXCNS */ - G_TYPE_STRING, /* Location */ - GDK_TYPE_PIXBUF /* GPS icon */ - ); - dive_list.treemodel = gtk_tree_store_new(DIVELIST_COLUMNS, - G_TYPE_INT, /* index */ - G_TYPE_INT, /* nr */ - G_TYPE_INT64, /* Date */ - G_TYPE_INT, /* Star rating */ - G_TYPE_INT, /* Depth */ - G_TYPE_INT, /* Duration */ - G_TYPE_INT, /* Temperature */ - G_TYPE_INT, /* Total weight */ - G_TYPE_STRING, /* Suit */ - G_TYPE_STRING, /* Cylinder */ - G_TYPE_INT, /* Nitrox */ - G_TYPE_INT, /* SAC */ - G_TYPE_INT, /* OTU */ - G_TYPE_INT, /* MAXCNS */ - G_TYPE_STRING, /* Location */ - GDK_TYPE_PIXBUF /* GPS icon */ - ); - dive_list.model = dive_list.treemodel; - dive_list.tree_view = gtk_tree_view_new_with_model(TREEMODEL(dive_list)); - set_divelist_font(prefs.divelist_font); - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - - gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE); - gtk_widget_set_size_request(dive_list.tree_view, 200, 200); - - /* check if utf8 stars are available as a default OS feature */ - if (!subsurface_os_feature_available(UTF8_FONT_WITH_STARS)) - dl_column[3].header = "*"; - - dive_list.nr = divelist_column(&dive_list, dl_column + DIVE_NR); - dive_list.date = divelist_column(&dive_list, dl_column + DIVE_DATE); - dive_list.stars = divelist_column(&dive_list, dl_column + DIVE_RATING); - dive_list.depth = divelist_column(&dive_list, dl_column + DIVE_DEPTH); - dive_list.duration = divelist_column(&dive_list, dl_column + DIVE_DURATION); - dive_list.temperature = divelist_column(&dive_list, dl_column + DIVE_TEMPERATURE); - dive_list.totalweight = divelist_column(&dive_list, dl_column + DIVE_TOTALWEIGHT); - dive_list.suit = divelist_column(&dive_list, dl_column + DIVE_SUIT); - dive_list.cylinder = divelist_column(&dive_list, dl_column + DIVE_CYLINDER); - dive_list.nitrox = divelist_column(&dive_list, dl_column + DIVE_NITROX); - dive_list.sac = divelist_column(&dive_list, dl_column + DIVE_SAC); - dive_list.otu = divelist_column(&dive_list, dl_column + DIVE_OTU); - dive_list.maxcns = divelist_column(&dive_list, dl_column + DIVE_MAXCNS); - dive_list.location = divelist_column(&dive_list, dl_column + DIVE_LOCATION); - gtk_tree_view_column_set_sort_indicator(dive_list.nr, TRUE); - gtk_tree_view_column_set_sort_order(dive_list.nr, GTK_SORT_DESCENDING); - /* now add the GPS icon to the location column */ - tree_view_column_add_pixbuf(dive_list.tree_view, gpsicon_data_func, dive_list.location); - - fill_dive_list(); - - g_object_set(G_OBJECT(dive_list.tree_view), "headers-visible", TRUE, - "search-column", DIVE_LOCATION, - "rules-hint", TRUE, - NULL); - - g_signal_connect_after(dive_list.tree_view, "realize", G_CALLBACK(realize_cb), NULL); - g_signal_connect(dive_list.tree_view, "row-activated", G_CALLBACK(row_activated_cb), NULL); - g_signal_connect(dive_list.tree_view, "row-expanded", G_CALLBACK(row_expanded_cb), NULL); - g_signal_connect(dive_list.tree_view, "row-collapsed", G_CALLBACK(row_collapsed_cb), NULL); - g_signal_connect(dive_list.tree_view, "button-press-event", G_CALLBACK(button_press_cb), NULL); - g_signal_connect(dive_list.tree_view, "popup-menu", G_CALLBACK(popup_menu_cb), NULL); - g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), dive_list.model); - g_signal_connect(dive_list.listmodel, "sort-column-changed", G_CALLBACK(sort_column_change_cb), NULL); - g_signal_connect(dive_list.treemodel, "sort-column-changed", G_CALLBACK(sort_column_change_cb), NULL); - - gtk_tree_selection_set_select_function(selection, modify_selection_cb, NULL, NULL); - - dive_list.container_widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dive_list.container_widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add(GTK_CONTAINER(dive_list.container_widget), dive_list.tree_view); - - dive_list.changed = 0; - - return dive_list.container_widget; -} - -void dive_list_destroy(void) -{ - gtk_widget_destroy(dive_list.tree_view); - g_object_unref(dive_list.treemodel); - g_object_unref(dive_list.listmodel); -} - void mark_divelist_changed(int changed) { - dive_list.changed = changed; + dive_list_changed = changed; } int unsaved_changes() { - return dive_list.changed; + return dive_list_changed; } void remove_autogen_trips() @@ -2877,142 +767,3 @@ void remove_autogen_trips() } } -struct iteridx { - int idx; - GtkTreeIter *iter; -}; - -static gboolean iter_has_idx(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer _data) -{ - struct iteridx *iteridx = _data; - int idx; - /* Get the dive number */ - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); - if (idx == iteridx->idx) { - iteridx->iter = gtk_tree_iter_copy(iter); - return TRUE; /* end foreach */ - } - return FALSE; -} - -static GtkTreeIter *get_iter_from_idx(int idx) -{ - struct iteridx iteridx = {idx, }; - gtk_tree_model_foreach(MODEL(dive_list), iter_has_idx, &iteridx); - return iteridx.iter; -} - -static void scroll_to_selected(GtkTreeIter *iter) -{ - GtkTreePath *treepath; - treepath = gtk_tree_model_get_path(MODEL(dive_list), iter); - scroll_to_path(treepath); - gtk_tree_path_free(treepath); -} - -static void go_to_iter(GtkTreeSelection *selection, GtkTreeIter *iter) -{ - gtk_tree_selection_unselect_all(selection); - gtk_tree_selection_select_iter(selection, iter); - scroll_to_selected(iter); -} - -void show_and_select_dive(struct dive *dive) -{ - GtkTreeSelection *selection; - GtkTreeIter *iter; - struct dive *odive; - int i, divenr; - - divenr = get_divenr(dive); - if (divenr < 0) - /* we failed to find the dive */ - return; - iter = get_iter_from_idx(divenr); - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - for_each_dive(i, odive) - odive->selected = FALSE; - amount_selected = 1; - selected_dive = divenr; - dive->selected = TRUE; - go_to_iter(selection, iter); - gtk_tree_iter_free(iter); -} - -void select_next_dive(void) -{ - GtkTreeIter *nextiter, *parent = NULL; - GtkTreeIter *iter = get_iter_from_idx(selected_dive); - GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - int idx; - - if (!iter) - return; - nextiter = gtk_tree_iter_copy(iter); - if (!gtk_tree_model_iter_next(MODEL(dive_list), nextiter)) { - if (!gtk_tree_model_iter_parent(MODEL(dive_list), nextiter, iter)) { - /* we're at the last top level node */ - goto free_iter; - } - if (!gtk_tree_model_iter_next(MODEL(dive_list), nextiter)) { - /* last trip */ - goto free_iter; - } - } - gtk_tree_model_get(MODEL(dive_list), nextiter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - /* need the first child */ - parent = gtk_tree_iter_copy(nextiter); - if (! gtk_tree_model_iter_children(MODEL(dive_list), nextiter, parent)) - goto free_iter; - } - go_to_iter(selection, nextiter); -free_iter: - if (nextiter) - gtk_tree_iter_free(nextiter); - if (parent) - gtk_tree_iter_free(parent); - gtk_tree_iter_free(iter); -} - -void select_prev_dive(void) -{ - GtkTreeIter previter, *parent = NULL; - GtkTreeIter *iter = get_iter_from_idx(selected_dive); - GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - GtkTreePath *treepath; - int idx; - - if (!iter) - return; - treepath = gtk_tree_model_get_path(MODEL(dive_list), iter); - if (!gtk_tree_path_prev(treepath)) { - if (!gtk_tree_model_iter_parent(MODEL(dive_list), &previter, iter)) - /* we're at the last top level node */ - goto free_iter; - gtk_tree_path_free(treepath); - treepath = gtk_tree_model_get_path(MODEL(dive_list), &previter); - if (!gtk_tree_path_prev(treepath)) - /* first trip */ - goto free_iter; - if (!gtk_tree_model_get_iter(MODEL(dive_list), &previter, treepath)) - goto free_iter; - } - if (!gtk_tree_model_get_iter(MODEL(dive_list), &previter, treepath)) - goto free_iter; - gtk_tree_model_get(MODEL(dive_list), &previter, DIVE_INDEX, &idx, -1); - if (idx < 0) { - /* need the last child */ - parent = gtk_tree_iter_copy(&previter); - if (! gtk_tree_model_iter_nth_child(MODEL(dive_list), &previter, parent, - gtk_tree_model_iter_n_children(MODEL(dive_list), parent) - 1)) - goto free_iter; - } - go_to_iter(selection, &previter); -free_iter: - gtk_tree_path_free(treepath); - if (parent) - gtk_tree_iter_free(parent); - gtk_tree_iter_free(iter); -} |