Properly implement the unsaved-changes flag(s). Since we currently have
two kinds of changes, there are two flags:
1) dive_list_changed in divelist.c marks non-undoable changes. This flag
is only cleared on save or load.
2) QUndoStack::isClean() is used to determine the state of undoable
changes. Every time the user returns to the state where they saved,
this flag is cleared.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
dive- and trip-table functions are generated in dive.c by macros.
Move this macros to a new "core/table.h" header file.
Thus, these functions can be used for other tables (e.g. dive site)
and the trip function can be moved to a separate translation unit
(divelist.c being quite large already).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The other dive- and trip-table functions were already autogenerated.
Let's do the same for these two.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For consistency with remove_dive(). Moreover, swap parameter order
in remove_dive() so that both functions use the same parameter order.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of setting dive->dive_site directly, call the
add_dive_to_dive_site() and unregister_dive_from_dive_site()
functions. In the parser this turned out to be a bit tricky.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Add a dive site table to each dive site to keep track of dives
that have been added to a dive site. Add two functions to add
dives to / remove dives from dive sites.
Since dive sites now contain a dive table, the order of includes
had to be changed: "divesite.h" now includes "dive.h" and not
vice-versa. This caused some include churn.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As opposed to dive trips, dive sites were always directly added
to the global table, even on import. Instead, parse the divesites
into a distinct table and merge them on import.
Currently, this does not do any merging of dive sites, i.e. dive
sites are considered as either equal or different. Nevertheless,
merging of data should be rather easy to implement and simply
follow the code of the dive merging.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To extend the undo system to dive sites, the importers and downloaders
must not parse directly into the global dive site table. Instead,
pass a dive_site_table argument to parse into.
For now, always pass the global dive_site_table so that this commit
should not cause any functional change.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To enable undo of dive site functions, it is crucial to work
with different dive site tables. Therefore add a dive site table
parameter to dive site functions. For now, always pass the global
dive site table. Thus, this commit shouldn't alter any functionality.
After this change, a simple search for dive_site_table reveals all
places where the global dive site table is accessed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Owing to a variable reuse in a nested loop, importing dive logs
with new trips could lead to an infinite loop. Use a fresh index "j".
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This function was defined in divelist.c, whereas it's better located
in divesite.c. Move it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
process_imported_dives() takes four boolean parameters. Replace these
by flags. This makes the function calls much more descriptive. Morover,
it becomes easier to add or remove flags.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since process_imported_dives() can add dives to a newly generated
trip, this need not be done in the downloading code. This makes
data flow distinctly simpler, as no trip table and no add-new-trip
flag has to be passed down to the libdivecomputer glue code.
Moreover, since now the trip creation is done at the import step
rather than the download step, the latest status of the "add to
new trip" checkbox will be considered.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
If this flag is set, dives that are not assigned to a trip will
be assigned to a new trip. This flag is set if the user checked
"add to new trip" in the download dialog of the desktop version.
Currently this is a no-op as the dives will already have been
added to a new trip by the downloading code. This will be removed
in a subsequent commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The logic in process_imported_dives() was faulty: Dives are merged
trip-wise in a loop. But if only autogenerated trips were supposed
to be merged, the trip would not be added.
Change the logic to always add the trip if it is not merged. To make
the loop easier to read, factor out the merge-trip-into-existing-trips
logic into a separate function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Split the process_imported_dives() function in two:
1) process_imported_dives() processes the dives and generates
a list of dives and trips to be added and removed.
2) add_imported_dives() calls process_imported_dives() and
does the actual removal / addition of dives and trips.
The goal is to split preparation and actual work, to
make dive import undo-able.
The code adds extra checks to never merge into the same
dive twice, as this would lead to a double-free() bug.
This should in principle never happen, as dives that
compare equal according to is_same_dive() are merged
in the imported-dives list, but perhaps in some pathologival
corner-cases is_same_dive() turns out to be non-transitive.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The installment of the divelist-undo system has made it unnecessary
to adopt the uniq-id of the merged-into dive. On the contrary, we
want to avoid two dives with the same dive-id in the divelist at
all costs, since get_divenr() still uses the id and thus may fetch
the wrong dive.
Therefore, don't copy the dive-id on merge.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When importing log-files we generally want to merge trips. But
when downloading and the user chose "generate new trip", that
new trip should not be merged into existing trips.
Therefore, add a "merge_all_trips" parameter to process_imported_dives().
If false only autogenerated trips [via autogroup] will be merged.
In the future we might want to let the user choose if trips
should be merged when importing log-files.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The old way of merging log-files was not well defined: Trips
were recognized as the same if and only if the first dives
started at the same instant. Later dives did not matter.
Change this to merge dives if they are overlapping.
Moreover, on parsing and download generate trips in a separate
trip-table.
This will be fundamental for undo of dive-import: Firstly, we
don't want to mix trips of imported and not-yet imported dives.
Secondly, by merging trip-wise, we can autogroup the dives
in the import-data to trips and merge these at once. This will
simplify the code to decide to which trip dives should be
autogrouped.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently trips are added to the global trip table. If we want to
make dive-import undoable, we should be able to parse trips of a
log-file into a distinct table. Therefore, add a trip_table
parameter to
- insert_trip()
- create_and_hookup_trip_from_dive()
- autogroup_dives()
- unregister_trip()
- remove_dive_from_trip()
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, all trips are kept in a linked list. Replace the list
by a table in analogy to dive_table. Use this to keep the trip_table
sorted as suggested by dump_trip_list(). When inserting a trip into
the table do that after adding the dives, to avoid warnings coming
out of dump_trip_list().
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In 64e6e435f8 the trip->when field
was replaced by a function. This forgot to adapt dump_trip_list(),
which is only compiled if DEBUG_TRIP is defined. Fix the function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Rename
- dive_get_insertion_index() -> dive_table_get_insertion_index()
- unregister_dive_from_table() -> remove_from_dive_table()
- get_idx_in_table() -> get_idx_in_dive_table()
- sort_table() -> sort_dive_table()
This will make it more straight-forward to generate these functions
from macros.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This function was not used outside of divelist.c, therefore make it
local. Moreover rename it to add_to_divetable so that the name
is generic and can be generated by a macro.
Moreover, remove the special case idx = -1, which would determine
the insertion index. Instead let the single caller who used this
feature do this.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently autogroup_dives() groups all dives in the global dive
list. Add a table parameter so that dives in any table can be
grouped. Thus it will be possible to pre-group dives on import,
which will be used for undo of import.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
After loading or importing, the caller usually called autogroup()
to autogroup dives if so wished by the user. This has already led
to bugs, when autogroup() was forgotten.
Instead, call autogroup() directly in the process_loaded_dives()
and process_imported_dives() functions. Not only does this prevent
forgetting the call - it also means that autogrouping can be
changed without changing every caller.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In commit 6bf4120dbb the trip-flags
were replaced by a simple boolean. This made the was_autogen
parameter to the remove_dive_from_trip() and unregister_dive_from_trip()
functions unused. Remove these parameters.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To make data flow more clear, unglobalize the downloadTable object.
Make it a subobject of DownloadThread. The difficult part was making
this compatible with QML, because somehow the pointer to the
download-table has to be passed to the DiveImportedModel. Desktop would
simply pass it to the constructor. But with objects generated in QML
this is not possible. Instead, pass the table in the repopulate()
function. This seems to make sense, but for this to work, we have to
declare pointer-to-dive-table as a Q_METATYPE. And this only works
if we use a typedef, because MOC removes the "struct" from "struct
dive_table". This leads to compilation errors, because dive_table is
the symbol-name of the global dive table! Sigh.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These two functions were called in different contexts:
- unregister_dive(): from the undo-commands to remove the dive
from the global dive table, but not delete it. The dive was
already removed from its trip.
- delete_single_dive(): from non-undo code. Most of it not in
use and removed in a sibling-commit. Here, the dive is supposed
to be removed from its trip and a new selection is calculated.
delete_single_dive() calls unregister_dive(), which removes the
dive from its trip. Move remove_dive_from_trip() from the former
to the latter and make both functions independent. Instead
of deleting the dive explicitly in delete_single_dive(), call
the delete_dive_from_table() function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
All callers of add_dive_to_trip() work on freshly generated dives,
with one exception, that was redundant anyway. Therefore it is not
necessary to remove the dive from a potential previous trip. Move the
responsibility of removing the dive from a trip to the caller,
respectively remove the redundant call. Add a warning message in the
case that trip is set.
Background: On import (either download or file-import) we might not
want to add trips to the global trip-list. For example to enable undo
of import but more generally to detangle that data flow. Thus,
add_dive_to_trip() should not mingle with the global trip-list,
which it has to do if a trip is deleted because the old dive was
removed.
Analysis of the add_dive_to_trip() callers:
1) core/dive.c
pick_trip():
called on freshly generated merged dive.
finish_split():
called on two freshly generated split dives.
2) core/divelist.c
create_and_hookup_trip_from_dive():
called on freshly downloaded dive in dive_cb().
called on freshly downloaded dive in record_uemis_dive().
autogroup_dives():
called on dive from get_dives_to_autogroup(), which only
finds dives that are outside of trips.
combine_trips():
unused - removed in sibling commit.
try_to_merge_into():
this call was actually erroneous - dive was already added
to trip in try_to_merge(). Remove call.
3) core/libdivecomputer.c
dive_cb():
called on freshly downloaded dive.
4) core/uemis_downloader.c
record_uemis_dive():
called on freshly downloaded dive.
5) core/load_git.c
create_new_dive():
called on freshly allocated dive.
6) core/parse.c
dive_end():
called on freshly parsed dive.
7) desktop-widgets/command_divelist.cpp
DiveListBase::addDive():
called on dive which is newly added to core.
moveDiveToTrip():
called on dive that was removed from trip a few lines above.
8) mobile-widgets/qmlmanager.cpp
QMLManager::undoDelete():
called on dive where divetrip was reset in the previous line.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In 014c04f8bd merging dives was included
in the undo-system. This made the merge_two_dives() function caller-less.
Remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In f427226b3b autogrouping / removal
of autogrouping was moved into the undo-machinery. This made the
remove_autogen_trips() function caller-less. Remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In f427226b3b a combine_trips_create()
function was introduced that combined trips without deleting the old
trips. This was necessary for making combine-trips function undo-able.
The old combine_trips() function is not used anymore. Therefore remove
it. Rename the combine_trips_create() function to combine_trips() as
no differentiation is needed anymore.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These functionality was used by the desktop filter. To unify desktop
and mobile, move it into two new functions in divelist.c
Since one of them is the only caller of is_same_day() move that
likewise into divelist.c and make it of static linkage.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Implement the protocol in Erik Baker's document
"Oxygen Toxicity Calculations". This code uses a
third-order polynomial approximation of Baker's
equation 2. Provision is made for
PSCR and CCR dive logs and dive plans. In the
case of dive logs, the values of o2 sensors are
used if there are data from such sensors. For CCR
only the data from the first O2 sensor is used even if
there are more than one sensor. This is a potential
weakness, but this function is probably NOT the
place to calculate mean o2 values accross all sensors
and to emulate voting logic to reject info from
aberrant sensors.
Signed-off-by: willemferguson <willemferguson@zoology.up.ac.za>
Signed-off-by: Robert C. Helling <helling@atdotde.de>
Commit 6b283e598a replaced the linked
list of dives in a trip by a table. Embarassingly, on dive deletion
the index of the dive in the table was compared for "!= 0" instead
of ">= 0". Thus, the first dive of a trip wouldn't be deleted, which
ultimately led to a crash, as different parts of the code were now
in disagreement over whether the trip is empty or not.
Fix the comparison.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The only remaining use of the tripflag was to mark dives that
were removed explicitly from a trip, i.e. shouldn't be autogrouped.
Therefore replace the enum by a simple boolean.
Currently, there is no way of unsetting the notrip flag. But this
shouldn't result in a user-visible change.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The distinction between ASSIGNED_TRIP and IN_TRIP was used to
prefer non-autogenerated trips on merging of dives. But owing
to bit rot this seem to have worked only partially anyway:
The IN_TRIP field was set in create_and_hookup_trip_from_dive()
and immediately overwritten in add_dive_to_trip() called
in the next line.
Instead, use the trip->autogen flag to check for priority and
remove the ASSIGNED_TRIP flag alltogether.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The when field gives the time of the first dive. Instead of keeping
this field in sync, replace it by a function that determines the time
of the first dive.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To make sorting more controlled, move all sorting functions into
the core. For this, introduce a "dive_or_trip" structure, which
represents a top-level item. Adapt the DiveTripModel accordingly.
There are now three sorting functions:
1) dive_less_than
2) trip_less_than
3) dive_or_trip_less_than
These should be used by all sorting code. By moving them to a
single place, the mess can hopefully be cleaned up.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As a step towards proper sorting, introduce a trip_less_than()
function in core. It simply sorts by the first dive, which should
be unique as dives may belong to only one trip.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The dives of each trip were kept in a list. Replace this by a
struct dive_table. This will make it significantly easier to
keep the dives of a trip in sorted state.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Up to now, dives were added to the global dive table with
add_single_dive(). Split out the funtionality to add a dive to
an arbitrary dive in the add_dive_to_table_function(). The
difference compared to record_dive_to_table is that dives
are added at a specific position or the sort-criterion given
by dive_less_than(). This will allow to use a dive tabe for trips
instead of a linked list.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two versions of the insert_trip() function: one
would merge trips if a trip with the same date already existed,
the other wouldn't. The latter was introduced with the dive-list
undo work.
The problem is that the "date" of a trip (i.e. the first dive)
seems ill-defined as this is a volatile value. Moreover in
the context of making dive-import undoable this is a very
dangerous notion, as the caller needs control over when the dives
are added to a trip.
Therefore, unify these two functions and never merge trips.
The decision on merging dives now has to made by the caller.
This will be implemented in a future commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The DiveTripModel places dives after trips in chronologically
ascending mode if the dive and the trip start at the same instant.
But in the core the sort order was undefined. This could lead
to a discrepancy. Therefore, implement the same sort-criterion
in the core code.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Update table of maximum oxygen exposure durations, used in CNS calulations.
This table shows the official NOAA maximum O2 exposure limits
(in seconds) for different PO2 values. It also gives
slope values for linear interpolation for intermediate PO2 values
between the tabulated PO2 values in the 1st column.
Top & bottom rows are inserted that are not in the NOAA table:
(1) For PO2 > 1.6 the same slope value as between
1.5 & 1.6 is used. This exptrapolation for PO2 > 1.6 likely
gives an underestimate above 1.6 but is better than the
value for PO2=1.6 (45 min). (2) The NOAA table only
tabulates values for PO2 >= 0.6. Since O2-uptake occurs down to
PO2=0.5, the same slope is used as for 0.7 > PO2 > 0.6.
This gives a conservative estimate for 0.6 > PO2 > 0.5. To
preserve the integer structure of the table, all slopes are
given as slope*10: divide by 10 to get the valid slope.
The columns below are:
po2 (mbar), Maximum Single Exposure (seconds), single_slope,
Maximum 24 hour Exposure (seconds), 24h_slope */
Then update Calculations of the CNS for a single dive -
this only takes the first divecomputer into account.
The previous version of the code did a table lookup and
used the max O2 exposure for the next-higher PO2 category.
This gave a shorter max O2 exposure time and a higher CNS
contribution for a specific dive segment, resulting in a
slightly conservative value of CNS, often some 2 - 3 % too high.
This code does an interpolation for PO2 values inbetween
PO2 entries in the lookup table and therefore results in a more
accurate maximum O2 exposure time for that PO2.
The maximum O2 exposure duration for each segment
is also calculated based on the mean depth of the two
samples (start & end) that define each segment. The CNS
contribution of each segment is found by dividing the
time duration of the segment by its maximum exposure duration.
The contributions of all segments of the dive are summed to
get the total CNS% value. This is a partial implementation
of the proposals in Erik Baker's document "Oxygen Toxicity Calculations" */
Overall, this PR does not radically alter the existing CNS calculation,
it only makes it more accurate and more consistent by doing
interpolation and by using mean segment depth to find PO2.
Signed-off-by: willemferguson <willemferguson@zoology.up.ac.za>
With the fixed sematics of get_gasmix to return the new gasmix for
the time of a gas switch (added comments to make this clear), in the
OTU calculation we need the previous gasmix for the interval up to the
current time.
Signed-off-by: Robert C. Helling <helling@atdotde.de>