summaryrefslogtreecommitdiffstats
path: root/divelist-gtk.c
diff options
context:
space:
mode:
Diffstat (limited to 'divelist-gtk.c')
-rw-r--r--divelist-gtk.c2343
1 files changed, 0 insertions, 2343 deletions
diff --git a/divelist-gtk.c b/divelist-gtk.c
deleted file mode 100644
index 49f4b143c..000000000
--- a/divelist-gtk.c
+++ /dev/null
@@ -1,2343 +0,0 @@
-/* divelist-gtk.c */
-/* this creates the UI for the dive list -
- * controlled through the following interfaces:
- *
- * GdkPixbuf *get_gps_icon(void)
- * void flush_divelist(struct dive *dive)
- * void set_divelist_font(const char *font)
- * void dive_list_update_dives(void)
- * void update_dive_list_units(void)
- * void update_dive_list_col_visibility(void)
- * void dive_list_update_dives(void)
- * void add_dive_cb(GtkWidget *menuitem, gpointer data)
- * gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data)
- * void export_all_dives_uddf_cb()
- * GtkWidget dive_list_create(void)
- * void dive_list_destroy(void)
- * void show_and_select_dive(struct dive *dive)
- * void select_next_dive(void)
- * void select_prev_dive(void)
- */
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-#include <glib/gi18n.h>
-#include <assert.h>
-#include <zip.h>
-#include <libxslt/transform.h>
-
-#include "dive.h"
-#include "divelist.h"
-#include "display.h"
-#include "display-gtk.h"
-#include "webservice.h"
-#include "profile.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 gboolean ignore_selection_changes = 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
-
-/* 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 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));
-}
-
-/* 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;
- timestamp_t when;
- /* this should be enought for most languages. if not increase the value. */
- char *buffer;
-
- gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1);
- nr = gtk_tree_model_iter_n_children(model, iter);
-
- if (idx < 0) {
- buffer = get_trip_date_string(when, nr);
- } else {
- buffer = get_dive_date_string(when);
- }
- g_object_set(renderer, "text", buffer, NULL);
- free(buffer);
-}
-
-static void depth_data_func(GtkTreeViewColumn *col,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- int depth, integer, frac, len, idx, show_decimal;
- char buffer[40];
-
- gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DEPTH, &depth, -1);
-
- if (idx < 0) {
- *buffer = '\0';
- } else {
- get_depth_values(depth, &integer, &frac, &show_decimal);
- len = snprintf(buffer, sizeof(buffer), "%d", integer);
- if (show_decimal)
- 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);
-}
-
-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;
-}
-
-static void nitrox_data_func(GtkTreeViewColumn *col,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- int idx;
- char *buffer;
- struct dive *dive;
-
- gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1);
- if (idx >= 0 && (dive = get_dive(idx))) {
- buffer = get_nitrox_string(dive);
- g_object_set(renderer, "text", buffer, NULL);
- free(buffer);
- } else {
- g_object_set(renderer, "text", "", 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);
-}
-
-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;
-}
-
-/* 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;
- if (((dive->dive_tags & DTAG_INVALID) && !prefs.display_invalid_dives) ||
- (dive->dive_tags & dive_mask) != dive_mask)
- continue;
- 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;
- ignore_selection_changes = TRUE;
- gtk_tree_store_clear(TREESTORE(dive_list));
- gtk_tree_store_clear(LISTSTORE(dive_list));
- ignore_selection_changes = FALSE;
- fill_dive_list();
- restore_tree_state();
- repaint_dive();
-}
-
-static gint gtk_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;
-
- 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);
-
- return dive_nr_sort(idx_a, idx_b, 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, gtk_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 report_dives(bool is_imported, bool prefer_imported)
-{
- process_dives(is_imported, prefer_imported);
- dive_list_update_dives();
-}
-
-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();
- }
-}
-
-static void show_gps_location_cb(GtkWidget *menuitem, struct dive *dive)
-{
- show_gps_location(dive, NULL);
-}
-
-gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data)
-{
- 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);
- }
- /* 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 invalid_dives_cb(GtkWidget *menuitem, GtkTreePath *path)
-{
- int i;
- int changed = 0;
- struct dive *dive;
-
- if (!amount_selected)
- return;
- /* walk the dive list in chronological order */
- for_each_dive(i, dive) {
- if (!dive->selected)
- continue;
- /* now swap the invalid tag if just 1 dive was selected
- * otherwise set all to invalid */
- if(amount_selected == 1) {
- if (dive->dive_tags & DTAG_INVALID)
- dive->dive_tags &= ~DTAG_INVALID;
- else
- dive->dive_tags |= DTAG_INVALID;
- changed = 1;
- } else {
- if (! dive->dive_tags & DTAG_INVALID) {
- dive->dive_tags |= DTAG_INVALID;
- changed = 1;
- }
- }
- /* if invalid dives aren't shown they need to be
- * de-selected here to avoid confusion */
- if (dive->selected && !prefs.display_invalid_dives) {
- dive->selected = 0;
- amount_selected--;
- }
- }
- if (amount_selected == 0)
- selected_dive = -1;
- if (changed) {
- dive_list_update_dives();
- mark_divelist_changed(TRUE);
- }
-}
-
-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);
-}
-
-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 = -1;
- 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);
-}
-
-void divelogs_status_dialog(char *error, GtkMessageType type)
-{
- GtkWidget *dialog, *vbox, *label;
-
- dialog = gtk_message_dialog_new(
- GTK_WINDOW(main_window),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- type,
- GTK_BUTTONS_OK,
- _("%s: Response from divelogs.de"), type == GTK_MESSAGE_INFO ? _("Info") : _("Error")
- );
-
- vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-
- label = create_label("%s", error);
- gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
- gtk_widget_show_all(dialog);
- gtk_dialog_run(GTK_DIALOG(dialog));
-
- gtk_widget_destroy(dialog);
-
-}
-
-static void upload_dives_divelogs(const gboolean selected)
-{
- 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();
- GtkMessageType type;
- char *error = NULL;
- char *parsed = NULL, *endat = NULL;
-
- /*
- * 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 (selected && !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, &error)) {
- type = GTK_MESSAGE_ERROR;
- } else {
- /* The upload status XML message should be parsed
- * properly and displayed in a sensible manner. But just
- * displaying the information part of the raw message is
- * better than nothing.
- * And at least the dialog is customized to indicate
- * error or success.
- */
- if (error) {
- parsed = strstr(error, "<Login>");
- endat = strstr(error, "</divelogsDataImport>");
- if (parsed && endat)
- *endat = '\0';
- }
- if (error && strstr(error, "failed"))
- type = GTK_MESSAGE_ERROR;
- else
- type = GTK_MESSAGE_INFO;
- }
- if (parsed)
- divelogs_status_dialog(parsed, type);
- else if (error)
- divelogs_status_dialog(error, type);
- free(error);
-
- g_unlink(tempfile);
- g_free(tempfile);
-}
-
-void upload_selected_dives_divelogs_cb(GtkWidget *menuitem, GtkTreePath *path)
-{
- upload_dives_divelogs(TRUE);
-}
-
-void upload_all_dives_divelogs_cb()
-{
- upload_dives_divelogs(FALSE);
-}
-
-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);
-}
-
-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;
- char exportuddflabel[] = N_("Export dive(s) to UDDF");
- char uploaddivelogslabel[] = N_("Upload dive(s) to divelogs.de");
- 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, delete or tag them as invalid */
- 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);
-
- if (amount_selected == 1) {
- if (dive->dive_tags & DTAG_INVALID)
- menuitem = gtk_menu_item_new_with_label(_("Mark valid"));
- else
- menuitem = gtk_menu_item_new_with_label(_("Mark invalid"));
- } else {
- menuitem = gtk_menu_item_new_with_label(_("Mark invalid"));
- }
- g_signal_connect(menuitem, "activate", G_CALLBACK(invalid_dives_cb), path);
- 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);
-
- menuitem = gtk_menu_item_new_with_label(_(uploaddivelogslabel));
- g_signal_connect(menuitem, "activate", G_CALLBACK(upload_selected_dives_divelogs_cb), path);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
- 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);
-
- 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);
- }
- /* 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);
- }
- /* 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 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;
-
- if (ignore_selection_changes)
- return;
-
- 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);
-}
-
-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);
-}