summaryrefslogtreecommitdiffstats
path: root/divelist.c
diff options
context:
space:
mode:
authorGravatar Tomaz Canabrava <tomaz.canabrava@intel.com>2015-09-02 20:52:34 -0300
committerGravatar Dirk Hohndel <dirk@hohndel.org>2015-10-30 10:36:48 -0700
commit4c0156e3d51b389db8eccc3fa3da4b8f248f9b13 (patch)
tree966868d29150fdba13a5a56fb4305bc432ec7a72 /divelist.c
parenta0798214231c652ac6142228f5ddfc4b65c921f8 (diff)
downloadsubsurface-4c0156e3d51b389db8eccc3fa3da4b8f248f9b13.tar.gz
Move all core-functionality to subsurface-core
And adapt a new CMakeLists.txt file for it. On the way I've also found out that we where double-compilling a few files. I've also set the subsurface-core as a include_path but that was just to reduce the noise on this commit, since I plan to remove it from the include path to make it obligatory to specify something like include "subsurface-core/dive.h" for the header files. Since the app is growing quite a bit we ended up having a few different files with almost same name that did similar things, I want to kill that (for instance Dive.h, dive.h, PrintDive.h and such). Signed-off-by: Tomaz Canabrava <tomaz.canabrava@intel.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'divelist.c')
-rw-r--r--divelist.c1141
1 files changed, 0 insertions, 1141 deletions
diff --git a/divelist.c b/divelist.c
deleted file mode 100644
index a14fabf88..000000000
--- a/divelist.c
+++ /dev/null
@@ -1,1141 +0,0 @@
-/* divelist.c */
-/* core logic for the dive list -
- * accessed through the following interfaces:
- *
- * 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 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 delete_single_dive(int idx)
- * void add_single_dive(int idx, struct dive *dive)
- * void merge_two_dives(struct dive *a, struct dive *b)
- * 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>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-#include "gettext.h"
-#include <assert.h>
-#include <zip.h>
-#include <libxslt/transform.h>
-
-#include "dive.h"
-#include "divelist.h"
-#include "display.h"
-#include "planner.h"
-#include "qthelperfromc.h"
-
-static short dive_list_changed = false;
-
-short autogroup = false;
-
-dive_trip_t *dive_trip_list;
-
-unsigned int amount_selected;
-
-#if DEBUG_SELECTION_TRACKING
-void dump_selection(void)
-{
- int i;
- struct dive *dive;
-
- printf("currently selected are %u dives:", amount_selected);
- for_each_dive(i, dive) {
- if (dive->selected)
- printf(" %d", i);
- }
- printf("\n");
-}
-#endif
-
-void set_autogroup(bool value)
-{
- /* if we keep the UI paradigm, this needs to toggle
- * the checkbox on the autogroup menu item */
- autogroup = value;
-}
-
-dive_trip_t *find_trip_by_idx(int idx)
-{
- dive_trip_t *trip = dive_trip_list;
-
- if (idx >= 0)
- return NULL;
- idx = -idx;
- while (trip) {
- if (trip->index == idx)
- return trip;
- trip = trip->next;
- }
- return NULL;
-}
-
-int trip_has_selected_dives(dive_trip_t *trip)
-{
- struct dive *dive;
- for (dive = trip->dives; dive; dive = dive->next) {
- if (dive->selected)
- return 1;
- }
- return 0;
-}
-
-/*
- * Get "maximal" dive gas for a dive.
- * Rules:
- * - Trimix trumps nitrox (highest He wins, O2 breaks ties)
- * - Nitrox trumps air (even if hypoxic)
- * These are the same rules as the inter-dive sorting rules.
- */
-void get_dive_gas(struct dive *dive, int *o2_p, int *he_p, int *o2max_p)
-{
- int i;
- int maxo2 = -1, maxhe = -1, mino2 = 1000;
-
-
- for (i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = dive->cylinder + i;
- int o2 = get_o2(&cyl->gasmix);
- int he = get_he(&cyl->gasmix);
-
- if (!is_cylinder_used(dive, i))
- continue;
- if (cylinder_none(cyl))
- continue;
- if (o2 > maxo2)
- maxo2 = o2;
- if (he > maxhe)
- goto newmax;
- if (he < maxhe)
- continue;
- if (o2 <= maxo2)
- continue;
- newmax:
- maxhe = he;
- mino2 = o2;
- }
- /* All air? Show/sort as "air"/zero */
- if ((!maxhe && maxo2 == O2_IN_AIR && mino2 == maxo2) ||
- (maxo2 == -1 && maxhe == -1 && mino2 == 1000))
- maxo2 = mino2 = 0;
- *o2_p = mino2;
- *he_p = maxhe;
- *o2max_p = maxo2;
-}
-
-int total_weight(struct dive *dive)
-{
- int i, total_grams = 0;
-
- if (dive)
- for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
- total_grams += dive->weightsystem[i].weight.grams;
- return total_grams;
-}
-
-static int active_o2(struct dive *dive, struct divecomputer *dc, duration_t time)
-{
- struct gasmix gas;
- get_gas_at_time(dive, dc, time, &gas);
- return get_o2(&gas);
-}
-
-/* calculate OTU for a dive - this only takes the first divecomputer into account */
-static int calculate_otu(struct dive *dive)
-{
- int i;
- double otu = 0.0;
- struct divecomputer *dc = &dive->dc;
-
- for (i = 1; i < dc->samples; i++) {
- int t;
- int po2;
- struct sample *sample = dc->sample + i;
- struct sample *psample = sample - 1;
- t = sample->time.seconds - psample->time.seconds;
- if (sample->setpoint.mbar) {
- po2 = sample->setpoint.mbar;
- } else {
- int o2 = active_o2(dive, dc, sample->time);
- po2 = o2 * depth_to_atm(sample->depth.mm, dive);
- }
- if (po2 >= 500)
- otu += pow((po2 - 500) / 1000.0, 0.83) * t / 30.0;
- }
- return rint(otu);
-}
-/* calculate CNS for a dive - this only takes the first divecomputer into account */
-int const cns_table[][3] = {
- /* po2, Maximum Single Exposure, Maximum 24 hour Exposure */
- { 1600, 45 * 60, 150 * 60 },
- { 1500, 120 * 60, 180 * 60 },
- { 1400, 150 * 60, 180 * 60 },
- { 1300, 180 * 60, 210 * 60 },
- { 1200, 210 * 60, 240 * 60 },
- { 1100, 240 * 60, 270 * 60 },
- { 1000, 300 * 60, 300 * 60 },
- { 900, 360 * 60, 360 * 60 },
- { 800, 450 * 60, 450 * 60 },
- { 700, 570 * 60, 570 * 60 },
- { 600, 720 * 60, 720 * 60 }
-};
-
-/* this only gets called if dive->maxcns == 0 which means we know that
- * none of the divecomputers has tracked any CNS for us
- * so we calculated it "by hand" */
-static int calculate_cns(struct dive *dive)
-{
- int i, j, divenr;
- double cns = 0.0;
- struct divecomputer *dc = &dive->dc;
- struct dive *prev_dive;
- timestamp_t endtime;
-
- /* shortcut */
- if (dive->cns)
- return dive->cns;
- /*
- * Do we start with a cns loading from a previous dive?
- * Check if we did a dive 12 hours prior, and what cns we had from that.
- * Then apply ha 90min halftime to see whats left.
- */
- divenr = get_divenr(dive);
- if (divenr) {
- prev_dive = get_dive(divenr - 1);
- if (prev_dive) {
- endtime = prev_dive->when + prev_dive->duration.seconds;
- if (dive->when < (endtime + 3600 * 12)) {
- cns = calculate_cns(prev_dive);
- cns = cns * 1 / pow(2, (dive->when - endtime) / (90.0 * 60.0));
- }
- }
- }
- /* Caclulate the cns for each sample in this dive and sum them */
- for (i = 1; i < dc->samples; i++) {
- int t;
- int po2;
- struct sample *sample = dc->sample + i;
- struct sample *psample = sample - 1;
- t = sample->time.seconds - psample->time.seconds;
- if (sample->setpoint.mbar) {
- po2 = sample->setpoint.mbar;
- } else {
- int o2 = active_o2(dive, dc, sample->time);
- po2 = o2 * depth_to_atm(sample->depth.mm, dive);
- }
- /* CNS don't increse when below 500 matm */
- if (po2 < 500)
- continue;
- /* Find what table-row we should calculate % for */
- for (j = 1; j < sizeof(cns_table) / (sizeof(int) * 3); j++)
- if (po2 > cns_table[j][0])
- break;
- j--;
- cns += ((double)t) / ((double)cns_table[j][1]) * 100;
- }
- /* save calculated cns in dive struct */
- dive->cns = cns;
- return dive->cns;
-}
-/*
- * Return air usage (in liters).
- */
-static double calculate_airuse(struct dive *dive)
-{
- int airuse = 0;
- int i;
-
- for (i = 0; i < MAX_CYLINDERS; i++) {
- pressure_t start, end;
- cylinder_t *cyl = dive->cylinder + i;
-
- start = cyl->start.mbar ? cyl->start : cyl->sample_start;
- end = cyl->end.mbar ? cyl->end : cyl->sample_end;
- if (!end.mbar || start.mbar <= end.mbar)
- continue;
-
- airuse += gas_volume(cyl, start) - gas_volume(cyl, end);
- }
- return airuse / 1000.0;
-}
-
-/* this only uses the first divecomputer to calculate the SAC rate */
-static int calculate_sac(struct dive *dive)
-{
- struct divecomputer *dc = &dive->dc;
- double airuse, pressure, sac;
- int duration, meandepth;
-
- airuse = calculate_airuse(dive);
- if (!airuse)
- return 0;
-
- duration = dc->duration.seconds;
- if (!duration)
- return 0;
-
- meandepth = dc->meandepth.mm;
- if (!meandepth)
- return 0;
-
- /* Mean pressure in ATM (SAC calculations are in atm*l/min) */
- pressure = depth_to_atm(meandepth, dive);
- sac = airuse / pressure * 60 / duration;
-
- /* milliliters per minute.. */
- return sac * 1000;
-}
-
-/* for now we do this based on the first divecomputer */
-static void add_dive_to_deco(struct dive *dive)
-{
- struct divecomputer *dc = &dive->dc;
- int i;
-
- if (!dc)
- return;
- for (i = 1; i < dc->samples; i++) {
- struct sample *psample = dc->sample + i - 1;
- struct sample *sample = dc->sample + i;
- int t0 = psample->time.seconds;
- int t1 = sample->time.seconds;
- int j;
-
- for (j = t0; j < t1; j++) {
- int depth = interpolate(psample->depth.mm, sample->depth.mm, j - t0, t1 - t0);
- add_segment(depth_to_bar(depth, dive),
- &dive->cylinder[sample->sensor].gasmix, 1, sample->setpoint.mbar, dive, dive->sac);
- }
- }
-}
-
-int get_divenr(struct dive *dive)
-{
- int i;
- struct dive *d;
- // tempting as it may be, don't die when called with dive=NULL
- if (dive)
- for_each_dive(i, d) {
- if (d->id == dive->id) // don't compare pointers, we could be passing in a copy of the dive
- return i;
- }
- return -1;
-}
-
-int get_divesite_idx(struct dive_site *ds)
-{
- int i;
- struct dive_site *d;
- // tempting as it may be, don't die when called with dive=NULL
- if (ds)
- for_each_dive_site(i, d) {
- if (d->uuid == ds->uuid) // don't compare pointers, we could be passing in a copy of the dive
- return i;
- }
- return -1;
-}
-
-static struct gasmix air = { .o2.permille = O2_IN_AIR, .he.permille = 0 };
-
-/* take into account previous dives until there is a 48h gap between dives */
-double init_decompression(struct dive *dive)
-{
- int i, divenr = -1;
- unsigned int surface_time;
- timestamp_t when, lasttime = 0, laststart = 0;
- bool deco_init = false;
- double surface_pressure;
-
- if (!dive)
- return 0.0;
-
- surface_pressure = get_surface_pressure_in_mbar(dive, true) / 1000.0;
- divenr = get_divenr(dive);
- when = dive->when;
- i = divenr;
- if (i < 0) {
- i = dive_table.nr - 1;
- while (i >= 0 && get_dive(i)->when > when)
- --i;
- i++;
- }
- while (i--) {
- struct dive *pdive = get_dive(i);
- /* we don't want to mix dives from different trips as we keep looking
- * for how far back we need to go */
- if (dive->divetrip && pdive->divetrip != dive->divetrip)
- continue;
- if (!pdive || pdive->when >= when || pdive->when + pdive->duration.seconds + 48 * 60 * 60 < when)
- break;
- /* For simultaneous dives, only consider the first */
- if (pdive->when == laststart)
- continue;
- when = pdive->when;
- lasttime = when + pdive->duration.seconds;
- }
- while (++i < (divenr >= 0 ? divenr : dive_table.nr)) {
- struct dive *pdive = get_dive(i);
- /* again skip dives from different trips */
- if (dive->divetrip && dive->divetrip != pdive->divetrip)
- continue;
- surface_pressure = get_surface_pressure_in_mbar(pdive, true) / 1000.0;
- if (!deco_init) {
- clear_deco(surface_pressure);
- deco_init = true;
-#if DECO_CALC_DEBUG & 2
- dump_tissues();
-#endif
- }
- add_dive_to_deco(pdive);
- laststart = pdive->when;
-#if DECO_CALC_DEBUG & 2
- printf("added dive #%d\n", pdive->number);
- dump_tissues();
-#endif
- if (pdive->when > lasttime) {
- surface_time = pdive->when - lasttime;
- lasttime = pdive->when + pdive->duration.seconds;
- add_segment(surface_pressure, &air, surface_time, 0, dive, prefs.decosac);
-#if DECO_CALC_DEBUG & 2
- printf("after surface intervall of %d:%02u\n", FRACTION(surface_time, 60));
- dump_tissues();
-#endif
- }
- }
- /* add the final surface time */
- if (lasttime && dive->when > lasttime) {
- surface_time = dive->when - lasttime;
- surface_pressure = get_surface_pressure_in_mbar(dive, true) / 1000.0;
- add_segment(surface_pressure, &air, surface_time, 0, dive, prefs.decosac);
-#if DECO_CALC_DEBUG & 2
- printf("after surface intervall of %d:%02u\n", FRACTION(surface_time, 60));
- dump_tissues();
-#endif
- }
- if (!deco_init) {
- surface_pressure = get_surface_pressure_in_mbar(dive, true) / 1000.0;
- clear_deco(surface_pressure);
-#if DECO_CALC_DEBUG & 2
- printf("no previous dive\n");
- dump_tissues();
-#endif
- }
- return tissue_tolerance_calc(dive, surface_pressure);
-}
-
-void update_cylinder_related_info(struct dive *dive)
-{
- if (dive != NULL) {
- dive->sac = calculate_sac(dive);
- dive->otu = calculate_otu(dive);
- if (dive->maxcns == 0)
- dive->maxcns = calculate_cns(dive);
- }
-}
-
-#define MAX_GAS_STRING 80
-#define UTF8_ELLIPSIS "\xE2\x80\xA6"
-
-/* callers needs to free the string */
-char *get_dive_gas_string(struct dive *dive)
-{
- int o2, he, o2max;
- char *buffer = malloc(MAX_GAS_STRING);
-
- if (buffer) {
- get_dive_gas(dive, &o2, &he, &o2max);
- o2 = (o2 + 5) / 10;
- he = (he + 5) / 10;
- o2max = (o2max + 5) / 10;
-
- if (he)
- if (o2 == o2max)
- snprintf(buffer, MAX_GAS_STRING, "%d/%d", o2, he);
- else
- snprintf(buffer, MAX_GAS_STRING, "%d/%d" UTF8_ELLIPSIS "%d%%", o2, he, o2max);
- else if (o2)
- if (o2 == o2max)
- snprintf(buffer, MAX_GAS_STRING, "%d%%", o2);
- else
- snprintf(buffer, MAX_GAS_STRING, "%d" UTF8_ELLIPSIS "%d%%", o2, o2max);
- else
- strcpy(buffer, translate("gettextFromC", "air"));
- }
- return buffer;
-}
-
-/*
- * helper functions for dive_trip handling
- */
-#ifdef DEBUG_TRIP
-void dump_trip_list(void)
-{
- dive_trip_t *trip;
- int i = 0;
- timestamp_t last_time = 0;
-
- for (trip = dive_trip_list; trip; trip = trip->next) {
- struct tm tm;
- utc_mkdate(trip->when, &tm);
- if (trip->when < last_time)
- printf("\n\ndive_trip_list OUT OF ORDER!!!\n\n\n");
- printf("%s trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u (%d dives - %p)\n",
- trip->autogen ? "autogen " : "",
- ++i, trip->location,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
- trip->nrdives, trip);
- last_time = trip->when;
- }
- printf("-----\n");
-}
-#endif
-
-/* this finds the last trip that at or before the time given */
-dive_trip_t *find_matching_trip(timestamp_t when)
-{
- dive_trip_t *trip = dive_trip_list;
-
- if (!trip || trip->when > when) {
-#ifdef DEBUG_TRIP
- printf("no matching trip\n");
-#endif
- return NULL;
- }
- while (trip->next && trip->next->when <= when)
- trip = trip->next;
-#ifdef DEBUG_TRIP
- {
- struct tm tm;
- utc_mkdate(trip->when, &tm);
- printf("found trip %p @ %04d-%02d-%02d %02d:%02d:%02d\n",
- trip,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- }
-#endif
- return trip;
-}
-
-/* insert the trip into the dive_trip_list - but ensure you don't have
- * two trips for the same date; but if you have, make sure you don't
- * keep the one with less information */
-void insert_trip(dive_trip_t **dive_trip_p)
-{
- dive_trip_t *dive_trip = *dive_trip_p;
- dive_trip_t **p = &dive_trip_list;
- dive_trip_t *trip;
- struct dive *divep;
-
- /* Walk the dive trip list looking for the right location.. */
- while ((trip = *p) != NULL && trip->when < dive_trip->when)
- p = &trip->next;
-
- if (trip && trip->when == dive_trip->when) {
- if (!trip->location)
- trip->location = dive_trip->location;
- if (!trip->notes)
- trip->notes = dive_trip->notes;
- divep = dive_trip->dives;
- while (divep) {
- add_dive_to_trip(divep, trip);
- divep = divep->next;
- }
- *dive_trip_p = trip;
- } else {
- dive_trip->next = trip;
- *p = dive_trip;
- }
-#ifdef DEBUG_TRIP
- dump_trip_list();
-#endif
-}
-
-static void delete_trip(dive_trip_t *trip)
-{
- dive_trip_t **p, *tmp;
-
- assert(!trip->dives);
-
- /* Remove the trip from the list of trips */
- p = &dive_trip_list;
- while ((tmp = *p) != NULL) {
- if (tmp == trip) {
- *p = trip->next;
- break;
- }
- p = &tmp->next;
- }
-
- /* .. and free it */
- free(trip->location);
- free(trip->notes);
- free(trip);
-}
-
-void find_new_trip_start_time(dive_trip_t *trip)
-{
- struct dive *dive = trip->dives;
- timestamp_t when = dive->when;
-
- while ((dive = dive->next) != NULL) {
- if (dive->when < when)
- when = dive->when;
- }
- trip->when = when;
-}
-
-/* check if we have a trip right before / after this dive */
-bool is_trip_before_after(struct dive *dive, bool before)
-{
- int idx = get_idx_by_uniq_id(dive->id);
- if (before) {
- if (idx > 0 && get_dive(idx - 1)->divetrip)
- return true;
- } else {
- if (idx < dive_table.nr - 1 && get_dive(idx + 1)->divetrip)
- return true;
- }
- return false;
-}
-
-struct dive *first_selected_dive()
-{
- int idx;
- struct dive *d;
-
- for_each_dive (idx, d) {
- if (d->selected)
- return d;
- }
- return NULL;
-}
-
-struct dive *last_selected_dive()
-{
- int idx;
- struct dive *d, *ret = NULL;
-
- for_each_dive (idx, d) {
- if (d->selected)
- ret = d;
- }
- return ret;
-}
-
-void remove_dive_from_trip(struct dive *dive, short was_autogen)
-{
- struct dive *next, **pprev;
- dive_trip_t *trip = dive->divetrip;
-
- if (!trip)
- return;
-
- /* Remove the dive from the trip's list of dives */
- next = dive->next;
- pprev = dive->pprev;
- *pprev = next;
- if (next)
- next->pprev = pprev;
-
- dive->divetrip = NULL;
- if (was_autogen)
- dive->tripflag = TF_NONE;
- else
- dive->tripflag = NO_TRIP;
- assert(trip->nrdives > 0);
- if (!--trip->nrdives)
- delete_trip(trip);
- else if (trip->when == dive->when)
- find_new_trip_start_time(trip);
-}
-
-void add_dive_to_trip(struct dive *dive, dive_trip_t *trip)
-{
- if (dive->divetrip == trip)
- return;
- remove_dive_from_trip(dive, false);
- trip->nrdives++;
- dive->divetrip = trip;
- dive->tripflag = ASSIGNED_TRIP;
-
- /* Add it to the trip's list of dives*/
- dive->next = trip->dives;
- if (dive->next)
- dive->next->pprev = &dive->next;
- trip->dives = dive;
- dive->pprev = &trip->dives;
-
- if (dive->when && trip->when > dive->when)
- trip->when = dive->when;
-}
-
-dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive)
-{
- dive_trip_t *dive_trip = calloc(1, sizeof(dive_trip_t));
-
- dive_trip->when = dive->when;
- dive_trip->location = copy_string(get_dive_location(dive));
- insert_trip(&dive_trip);
-
- dive->tripflag = IN_TRIP;
- add_dive_to_trip(dive, dive_trip);
- return dive_trip;
-}
-
-/*
- * Walk the dives from the oldest dive, and see if we can autogroup them
- */
-void autogroup_dives(void)
-{
- int i;
- struct dive *dive, *lastdive = NULL;
-
- for_each_dive(i, dive) {
- dive_trip_t *trip;
-
- if (dive->divetrip) {
- lastdive = dive;
- continue;
- }
-
- if (!DIVE_NEEDS_TRIP(dive)) {
- lastdive = NULL;
- continue;
- }
-
- /* Do we have a trip we can combine this into? */
- if (lastdive && dive->when < lastdive->when + TRIP_THRESHOLD) {
- dive_trip_t *trip = lastdive->divetrip;
- add_dive_to_trip(dive, trip);
- if (get_dive_location(dive) && !trip->location)
- trip->location = copy_string(get_dive_location(dive));
- lastdive = dive;
- continue;
- }
-
- lastdive = dive;
- trip = create_and_hookup_trip_from_dive(dive);
- trip->autogen = 1;
- }
-
-#ifdef DEBUG_TRIP
- dump_trip_list();
-#endif
-}
-
-/* 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)
-{
- int i;
- struct dive *dive = get_dive(idx);
- if (!dive)
- return; /* this should never happen */
- remove_dive_from_trip(dive, false);
- if (dive->selected)
- deselect_dive(idx);
- for (i = idx; i < dive_table.nr - 1; i++)
- dive_table.dives[i] = dive_table.dives[i + 1];
- dive_table.dives[--dive_table.nr] = NULL;
- /* free all allocations */
- free(dive->dc.sample);
- free((void *)dive->notes);
- free((void *)dive->divemaster);
- free((void *)dive->buddy);
- free((void *)dive->suit);
- taglist_free(dive->tag_list);
- free(dive);
-}
-
-struct dive **grow_dive_table(struct dive_table *table)
-{
- int nr = table->nr, allocated = table->allocated;
- struct dive **dives = table->dives;
-
- if (nr >= allocated) {
- allocated = (nr + 32) * 3 / 2;
- dives = realloc(dives, allocated * sizeof(struct dive *));
- if (!dives)
- exit(1);
- table->dives = dives;
- table->allocated = allocated;
- }
- return dives;
-}
-
-void add_single_dive(int idx, struct dive *dive)
-{
- int i;
- grow_dive_table(&dive_table);
- dive_table.nr++;
- if (dive->selected)
- amount_selected++;
- for (i = idx; i < dive_table.nr; i++) {
- struct dive *tmp = dive_table.dives[i];
- dive_table.dives[i] = dive;
- dive = tmp;
- }
-}
-
-bool consecutive_selected()
-{
- struct dive *d;
- int i;
- bool consecutive = true;
- bool firstfound = false;
- bool lastfound = false;
-
- if (amount_selected == 0 || amount_selected == 1)
- return true;
-
- for_each_dive(i, d) {
- if (d->selected) {
- if (!firstfound)
- firstfound = true;
- else if (lastfound)
- consecutive = false;
- } else if (firstfound) {
- lastfound = true;
- }
- }
- return consecutive;
-}
-
-struct dive *merge_two_dives(struct dive *a, struct dive *b)
-{
- struct dive *res;
- int i, j;
- int id;
-
- if (!a || !b)
- return NULL;
-
- id = a->id;
- i = get_divenr(a);
- j = get_divenr(b);
- if (i < 0 || j < 0)
- // something is wrong with those dives. Bail
- return NULL;
- res = merge_dives(a, b, b->when - a->when, false);
- if (!res)
- return NULL;
-
- add_single_dive(i, res);
- delete_single_dive(i + 1);
- delete_single_dive(j);
- // now make sure that we keep the id of the first dive.
- // why?
- // because this way one of the previously selected ids is still around
- res->id = id;
- mark_divelist_changed(true);
- return res;
-}
-
-void select_dive(int idx)
-{
- struct dive *dive = get_dive(idx);
- if (dive) {
- /* never select an invalid dive that isn't displayed */
- if (!dive->selected) {
- dive->selected = 1;
- amount_selected++;
- }
- selected_dive = idx;
- }
-}
-
-void deselect_dive(int idx)
-{
- struct dive *dive = get_dive(idx);
- if (dive && dive->selected) {
- dive->selected = 0;
- if (amount_selected)
- amount_selected--;
- if (selected_dive == idx && amount_selected > 0) {
- /* pick a different dive as selected */
- while (--selected_dive >= 0) {
- dive = get_dive(selected_dive);
- if (dive && dive->selected)
- return;
- }
- selected_dive = idx;
- while (++selected_dive < dive_table.nr) {
- dive = get_dive(selected_dive);
- if (dive && dive->selected)
- return;
- }
- }
- if (amount_selected == 0)
- selected_dive = -1;
- }
-}
-
-void deselect_dives_in_trip(struct dive_trip *trip)
-{
- struct dive *dive;
- if (!trip)
- return;
- for (dive = trip->dives; dive; dive = dive->next)
- deselect_dive(get_divenr(dive));
-}
-
-void select_dives_in_trip(struct dive_trip *trip)
-{
- struct dive *dive;
- if (!trip)
- return;
- for (dive = trip->dives; dive; dive = dive->next)
- if (!dive->hidden_by_filter)
- select_dive(get_divenr(dive));
-}
-
-void filter_dive(struct dive *d, bool shown)
-{
- if (!d)
- return;
- d->hidden_by_filter = !shown;
- if (!shown && d->selected)
- deselect_dive(get_divenr(d));
-}
-
-
-/* This only gets called with non-NULL trips.
- * It does not combine notes or location, just picks the first one
- * (or the second one if the first one is empty */
-void combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b)
-{
- if (same_string(trip_a->location, "") && trip_b->location) {
- free(trip_a->location);
- trip_a->location = strdup(trip_b->location);
- }
- if (same_string(trip_a->notes, "") && trip_b->notes) {
- free(trip_a->notes);
- trip_a->notes = strdup(trip_b->notes);
- }
- /* this also removes the dives from trip_b and eventually
- * calls delete_trip(trip_b) when the last dive has been moved */
- while (trip_b->dives)
- add_dive_to_trip(trip_b->dives, trip_a);
-}
-
-void mark_divelist_changed(int changed)
-{
- dive_list_changed = changed;
- updateWindowTitle();
-}
-
-int unsaved_changes()
-{
- return dive_list_changed;
-}
-
-void remove_autogen_trips()
-{
- int i;
- struct dive *dive;
-
- for_each_dive(i, dive) {
- dive_trip_t *trip = dive->divetrip;
-
- if (trip && trip->autogen)
- remove_dive_from_trip(dive, true);
- }
-}
-
-/*
- * When adding dives to the dive table, we try to renumber
- * the new dives based on any old dives in the dive table.
- *
- * But we only do it if:
- *
- * - there are no dives in the dive table
- *
- * OR
- *
- * - the last dive in the old dive table was numbered
- *
- * - all the new dives are strictly at the end (so the
- * "last dive" is at the same location in the dive table
- * after re-sorting the dives.
- *
- * - none of the new dives have any numbers
- *
- * This catches the common case of importing new dives from
- * a dive computer, and gives them proper numbers based on
- * your old dive list. But it tries to be very conservative
- * and not give numbers if there is *any* question about
- * what the numbers should be - in which case you need to do
- * a manual re-numbering.
- */
-static void try_to_renumber(struct dive *last, int preexisting)
-{
- int i, nr;
-
- /*
- * If the new dives aren't all strictly at the end,
- * we're going to expect the user to do a manual
- * renumbering.
- */
- if (preexisting && get_dive(preexisting - 1) != last)
- return;
-
- /*
- * If any of the new dives already had a number,
- * we'll have to do a manual renumbering.
- */
- for (i = preexisting; i < dive_table.nr; i++) {
- struct dive *dive = get_dive(i);
- if (dive->number)
- return;
- }
-
- /*
- * Ok, renumber..
- */
- if (last)
- nr = last->number;
- else
- nr = 0;
- for (i = preexisting; i < dive_table.nr; i++) {
- struct dive *dive = get_dive(i);
- dive->number = ++nr;
- }
-}
-
-void process_dives(bool is_imported, bool prefer_imported)
-{
- int i;
- int preexisting = dive_table.preexisting;
- bool did_merge = false;
- struct dive *last;
-
- /* check if we need a nickname for the divecomputer for newly downloaded dives;
- * since we know they all came from the same divecomputer we just check for the
- * first one */
- if (preexisting < dive_table.nr && dive_table.dives[preexisting]->downloaded)
- set_dc_nickname(dive_table.dives[preexisting]);
- else
- /* they aren't downloaded, so record / check all new ones */
- for (i = preexisting; i < dive_table.nr; i++)
- set_dc_nickname(dive_table.dives[i]);
-
- for (i = preexisting; i < dive_table.nr; i++)
- dive_table.dives[i]->downloaded = true;
-
- /* This does the right thing for -1: NULL */
- last = get_dive(preexisting - 1);
-
- sort_table(&dive_table);
-
- for (i = 1; i < dive_table.nr; i++) {
- struct dive **pp = &dive_table.dives[i - 1];
- struct dive *prev = pp[0];
- struct dive *dive = pp[1];
- struct dive *merged;
- int id;
-
- /* only try to merge overlapping dives - or if one of the dives has
- * zero duration (that might be a gps marker from the webservice) */
- if (prev->duration.seconds && dive->duration.seconds &&
- prev->when + prev->duration.seconds < dive->when)
- continue;
-
- merged = try_to_merge(prev, dive, prefer_imported);
- if (!merged)
- continue;
-
- // remember the earlier dive's id
- id = prev->id;
-
- /* careful - we might free the dive that last points to. Oops... */
- if (last == prev || last == dive)
- last = merged;
-
- /* Redo the new 'i'th dive */
- i--;
- add_single_dive(i, merged);
- delete_single_dive(i + 1);
- delete_single_dive(i + 1);
- // keep the id or the first dive for the merged dive
- merged->id = id;
-
- /* this means the table was changed */
- did_merge = true;
- }
- /* make sure no dives are still marked as downloaded */
- for (i = 1; i < dive_table.nr; i++)
- dive_table.dives[i]->downloaded = false;
-
- if (is_imported) {
- /* If there are dives in the table, are they numbered */
- if (!last || last->number)
- try_to_renumber(last, preexisting);
-
- /* did we add dives or divecomputers to the dive table? */
- if (did_merge || preexisting < dive_table.nr) {
- mark_divelist_changed(true);
- }
- }
-}
-
-void set_dive_nr_for_current_dive()
-{
- if (dive_table.nr == 1)
- current_dive->number = 1;
- else if (selected_dive == dive_table.nr - 1 && get_dive(dive_table.nr - 2)->number)
- current_dive->number = get_dive(dive_table.nr - 2)->number + 1;
-}
-
-static int min_datafile_version;
-
-int get_min_datafile_version()
-{
- return min_datafile_version;
-}
-
-void reset_min_datafile_version()
-{
- min_datafile_version = 0;
-}
-
-void report_datafile_version(int version)
-{
- if (min_datafile_version == 0 || min_datafile_version > version)
- min_datafile_version = version;
-}
-
-void clear_dive_file_data()
-{
- while (dive_table.nr)
- delete_single_dive(0);
- while (dive_site_table.nr)
- delete_dive_site(get_dive_site(0)->uuid);
-
- clear_dive(&displayed_dive);
- clear_dive_site(&displayed_dive_site);
-
- free((void *)existing_filename);
- existing_filename = NULL;
-
- reset_min_datafile_version();
-}