summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/dive.c96
-rw-r--r--core/dive.h15
-rw-r--r--core/equipment.c61
-rw-r--r--core/equipment.h5
-rw-r--r--core/parse-xml.c25
-rw-r--r--core/planner.c33
-rw-r--r--core/profile.c13
-rw-r--r--core/qthelper.cpp33
-rw-r--r--core/qthelper.h2
-rw-r--r--core/subsurface-qt/divelistnotifier.h6
10 files changed, 182 insertions, 107 deletions
diff --git a/core/dive.c b/core/dive.c
index c97c229f6..df5d7951d 100644
--- a/core/dive.c
+++ b/core/dive.c
@@ -11,6 +11,7 @@
#include "device.h"
#include "divelist.h"
#include "divesite.h"
+#include "errorhelper.h"
#include "qthelper.h"
#include "metadata.h"
#include "membuffer.h"
@@ -126,10 +127,10 @@ int event_is_gaschange(const struct event *ev)
ev->type == SAMPLE_EVENT_GASCHANGE2;
}
-struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name)
+struct event *create_event(unsigned int time, int type, int flags, int value, const char *name)
{
int gas_index = -1;
- struct event *ev, **p;
+ struct event *ev;
unsigned int size, len = strlen(name);
size = sizeof(*ev) + len + 1;
@@ -164,18 +165,85 @@ struct event *add_event(struct divecomputer *dc, unsigned int time, int type, in
break;
}
+ return ev;
+}
+
+/* warning: does not test idx for validity */
+struct event *create_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
+{
+ /* The gas switch event format is insane for historical reasons */
+ struct gasmix mix = get_cylinder(dive, idx)->gasmix;
+ int o2 = get_o2(mix);
+ int he = get_he(mix);
+ struct event *ev;
+ int value;
+
+ o2 = (o2 + 5) / 10;
+ he = (he + 5) / 10;
+ value = o2 + (he << 16);
+
+ ev = create_event(seconds, he ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE, 0, value, "gaschange");
+ ev->gas.index = idx;
+ ev->gas.mix = mix;
+ return ev;
+}
+
+struct event *clone_event_rename(const struct event *ev, const char *name)
+{
+ return create_event(ev->time.seconds, ev->type, ev->flags, ev->value, name);
+}
+
+void add_event_to_dc(struct divecomputer *dc, struct event *ev)
+{
+ struct event **p;
+
p = &dc->events;
/* insert in the sorted list of events */
- while (*p && (*p)->time.seconds <= time)
+ while (*p && (*p)->time.seconds <= ev->time.seconds)
p = &(*p)->next;
ev->next = *p;
*p = ev;
+}
+
+struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name)
+{
+ struct event *ev = create_event(time, type, flags, value, name);
+
+ if (!ev)
+ return NULL;
+
+ add_event_to_dc(dc, ev);
+
remember_event(name);
return ev;
}
-static int same_event(const struct event *a, const struct event *b)
+void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
+{
+ /* sanity check so we don't crash */
+ if (idx < 0 || idx >= dive->cylinders.nr) {
+ report_error("Unknown cylinder index: %d", idx);
+ return;
+ }
+ struct event *ev = create_gas_switch_event(dive, dc, seconds, idx);
+ add_event_to_dc(dc, ev);
+}
+
+/* Substitutes an event in a divecomputer for another. No reordering is performed! */
+void swap_event(struct divecomputer *dc, struct event *from, struct event *to)
+{
+ for (struct event **ep = &dc->events; *ep; ep = &(*ep)->next) {
+ if (*ep == from) {
+ to->next = from->next;
+ *ep = to;
+ from->next = NULL; // For good measure.
+ break;
+ }
+ }
+}
+
+bool same_event(const struct event *a, const struct event *b)
{
if (a->time.seconds != b->time.seconds)
return 0;
@@ -188,19 +256,15 @@ static int same_event(const struct event *a, const struct event *b)
return !strcmp(a->name, b->name);
}
-void remove_event(struct event *event)
+/* Remove given event from dive computer. Does *not* free the event. */
+void remove_event_from_dc(struct divecomputer *dc, struct event *event)
{
- struct event **ep = &current_dc->events;
- while (ep && !same_event(*ep, event))
- ep = &(*ep)->next;
- if (ep) {
- /* we can't link directly with event->next
- * because 'event' can be a copy from another
- * dive (for instance the displayed_dive
- * that we use on the interface to show things). */
- struct event *temp = (*ep)->next;
- free(*ep);
- *ep = temp;
+ for (struct event **ep = &dc->events; *ep; ep = &(*ep)->next) {
+ if (*ep == event) {
+ *ep = event->next;
+ event->next = NULL; // For good measure.
+ break;
+ }
}
}
diff --git a/core/dive.h b/core/dive.h
index 13de360ed..0d2dbc2a6 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -358,10 +358,15 @@ extern void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_
extern void copy_samples(const struct divecomputer *s, struct divecomputer *d);
extern bool is_cylinder_used(const struct dive *dive, int idx);
extern bool is_cylinder_prot(const struct dive *dive, int idx);
-extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl);
extern void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int time, int idx);
+extern struct event *create_event(unsigned int time, int type, int flags, int value, const char *name);
+extern struct event *create_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx);
+extern struct event *clone_event_rename(const struct event *ev, const char *name);
+extern void add_event_to_dc(struct divecomputer *dc, struct event *ev);
+extern void swap_event(struct divecomputer *dc, struct event *from, struct event *to);
+extern bool same_event(const struct event *a, const struct event *b);
extern struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name);
-extern void remove_event(struct event *event);
+extern void remove_event_from_dc(struct divecomputer *dc, struct event *event);
extern void update_event_name(struct dive *d, struct event *event, const char *name);
extern void add_extra_data(struct divecomputer *dc, const char *key, const char *value);
extern void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, int *mean, int *duration);
@@ -372,15 +377,9 @@ extern int nr_weightsystems(const struct dive *dive);
/* UI related protopypes */
-// extern void report_error(GError* error);
-
extern void remember_event(const char *eventname);
extern void invalidate_dive_cache(struct dive *dc);
-#if WE_DONT_USE_THIS /* this is a missing feature in Qt - selecting which events to display */
-extern int evn_foreach(void (*callback)(const char *, bool *, void *), void *data);
-#endif /* WE_DONT_USE_THIS */
-
extern void clear_events(void);
extern void set_dc_nickname(struct dive *dive);
diff --git a/core/equipment.c b/core/equipment.c
index c9c0539c3..4be46ed1e 100644
--- a/core/equipment.c
+++ b/core/equipment.c
@@ -29,7 +29,7 @@ void free_weightsystem(weightsystem_t ws)
ws.description = NULL;
}
-static void free_cylinder(cylinder_t c)
+void free_cylinder(cylinder_t c)
{
free((void *)c.type.description);
c.type.description = NULL;
@@ -137,12 +137,18 @@ void add_cloned_weightsystem_at(struct weightsystem_table *t, weightsystem_t ws)
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
}
+cylinder_t clone_cylinder(cylinder_t cyl)
+{
+ cylinder_t res = cyl;
+ res.type.description = copy_string(res.type.description);
+ return res;
+}
+
/* Add a clone of a cylinder to the end of a cylinder table.
* Cloned in means that the description-string is copied. */
void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl)
{
- cyl.type.description = copy_string(cyl.type.description);
- add_to_cylinder_table(t, t->nr, cyl);
+ add_to_cylinder_table(t, t->nr, clone_cylinder(cyl));
}
bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
@@ -151,15 +157,6 @@ bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
same_string(w1.description, w2.description);
}
-bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2)
-{
- return same_string(cyl1.type.description, cyl2.type.description) &&
- same_gasmix(cyl1.gasmix, cyl2.gasmix) &&
- cyl1.start.mbar == cyl2.start.mbar &&
- cyl1.end.mbar == cyl2.end.mbar &&
- cyl1.cylinder_use == cyl2.cylinder_use;
-}
-
void get_gas_string(struct gasmix gasmix, char *text, int len)
{
if (gasmix_is_air(gasmix))
@@ -377,6 +374,46 @@ cylinder_t *get_or_create_cylinder(struct dive *d, int idx)
return &d->cylinders.cylinders[idx];
}
+/* if a default cylinder is set, use that */
+void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
+{
+ const char *cyl_name = prefs.default_cylinder;
+ struct tank_info_t *ti = tank_info;
+ pressure_t pO2 = {.mbar = lrint(prefs.modpO2 * 1000.0)};
+
+ if (!cyl_name)
+ return;
+ while (ti->name != NULL && ti < tank_info + MAX_TANK_INFO) {
+ if (strcmp(ti->name, cyl_name) == 0)
+ break;
+ ti++;
+ }
+ if (ti->name == NULL)
+ /* didn't find it */
+ return;
+ cyl->type.description = strdup(ti->name);
+ if (ti->ml) {
+ cyl->type.size.mliter = ti->ml;
+ cyl->type.workingpressure.mbar = ti->bar * 1000;
+ } else {
+ cyl->type.workingpressure.mbar = psi_to_mbar(ti->psi);
+ if (ti->psi)
+ cyl->type.size.mliter = lrint(cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi)));
+ }
+ // MOD of air
+ cyl->depth = gas_mod(cyl->gasmix, pO2, dive, 1);
+}
+
+cylinder_t create_new_cylinder(const struct dive *d)
+{
+ cylinder_t cyl = empty_cylinder;
+ fill_default_cylinder(d, &cyl);
+ cyl.start = cyl.type.workingpressure;
+ cyl.manually_added = true;
+ cyl.cylinder_use = OC_GAS;
+ return cyl;
+}
+
#ifdef DEBUG_CYL
void dump_cylinders(struct dive *dive, bool verbose)
{
diff --git a/core/equipment.h b/core/equipment.h
index b62587447..081a13835 100644
--- a/core/equipment.h
+++ b/core/equipment.h
@@ -75,6 +75,8 @@ extern weightsystem_t clone_weightsystem(weightsystem_t ws);
extern void free_weightsystem(weightsystem_t ws);
extern void copy_cylinder_types(const struct dive *s, struct dive *d);
extern void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws);
+extern cylinder_t clone_cylinder(cylinder_t cyl);
+extern void free_cylinder(cylinder_t cyl);
extern cylinder_t *add_empty_cylinder(struct cylinder_table *t);
extern void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl);
extern cylinder_t *get_cylinder(const struct dive *d, int idx);
@@ -82,13 +84,14 @@ extern cylinder_t *get_or_create_cylinder(struct dive *d, int idx);
extern void add_cylinder_description(const cylinder_type_t *);
extern void add_weightsystem_description(const weightsystem_t *);
extern bool same_weightsystem(weightsystem_t w1, weightsystem_t w2);
-extern bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2);
extern void remove_cylinder(struct dive *dive, int idx);
extern void remove_weightsystem(struct dive *dive, int idx);
extern void set_weightsystem(struct dive *dive, int idx, weightsystem_t ws);
extern void reset_cylinders(struct dive *dive, bool track_gas);
extern int gas_volume(const cylinder_t *cyl, pressure_t p); /* Volume in mliter of a cylinder at pressure 'p' */
extern int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table *cylinders);
+extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl); /* dive is needed to fill out MOD, which depends on salinity. */
+extern cylinder_t create_new_cylinder(const struct dive *dive); /* dive is needed to fill out MOD, which depends on salinity. */
#ifdef DEBUG_CYL
extern void dump_cylinders(struct dive *dive, bool verbose);
#endif
diff --git a/core/parse-xml.c b/core/parse-xml.c
index 490e56275..50639d1d1 100644
--- a/core/parse-xml.c
+++ b/core/parse-xml.c
@@ -698,31 +698,6 @@ static void try_to_match_autogroup(const char *name, char *buf)
nonmatch("autogroup", name, buf);
}
-void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
-{
- /* sanity check so we don't crash */
- if (idx < 0 || idx >= dive->cylinders.nr) {
- report_error("Unknown cylinder index: %d", idx);
- return;
- }
- /* The gas switch event format is insane for historical reasons */
- struct gasmix mix = get_cylinder(dive, idx)->gasmix;
- int o2 = get_o2(mix);
- int he = get_he(mix);
- struct event *ev;
- int value;
-
- o2 = (o2 + 5) / 10;
- he = (he + 5) / 10;
- value = o2 + (he << 16);
-
- ev = add_event(dc, seconds, he ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE, 0, value, "gaschange");
- if (ev) {
- ev->gas.index = idx;
- ev->gas.mix = mix;
- }
-}
-
static void get_cylinderindex(char *buffer, uint8_t *i, struct parser_state *state)
{
*i = atoi(buffer);
diff --git a/core/planner.c b/core/planner.c
index 0e26a9a57..a5f0d36bc 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -175,37 +175,6 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, struct deco_s
return surface_interval;
}
-
-/* if a default cylinder is set, use that */
-void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
-{
- const char *cyl_name = prefs.default_cylinder;
- struct tank_info_t *ti = tank_info;
- pressure_t pO2 = {.mbar = 1600};
-
- if (!cyl_name)
- return;
- while (ti->name != NULL && ti < tank_info + MAX_TANK_INFO) {
- if (strcmp(ti->name, cyl_name) == 0)
- break;
- ti++;
- }
- if (ti->name == NULL)
- /* didn't find it */
- return;
- cyl->type.description = strdup(ti->name);
- if (ti->ml) {
- cyl->type.size.mliter = ti->ml;
- cyl->type.workingpressure.mbar = ti->bar * 1000;
- } else {
- cyl->type.workingpressure.mbar = psi_to_mbar(ti->psi);
- if (ti->psi)
- cyl->type.size.mliter = lrint(cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi)));
- }
- // MOD of air
- cyl->depth = gas_mod(cyl->gasmix, pO2, dive, 1);
-}
-
/* calculate the new end pressure of the cylinder, based on its current end pressure and the
* latest segment. */
static void update_cylinder_pressure(struct dive *d, int old_depth, int new_depth, int duration, int sac, cylinder_t *cyl, bool in_deco, enum divemode_t divemode)
@@ -315,7 +284,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
}
if (dp->divemode != type) {
type = dp->divemode;
- add_event(dc, lasttime, 8, 0, type, "modechange");
+ add_event(dc, lasttime, SAMPLE_EVENT_BOOKMARK, 0, type, "modechange");
}
/* Create sample */
diff --git a/core/profile.c b/core/profile.c
index 88b48d1cd..26488cc30 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -120,19 +120,6 @@ struct ev_select *ev_namelist;
int evn_allocated;
int evn_used;
-#if WE_DONT_USE_THIS /* we need to implement event filters in Qt */
-int evn_foreach (void (*callback)(const char *, bool *, void *), void *data)
-{
- int i;
-
- for (i = 0; i < evn_used; i++) {
- /* here we display an event name on screen - so translate */
- callback(translate("gettextFromC", ev_namelist[i].ev_name), &ev_namelist[i].plot_ev, data);
- }
- return i;
-}
-#endif /* WE_DONT_USE_THIS */
-
void clear_events(void)
{
for (int i = 0; i < evn_used; i++)
diff --git a/core/qthelper.cpp b/core/qthelper.cpp
index eb755bf20..91b3a3ee7 100644
--- a/core/qthelper.cpp
+++ b/core/qthelper.cpp
@@ -1662,3 +1662,36 @@ extern "C" char *get_changes_made()
else
return nullptr;
}
+
+// Generate a cylinder-renumber map for use when the n-th cylinder
+// of a dive with count cylinders is removed. It fills an int vector
+// with 0..n, -1, n..count-1. Each entry in the vector represents
+// the new id of the cylinder, whereby <0 means that this particular
+// cylinder does not get any new id. This should probably be moved
+// to the C-core, but using std::vector is simply more convenient.
+// The function assumes that n < count!
+std::vector<int> get_cylinder_map_for_remove(int count, int n)
+{
+ // 1) Fill mapping[0]..mapping[n-1] with 0..n-1
+ // 2) Set mapping[n] to -1
+ // 3) Fill mapping[n+1]..mapping[count-1] with n..count-2
+ std::vector<int> mapping(count);
+ std::iota(mapping.begin(), mapping.begin() + n, 0);
+ mapping[n] = -1;
+ std::iota(mapping.begin() + n + 1, mapping.end(), n);
+ return mapping;
+}
+
+// Generate a cylinder-renumber map for use when a cylinder is added
+// before the n-th cylinder. It fills an int vector with
+// with 0..n-1, n+1..count. Each entry in the vector represents
+// the new id of the cylinder. This probably should be moved
+// to the C-core, but using std::vector is simply more convenient.
+// This function assumes that that n <= count!
+std::vector<int> get_cylinder_map_for_add(int count, int n)
+{
+ std::vector<int> mapping(count);
+ std::iota(mapping.begin(), mapping.begin() + n, 0);
+ std::iota(mapping.begin() + n, mapping.end(), n + 1);
+ return mapping;
+}
diff --git a/core/qthelper.h b/core/qthelper.h
index bb8876383..848763138 100644
--- a/core/qthelper.h
+++ b/core/qthelper.h
@@ -83,6 +83,8 @@ QLocale getLocale();
QVector<QPair<QString, int>> selectedDivesGasUsed();
QString getUserAgent();
QString printGPSCoords(const location_t *loc);
+std::vector<int> get_cylinder_map_for_remove(int count, int n);
+std::vector<int> get_cylinder_map_for_add(int count, int n);
extern QString (*changesCallback)();
void uiNotification(const QString &msg);
diff --git a/core/subsurface-qt/divelistnotifier.h b/core/subsurface-qt/divelistnotifier.h
index aafe29c0c..63355fbcc 100644
--- a/core/subsurface-qt/divelistnotifier.h
+++ b/core/subsurface-qt/divelistnotifier.h
@@ -87,6 +87,9 @@ signals:
void divesTimeChanged(timestamp_t delta, const QVector<dive *> &dives);
void cylindersReset(const QVector<dive *> &dives);
+ void cylinderAdded(dive *d, int pos);
+ void cylinderRemoved(dive *d, int pos);
+ void cylinderEdited(dive *d, int pos);
void weightsystemsReset(const QVector<dive *> &dives);
void weightAdded(dive *d, int pos);
void weightRemoved(dive *d, int pos);
@@ -110,6 +113,9 @@ signals:
void numShownChanged();
void filterReset();
+ // Event-related signals. Currently, we're very blunt: only one signal for any changes to the events.
+ void eventsChanged(dive *d);
+
// This signal is emited every time a command is executed.
// This is used to hide an old multi-dives-edited warning message.
// This is necessary, so that the user can't click on the "undo" button and undo