+ if (!size)
+ continue;
+
+ start = cyl->start.mbar ? cyl->start : cyl->sample_start;
+ end = cyl->end.mbar ? cyl->end : cyl->sample_end;
+ kilo_atm = (to_ATM(start) - to_ATM(end)) / 1000.0;
+
+ /* Liters of air at 1 atm == milliliters at 1k atm*/
+ airuse += kilo_atm * size;
+ }
+ return airuse;
+}
+
+static int calculate_sac(struct dive *dive)
+{
+ double airuse, pressure, sac;
+ int duration, i;
+
+ airuse = calculate_airuse(dive);
+ if (!airuse)
+ return 0;
+ if (!dive->duration.seconds)
+ return 0;
+
+ /* find and eliminate long surface intervals */
+ duration = dive->duration.seconds;
+ for (i = 0; i < dive->samples; i++) {
+ if (dive->sample[i].depth.mm < 100) { /* less than 10cm */
+ int end = i + 1;
+ while (end < dive->samples && dive->sample[end].depth.mm < 100)
+ end++;
+ /* we only want the actual surface time during a dive */
+ if (end < dive->samples) {
+ end--;
+ duration -= dive->sample[end].time.seconds -
+ dive->sample[i].time.seconds;
+ i = end + 1;
+ }
+ }
+ }
+ /* Mean pressure in atm: 1 atm per 10m */
+ pressure = 1 + (dive->meandepth.mm / 10000.0);
+ sac = airuse / pressure * 60 / duration;
+
+ /* milliliters per minute.. */
+ return sac * 1000;
+}
+
+void update_cylinder_related_info(struct dive *dive)
+{
+ if (dive != NULL) {
+ dive->sac = calculate_sac(dive);
+ dive->otu = calculate_otu(dive);
+ }
+}
+
+static void get_string(char **str, const char *s)
+{
+ int len;
+ char *n;
+
+ if (!s)
+ s = "";
+ len = strlen(s);
+ if (len > 60)
+ len = 60;
+ n = malloc(len+1);
+ memcpy(n, s, len);
+ n[len] = 0;
+ *str = n;
+}
+
+static void get_location(struct dive *dive, char **str)
+{
+ get_string(str, dive->location);
+}
+
+static void get_cylinder(struct dive *dive, char **str)
+{
+ get_string(str, dive->cylinder[0].type.description);
+}
+
+/*
+ * Set up anything that could have changed due to editing
+ * of dive information
+ */
+static void fill_one_dive(struct dive *dive,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ char *location, *cylinder;
+
+ get_cylinder(dive, &cylinder);
+ get_location(dive, &location);
+
+ gtk_tree_store_set(GTK_TREE_STORE(model), iter,
+ DIVE_NR, dive->number,
+ DIVE_LOCATION, location,
+ DIVE_CYLINDER, cylinder,
+ DIVE_RATING, dive->rating,
+ DIVE_SAC, dive->sac,
+ DIVE_OTU, dive->otu,
+ -1);
+}
+
+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 = GTK_TREE_MODEL(dive_list.model);
+
+ 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 = GTK_TREE_MODEL(dive_list.model);
+
+ (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);
+
+ 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, visible_cols.cylinder);
+ gtk_tree_view_column_set_visible(dive_list.temperature, visible_cols.temperature);
+ gtk_tree_view_column_set_visible(dive_list.nitrox, visible_cols.nitrox);
+ gtk_tree_view_column_set_visible(dive_list.sac, visible_cols.sac);
+ gtk_tree_view_column_set_visible(dive_list.otu, visible_cols.otu);
+ return;
+}
+
+static int new_date(struct dive *dive, struct dive **last_dive, const int flag, time_t *tm_date)
+{
+ if (!last_dive)
+ return TRUE;
+ if (*last_dive) {
+ struct dive *ldive = *last_dive;
+ struct tm tm1, tm2;
+ (void) gmtime_r(&dive->when, &tm1);
+ (void) gmtime_r(&ldive->when, &tm2);
+ if (tm1.tm_year == tm2.tm_year &&
+ (tm1.tm_mon == tm2.tm_mon || flag > NEW_MON) &&
+ (tm1.tm_mday == tm2.tm_mday || flag > NEW_DAY))
+ return FALSE;
+ }
+ if (flag == NEW_DAY)
+ *last_dive = dive;
+ if (tm_date) {
+ struct tm *tm1 = gmtime(&dive->when);
+ tm1->tm_sec = 0;
+ tm1->tm_min = 0;
+ tm1->tm_hour = 0;
+ *tm_date = mktime(tm1);
+ }
+ return TRUE;
+}
+
+static void fill_dive_list(void)
+{
+ int i, j;
+ GtkTreeIter iter, parent_iter[NEW_YR + 2], *parents[NEW_YR + 2] = {NULL, };
+ GtkTreeStore *store;
+ struct dive *last_dive = NULL;
+ time_t dive_date;
+
+ store = GTK_TREE_STORE(dive_list.model);
+
+ i = dive_table.nr;
+ while (--i >= 0) {