mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Import: split process_imported_dives() function
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>
This commit is contained in:
parent
fd196f143a
commit
0249e12589
11 changed files with 215 additions and 200 deletions
381
core/divelist.c
381
core/divelist.c
|
@ -1368,66 +1368,6 @@ int unsaved_changes()
|
||||||
return dive_list_changed;
|
return dive_list_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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(int preexisting)
|
|
||||||
{
|
|
||||||
int i, nr;
|
|
||||||
struct dive *last = get_dive(preexisting - 1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there was a last dive, but it didn't have
|
|
||||||
* a number, give up.
|
|
||||||
*/
|
|
||||||
if (last && !last->number)
|
|
||||||
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_loaded_dives()
|
void process_loaded_dives()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1477,46 +1417,53 @@ static void merge_imported_dives(struct dive_table *table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void insert_dive(struct dive_table *table, struct dive *d)
|
||||||
|
{
|
||||||
|
int idx = dive_table_get_insertion_index(table, d);
|
||||||
|
add_to_dive_table(table, idx, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear a dive_table and a trip_table. Think about generating these with macros.
|
||||||
|
*/
|
||||||
|
void clear_table(struct dive_table *table)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < table->nr; i++)
|
||||||
|
free_dive(table->dives[i]);
|
||||||
|
table->nr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_trip_table(struct trip_table *table)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < table->nr; i++)
|
||||||
|
free_trip(table->trips[i]);
|
||||||
|
table->nr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to merge a new dive into the dive at position idx. Return
|
* Try to merge a new dive into the dive at position idx. Return
|
||||||
* true on success. On success, the old dive will be deleted. On failure,
|
* true on success. On success, the old dive will be added to the
|
||||||
* it is unchanged.
|
* dives_to_remove table and the merged dive to the dives_to_add
|
||||||
* If replace_in is not NULL, the original dive will also be replaced
|
* table. On failure everything stays unchanged.
|
||||||
* by the merged dive in this dive table. If it is NULL it will be
|
|
||||||
* replaced in the dive table of its trip. This is used for merging dive
|
|
||||||
* in the trip table *and* the dive table.
|
|
||||||
* If "prefer_imported" is true, use data of the new dive.
|
* If "prefer_imported" is true, use data of the new dive.
|
||||||
*/
|
*/
|
||||||
static bool try_to_merge_into(struct dive *dive_to_add, int idx, struct dive_table *table,
|
static bool try_to_merge_into(struct dive *dive_to_add, int idx, struct dive_table *table, bool prefer_imported,
|
||||||
struct dive_table *replace_in, bool prefer_imported)
|
/* output parameters: */
|
||||||
|
struct dive_table *dives_to_add, struct dive_table *dives_to_remove)
|
||||||
{
|
{
|
||||||
struct dive *old_dive = table->dives[idx];
|
struct dive *old_dive = table->dives[idx];
|
||||||
struct dive *merged = try_to_merge(old_dive, dive_to_add, prefer_imported);
|
struct dive *merged = try_to_merge(old_dive, dive_to_add, prefer_imported);
|
||||||
if (!merged)
|
if (!merged)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Hack alert! If no replace_in table was passed, we are merging
|
|
||||||
* a non-trip dive into a potentially in-trip dive. In this case
|
|
||||||
* we also have to replace the merged dive for the old dive in the
|
|
||||||
* trip list. This will be removed in a subsequent commit, when
|
|
||||||
* the merging is done outside of processing */
|
|
||||||
if (!replace_in && old_dive->divetrip)
|
|
||||||
replace_in = &old_dive->divetrip->dives;
|
|
||||||
|
|
||||||
merged->selected = old_dive->selected;
|
|
||||||
merged->divetrip = old_dive->divetrip;
|
merged->divetrip = old_dive->divetrip;
|
||||||
old_dive->divetrip = NULL;
|
insert_dive(dives_to_remove, old_dive);
|
||||||
table->dives[idx] = merged;
|
insert_dive(dives_to_add, merged);
|
||||||
if (replace_in) {
|
|
||||||
int idx2 = get_idx_in_dive_table(replace_in, old_dive);
|
|
||||||
if (idx2 >= 0)
|
|
||||||
replace_in->dives[idx2] = merged;
|
|
||||||
}
|
|
||||||
free_dive(old_dive);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if two trips overlap time-wise. */
|
||||||
static bool trips_overlap(const struct dive_trip *t1, const struct dive_trip *t2)
|
static bool trips_overlap(const struct dive_trip *t1, const struct dive_trip *t2)
|
||||||
{
|
{
|
||||||
/* First, handle the empty-trip cases. */
|
/* First, handle the empty-trip cases. */
|
||||||
|
@ -1529,22 +1476,33 @@ static bool trips_overlap(const struct dive_trip *t1, const struct dive_trip *t2
|
||||||
return trip_enddate(t2) >= trip_date(t1);
|
return trip_enddate(t2) >= trip_date(t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool insert_dive(struct dive_table *table, struct dive *d)
|
/* Check if a dive is ranked after the last dive of the global dive list */
|
||||||
|
static bool dive_is_after_last(struct dive *d)
|
||||||
{
|
{
|
||||||
int idx = dive_table_get_insertion_index(table, d);
|
if (dive_table.nr == 0)
|
||||||
add_to_dive_table(table, idx, d);
|
return true;
|
||||||
return idx == table->nr - 1;
|
return dive_less_than(dive_table.dives[dive_table.nr - 1], d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Merge dives from dives_from into dives_to. Overlapping dives will be merged,
|
/* Merge dives from "dives_from" into "dives_to". Overlapping dives will be merged,
|
||||||
* non-overlapping dives will be moved. Optionally, if delete_from and add_to
|
* non-overlapping dives will be moved. The results will be added to the "dives_to_add"
|
||||||
* are non-null, dives will be removed / added to these tables. This supposes that
|
* table. Dives that were merged are added to the "dives_to_remove" table.
|
||||||
* all tables are sorted. */
|
* Any newly added (not merged) dive will be assigned to the trip from the "trip"
|
||||||
|
* paremeter. If "delete_from" is non-null dives will be removed from this table.
|
||||||
|
* This function supposes that all input tables are sorted.
|
||||||
|
* Returns true if any dive was added (not merged) that is not past the
|
||||||
|
* last dive of the global dive list (i.e. the sequence will change).
|
||||||
|
* The integer pointed to by "num_merged" will be increased for every
|
||||||
|
* merged dive that is added to "dives_to_add" */
|
||||||
static bool merge_dive_tables(struct dive_table *dives_from, struct dive_table *delete_from,
|
static bool merge_dive_tables(struct dive_table *dives_from, struct dive_table *delete_from,
|
||||||
struct dive_table *dives_to, struct dive_table *add_to,
|
struct dive_table *dives_to,
|
||||||
bool prefer_imported, struct dive_trip *trip)
|
bool prefer_imported, struct dive_trip *trip,
|
||||||
|
/* output parameters: */
|
||||||
|
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
|
||||||
|
int *num_merged)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int last_merged_into = -1;
|
||||||
bool sequence_changed = false;
|
bool sequence_changed = false;
|
||||||
|
|
||||||
/* Merge newly imported dives into the dive table.
|
/* Merge newly imported dives into the dive table.
|
||||||
|
@ -1567,47 +1525,40 @@ static bool merge_dive_tables(struct dive_table *dives_from, struct dive_table *
|
||||||
while (j < dives_to->nr && dive_less_than(dives_to->dives[j], dive_to_add))
|
while (j < dives_to->nr && dive_less_than(dives_to->dives[j], dive_to_add))
|
||||||
j++;
|
j++;
|
||||||
|
|
||||||
/* Try to merge into previous dive. */
|
/* Try to merge into previous dive.
|
||||||
if (j > 0 && dive_endtime(dives_to->dives[j - 1]) > dive_to_add->when) {
|
* We are extra-careful to not merge into the same dive twice, as that
|
||||||
if (try_to_merge_into(dive_to_add, j - 1, dives_to, add_to, prefer_imported)) {
|
* would put the merged-into dive twice onto the dives-to-delete list.
|
||||||
|
* In principle that shouldn't happen as all dives that compare equal
|
||||||
|
* by is_same_dive() were already merged, and is_same_dive() should be
|
||||||
|
* transitive. But let's just go *completely* sure for the odd corner-case. */
|
||||||
|
if (j > 0 && j - 1 > last_merged_into &&
|
||||||
|
dive_endtime(dives_to->dives[j - 1]) > dive_to_add->when) {
|
||||||
|
if (try_to_merge_into(dive_to_add, j - 1, dives_to, prefer_imported,
|
||||||
|
dives_to_add, dives_to_remove)) {
|
||||||
free_dive(dive_to_add);
|
free_dive(dive_to_add);
|
||||||
|
last_merged_into = j - 1;
|
||||||
|
(*num_merged)++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* That didn't merge into the previous dive. If we're
|
/* That didn't merge into the previous dive.
|
||||||
* at the end of the dive table, quit the loop and add
|
* Try to merge into next dive. */
|
||||||
* all new dives at the end. */
|
if (j < dives_to->nr && j > last_merged_into &&
|
||||||
if (j >= dives_to->nr)
|
dive_endtime(dive_to_add) > dives_to->dives[j]->when) {
|
||||||
break;
|
if (try_to_merge_into(dive_to_add, j, dives_to, prefer_imported,
|
||||||
|
dives_to_add, dives_to_remove)) {
|
||||||
/* Try to merge into next dive. */
|
|
||||||
if (dive_endtime(dive_to_add) > dives_to->dives[j]->when) {
|
|
||||||
if (try_to_merge_into(dive_to_add, j, dives_to, add_to, prefer_imported)) {
|
|
||||||
free_dive(dive_to_add);
|
free_dive(dive_to_add);
|
||||||
|
last_merged_into = j;
|
||||||
|
(*num_merged)++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We couldnt merge dives, add at the given position. */
|
/* We couldnt merge dives, simply add to list of dives to-be-added. */
|
||||||
add_to_dive_table(dives_to, j, dive_to_add);
|
insert_dive(dives_to_add, dive_to_add);
|
||||||
|
sequence_changed |= !dive_is_after_last(dive_to_add);
|
||||||
dive_to_add->divetrip = trip;
|
dive_to_add->divetrip = trip;
|
||||||
if (add_to)
|
|
||||||
insert_dive(add_to, dive_to_add);
|
|
||||||
j++;
|
|
||||||
sequence_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are still dives to add, add them at the end of the dive table. */
|
|
||||||
for ( ; i < dives_from->nr; i++) {
|
|
||||||
struct dive *dive_to_add = dives_from->dives[i];
|
|
||||||
if (delete_from)
|
|
||||||
remove_dive(delete_from, dive_to_add);
|
|
||||||
|
|
||||||
dive_to_add->divetrip = trip;
|
|
||||||
add_to_dive_table(dives_to, dives_to->nr, dive_to_add);
|
|
||||||
if (add_to)
|
|
||||||
sequence_changed |= !insert_dive(add_to, dive_to_add);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we took care of all dives, clean up the import table */
|
/* we took care of all dives, clean up the import table */
|
||||||
|
@ -1619,56 +1570,105 @@ static bool merge_dive_tables(struct dive_table *dives_from, struct dive_table *
|
||||||
/* Merge the dives of the trip "from" and the dive_table "dives_from" into the trip "to"
|
/* Merge the dives of the trip "from" and the dive_table "dives_from" into the trip "to"
|
||||||
* and dive_table "dives_to". If "prefer_imported" is true, dive data of "from" takes
|
* and dive_table "dives_to". If "prefer_imported" is true, dive data of "from" takes
|
||||||
* precedence */
|
* precedence */
|
||||||
static bool merge_trips(struct dive_trip *from, struct dive_table *dives_from,
|
void add_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table,
|
||||||
struct dive_trip *to, struct dive_table *dives_to, bool prefer_imported)
|
bool prefer_imported, bool downloaded, bool merge_all_trips)
|
||||||
{
|
{
|
||||||
return merge_dive_tables(&from->dives, dives_from, &to->dives, dives_to, prefer_imported, to);
|
int i, idx;
|
||||||
}
|
struct dive_table dives_to_add = { 0 };
|
||||||
|
struct dive_table dives_to_remove = { 0 };
|
||||||
|
struct trip_table trips_to_add = { 0 };
|
||||||
|
|
||||||
static bool add_trip_to_table(struct dive_trip *trip, struct dive_table *dives_from,
|
/* Process imported dives and generate lists of dives
|
||||||
struct trip_table *table, struct dive_table *dives_to)
|
* to-be-added and to-be-removed */
|
||||||
{
|
process_imported_dives(import_table, import_trip_table,
|
||||||
int i;
|
prefer_imported, downloaded, merge_all_trips,
|
||||||
struct dive *d;
|
&dives_to_add, &dives_to_remove, &trips_to_add);
|
||||||
bool sequence_changed = false;
|
|
||||||
for (i = 0; i < trip->dives.nr; i++) {
|
|
||||||
d = trip->dives.dives[i];
|
|
||||||
|
|
||||||
/* Add dive to copy-to table */
|
/* Add new dives to trip, so that trips don't get deleted
|
||||||
sequence_changed |= !insert_dive(dives_to, d);
|
* on deletion of old dives */
|
||||||
|
for (i = 0; i < dives_to_add.nr; i++) {
|
||||||
/* Remove dive from copy-from table */
|
struct dive *d = dives_to_add.dives[i];
|
||||||
remove_dive(dives_from, d);
|
struct dive_trip *trip = d->divetrip;
|
||||||
|
if (!trip)
|
||||||
|
continue;
|
||||||
|
d->divetrip = NULL;
|
||||||
|
add_dive_to_trip(d, trip);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add trip to list */
|
/* Remove old dives */
|
||||||
insert_trip(trip, table);
|
for (i = 0; i < dives_to_remove.nr; i++) {
|
||||||
|
idx = get_divenr(dives_to_remove.dives[i]);
|
||||||
|
delete_single_dive(idx);
|
||||||
|
}
|
||||||
|
dives_to_remove.nr = 0;
|
||||||
|
|
||||||
return sequence_changed;
|
/* Add new dives */
|
||||||
|
for (i = 0; i < dives_to_add.nr; i++) {
|
||||||
|
idx = dive_table_get_insertion_index(&dive_table, dives_to_add.dives[i]);
|
||||||
|
add_single_dive(idx, dives_to_add.dives[i]);
|
||||||
|
}
|
||||||
|
dives_to_add.nr = 0;
|
||||||
|
|
||||||
|
/* Add new trips */
|
||||||
|
for (i = 0; i < trips_to_add.nr; i++)
|
||||||
|
insert_trip(trips_to_add.trips[i], &trip_table);
|
||||||
|
trips_to_add.nr = 0;
|
||||||
|
|
||||||
|
/* We might have deleted the old selected dive.
|
||||||
|
* Choose the newest dive as selected (if any) */
|
||||||
|
current_dive = dive_table.nr > 0 ? dive_table.dives[dive_table.nr - 1] : NULL;
|
||||||
|
mark_divelist_changed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Process imported dives: take a table of dives to be imported and
|
||||||
* Add imported dive to global dive table. Overlapping dives will
|
* generate three lists:
|
||||||
* be merged if possible. If prefer_imported is true, data of the
|
* 1) Dives to be added
|
||||||
* new dives are prioritized in such a case.
|
* 2) Dives to be removed
|
||||||
* If downloaded is true, only the divecomputer of the first dive
|
* 3) Trips to be added
|
||||||
|
* The dives to be added are owning (i.e. the caller is responsible
|
||||||
|
* for freeing them).
|
||||||
|
* The dives and trips in import_table and import_trip table are
|
||||||
|
* consumed. On return, both tables have size 0.
|
||||||
|
* The output parameters should be empty - if not, their content
|
||||||
|
* will be cleared!
|
||||||
|
*
|
||||||
|
* Note: The new dives will have their divetrip-field set, but will
|
||||||
|
* *not* be part of the trip. The caller has to add them to the trip.
|
||||||
|
*
|
||||||
|
* The lists are generated by merging dives if possible. This is
|
||||||
|
* performed trip-wise. If prefer_imported is true, data of the
|
||||||
|
* new dives are prioritized in such a case. If merge_all_trips is
|
||||||
|
* true, all overlapping trips will be merged, not only non-autogenerated
|
||||||
|
* trips. If downloaded is true, only the divecomputer of the first dive
|
||||||
* will be considered, as it is assumed that all dives come from
|
* will be considered, as it is assumed that all dives come from
|
||||||
* the same computer.
|
* the same computer.
|
||||||
* If merge_all_trips is true, all trips are merged. This is used
|
|
||||||
* when merging log files. If it is false, only autogenerated trips
|
|
||||||
* are merged. This is used for download-from-dc. There, if the user
|
|
||||||
* explicitly asked for a new trip, we don't want to merge into old
|
|
||||||
* trips.
|
|
||||||
* Note: the dives in import_table and the trips in import_trip_table
|
|
||||||
* are consumed. On return both tables have size 0.
|
|
||||||
*/
|
*/
|
||||||
void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table,
|
void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table,
|
||||||
bool prefer_imported, bool downloaded, bool merge_all_trips)
|
bool prefer_imported, bool downloaded, bool merge_all_trips,
|
||||||
|
/* output parameters: */
|
||||||
|
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
|
||||||
|
struct trip_table *trips_to_add)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j, nr, start_renumbering_at = 0;
|
||||||
struct dive_trip *trip_import, *trip_old;
|
struct dive_trip *trip_import, *trip_old;
|
||||||
int preexisting;
|
int preexisting;
|
||||||
bool sequence_changed = false;
|
bool sequence_changed = false;
|
||||||
|
bool new_dive_has_number = false;
|
||||||
|
|
||||||
|
/* Make sure that output parameters don't contain garbage */
|
||||||
|
clear_table(dives_to_add);
|
||||||
|
clear_table(dives_to_remove);
|
||||||
|
clear_trip_table(trips_to_add);
|
||||||
|
|
||||||
|
/* Check if any of the new dives has a number. This will be
|
||||||
|
* important later to decide if we want to renumber the added
|
||||||
|
* dives */
|
||||||
|
for (int i = 0; i < import_table->nr; i++) {
|
||||||
|
if (import_table->dives[i]->number > 0) {
|
||||||
|
new_dive_has_number = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If no dives were imported, don't bother doing anything */
|
/* If no dives were imported, don't bother doing anything */
|
||||||
if (!import_table->nr)
|
if (!import_table->nr)
|
||||||
|
@ -1704,31 +1704,52 @@ void process_imported_dives(struct dive_table *import_table, struct trip_table *
|
||||||
for (j = 0; j < trip_table.nr; j++) {
|
for (j = 0; j < trip_table.nr; j++) {
|
||||||
trip_old = trip_table.trips[j];
|
trip_old = trip_table.trips[j];
|
||||||
if (trips_overlap(trip_import, trip_old)) {
|
if (trips_overlap(trip_import, trip_old)) {
|
||||||
sequence_changed |= merge_trips(trip_import, import_table, trip_old, &dive_table, prefer_imported);
|
sequence_changed |= merge_dive_tables(&trip_import->dives, import_table, &trip_old->dives,
|
||||||
|
prefer_imported, trip_old,
|
||||||
|
dives_to_add, dives_to_remove,
|
||||||
|
&start_renumbering_at);
|
||||||
free_trip(trip_import); /* All dives in trip have been consumed -> free */
|
free_trip(trip_import); /* All dives in trip have been consumed -> free */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If no trip to merge-into was found, add trip as-is. */
|
/* If no trip to merge-into was found, add trip as-is. */
|
||||||
if (j == trip_table.nr)
|
if (j == trip_table.nr) {
|
||||||
sequence_changed |= add_trip_to_table(trip_import, import_table, &trip_table, &dive_table);
|
/* Add dives to list of dives to add */
|
||||||
|
for (i = 0; i < trip_import->dives.nr; i++) {
|
||||||
|
struct dive *d = trip_import->dives.dives[i];
|
||||||
|
|
||||||
|
/* Add dive to list of dives to-be-added. */
|
||||||
|
insert_dive(dives_to_add, d);
|
||||||
|
sequence_changed |= !dive_is_after_last(d);
|
||||||
|
|
||||||
|
remove_dive(import_table, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add trip to list of trips to add */
|
||||||
|
insert_trip(trip_import, trips_to_add);
|
||||||
|
trip_import->dives.nr = 0; /* Caller is responsible for adding dives to trip */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
import_trip_table->nr = 0; /* All trips were consumed */
|
import_trip_table->nr = 0; /* All trips were consumed */
|
||||||
|
|
||||||
sequence_changed |= merge_dive_tables(import_table, NULL, &dive_table, NULL, prefer_imported, NULL);
|
/* The remaining dives in import_table are those that don't belong to
|
||||||
|
* a trip. Merge them into the global table. */
|
||||||
|
sequence_changed |= merge_dive_tables(import_table, NULL, &dive_table, prefer_imported, NULL,
|
||||||
|
dives_to_add, dives_to_remove, &start_renumbering_at);
|
||||||
|
|
||||||
/* If the sequence wasn't changed, renumber */
|
/* If new dives were only added at the end, renumber the added dives.
|
||||||
if (!sequence_changed)
|
* But only if
|
||||||
try_to_renumber(preexisting);
|
* - The last dive in the old dive table had a number itself.
|
||||||
|
* - None of the new dives has a number.
|
||||||
/* Unlikely, but trip order may have changed owing to merging dives -
|
*/
|
||||||
* make sure that they are still ordered */
|
nr = dive_table.nr > 0 ? dive_table.dives[dive_table.nr - 1]->number : 0;
|
||||||
sort_trip_table(&trip_table);
|
/* We counted the number of merged dives that were added to dives_to_add.
|
||||||
|
* Skip those. Since sequence_changed is false all added dives are *after*
|
||||||
/* We might have deleted the old selected dive.
|
* all merged dives. */
|
||||||
* Choose the newest dive as selected (if any) */
|
if (!sequence_changed && nr >= preexisting && !new_dive_has_number) {
|
||||||
current_dive = dive_table.nr > 0 ? dive_table.dives[dive_table.nr - 1] : NULL;
|
for (i = start_renumbering_at; i < dives_to_add->nr; i++)
|
||||||
mark_divelist_changed(true);
|
dives_to_add->dives[i]->number = ++nr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the number a dive gets when inserted at the given index.
|
/* return the number a dive gets when inserted at the given index.
|
||||||
|
@ -1819,16 +1840,6 @@ void clear_dive_file_data()
|
||||||
saved_git_id = "";
|
saved_git_id = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear a dive_table
|
|
||||||
*/
|
|
||||||
void clear_table(struct dive_table *table)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < table->nr; i++)
|
|
||||||
free_dive(table->dives[i]);
|
|
||||||
table->nr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dive_less_than(const struct dive *a, const struct dive *b)
|
bool dive_less_than(const struct dive *a, const struct dive *b)
|
||||||
{
|
{
|
||||||
return comp_dives(a, b) < 0;
|
return comp_dives(a, b) < 0;
|
||||||
|
|
|
@ -18,8 +18,12 @@ extern int init_decompression(struct deco_state *ds, struct dive *dive);
|
||||||
|
|
||||||
/* divelist core logic functions */
|
/* divelist core logic functions */
|
||||||
extern void process_loaded_dives();
|
extern void process_loaded_dives();
|
||||||
|
extern void add_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table,
|
||||||
|
bool prefer_imported, bool downloaded, bool merge_all_trips);
|
||||||
extern void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table,
|
extern void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table,
|
||||||
bool prefer_imported, bool downloaded, bool merge_all_trips);
|
bool prefer_imported, bool downloaded, bool merge_all_trips,
|
||||||
|
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
|
||||||
|
struct trip_table *trips_to_add);
|
||||||
extern char *get_dive_gas_string(const struct dive *dive);
|
extern char *get_dive_gas_string(const struct dive *dive);
|
||||||
|
|
||||||
extern struct dive **grow_dive_table(struct dive_table *table);
|
extern struct dive **grow_dive_table(struct dive_table *table);
|
||||||
|
|
|
@ -1011,7 +1011,7 @@ void DiveLogImportDialog::on_buttonBox_accepted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
Command::clear();
|
Command::clear();
|
||||||
MainWindow::instance()->refreshDisplay();
|
MainWindow::instance()->refreshDisplay();
|
||||||
}
|
}
|
||||||
|
|
|
@ -525,9 +525,9 @@ void DownloadFromDCWidget::on_ok_clicked()
|
||||||
// remember the last downloaded dive (on most dive computers this will be the chronologically
|
// remember the last downloaded dive (on most dive computers this will be the chronologically
|
||||||
// first new dive) and select it again after processing all the dives
|
// first new dive) and select it again after processing all the dives
|
||||||
int uniqId = table->dives[table->nr - 1]->id;
|
int uniqId = table->dives[table->nr - 1]->id;
|
||||||
process_imported_dives(table, trips, preferDownloaded(), true, false);
|
add_imported_dives(table, trips, preferDownloaded(), true, false);
|
||||||
Command::clear();
|
Command::clear();
|
||||||
// after process_imported_dives does any merging or resorting needed, we need
|
// after add_imported_dives does any merging or resorting needed, we need
|
||||||
// to recreate the model for the dive list so we can select the newest dive
|
// to recreate the model for the dive list so we can select the newest dive
|
||||||
MainWindow::instance()->recreateDiveList();
|
MainWindow::instance()->recreateDiveList();
|
||||||
int idx = get_idx_by_uniq_id(uniqId);
|
int idx = get_idx_by_uniq_id(uniqId);
|
||||||
|
|
|
@ -1714,7 +1714,7 @@ void MainWindow::importFiles(const QStringList fileNames)
|
||||||
fileNamePtr = QFile::encodeName(fileNames.at(i));
|
fileNamePtr = QFile::encodeName(fileNames.at(i));
|
||||||
parse_file(fileNamePtr.data(), &table, &trips);
|
parse_file(fileNamePtr.data(), &table, &trips);
|
||||||
}
|
}
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
Command::clear();
|
Command::clear();
|
||||||
refreshDisplay();
|
refreshDisplay();
|
||||||
}
|
}
|
||||||
|
|
|
@ -771,7 +771,7 @@ void DivelogsDeWebServices::buttonClicked(QAbstractButton *button)
|
||||||
struct dive_table table = { 0 };
|
struct dive_table table = { 0 };
|
||||||
struct trip_table trips = { 0 };
|
struct trip_table trips = { 0 };
|
||||||
parse_file(QFile::encodeName(zipFile.fileName()), &table, &trips);
|
parse_file(QFile::encodeName(zipFile.fileName()), &table, &trips);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
MainWindow::instance()->refreshDisplay();
|
MainWindow::instance()->refreshDisplay();
|
||||||
|
|
||||||
/* store last entered user/pass in config */
|
/* store last entered user/pass in config */
|
||||||
|
|
|
@ -341,7 +341,7 @@ void QMLManager::mergeLocalRepo()
|
||||||
struct dive_table table = { 0 };
|
struct dive_table table = { 0 };
|
||||||
struct trip_table trips = { 0 };
|
struct trip_table trips = { 0 };
|
||||||
parse_file(filename, &table, &trips);
|
parse_file(filename, &table, &trips);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMLManager::copyAppLogToClipboard()
|
void QMLManager::copyAppLogToClipboard()
|
||||||
|
|
|
@ -157,7 +157,7 @@ void DiveImportedModel::recordDives()
|
||||||
delete_dive_from_table(diveTable, j);
|
delete_dive_from_table(diveTable, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
process_imported_dives(diveTable, tripTable, true, true, false);
|
add_imported_dives(diveTable, tripTable, true, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> DiveImportedModel::roleNames() const {
|
QHash<int, QByteArray> DiveImportedModel::roleNames() const {
|
||||||
|
|
|
@ -137,7 +137,7 @@ void TestGitStorage::testGitStorageCloudOfflineSync()
|
||||||
// read the local repo from the previous test and add dive 10
|
// read the local repo from the previous test and add dive 10
|
||||||
QCOMPARE(parse_file(qPrintable(localCacheRepo), &dive_table, &trip_table), 0);
|
QCOMPARE(parse_file(qPrintable(localCacheRepo), &dive_table, &trip_table), 0);
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test10.xml", &dive_table, &trip_table), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test10.xml", &dive_table, &trip_table), 0);
|
||||||
// calling process_loaded_dives() sorts the table, but calling process_imported_dives()
|
// calling process_loaded_dives() sorts the table, but calling add_imported_dives()
|
||||||
// causes it to try to update the window title... let's not do that
|
// causes it to try to update the window title... let's not do that
|
||||||
process_loaded_dives();
|
process_loaded_dives();
|
||||||
// now save only to the local cache but not to the remote server
|
// now save only to the local cache but not to the remote server
|
||||||
|
|
|
@ -24,9 +24,9 @@ void TestMerge::testMergeEmpty()
|
||||||
struct dive_table table = { 0 };
|
struct dive_table table = { 0 };
|
||||||
struct trip_table trips = { 0 };
|
struct trip_table trips = { 0 };
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47.xml", &table, &trips), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47.xml", &table, &trips), 0);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test48.xml", &table, &trips), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test48.xml", &table, &trips), 0);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
QCOMPARE(save_dives("./testmerge47+48.ssrf"), 0);
|
QCOMPARE(save_dives("./testmerge47+48.ssrf"), 0);
|
||||||
QFile org(SUBSURFACE_TEST_DATA "/dives/test47+48.xml");
|
QFile org(SUBSURFACE_TEST_DATA "/dives/test47+48.xml");
|
||||||
org.open(QFile::ReadOnly);
|
org.open(QFile::ReadOnly);
|
||||||
|
@ -49,9 +49,9 @@ void TestMerge::testMergeBackwards()
|
||||||
struct dive_table table = { 0 };
|
struct dive_table table = { 0 };
|
||||||
struct trip_table trips = { 0 };
|
struct trip_table trips = { 0 };
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test48.xml", &table, &trips), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test48.xml", &table, &trips), 0);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47.xml", &table, &trips), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47.xml", &table, &trips), 0);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
QCOMPARE(save_dives("./testmerge47+48.ssrf"), 0);
|
QCOMPARE(save_dives("./testmerge47+48.ssrf"), 0);
|
||||||
QFile org(SUBSURFACE_TEST_DATA "/dives/test47+48.xml");
|
QFile org(SUBSURFACE_TEST_DATA "/dives/test47+48.xml");
|
||||||
org.open(QFile::ReadOnly);
|
org.open(QFile::ReadOnly);
|
||||||
|
|
|
@ -16,7 +16,7 @@ void TestRenumber::testMerge()
|
||||||
struct dive_table table = { 0 };
|
struct dive_table table = { 0 };
|
||||||
struct trip_table trips = { 0 };
|
struct trip_table trips = { 0 };
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47b.xml", &table, &trip_table), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47b.xml", &table, &trip_table), 0);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
QCOMPARE(dive_table.nr, 1);
|
QCOMPARE(dive_table.nr, 1);
|
||||||
QCOMPARE(unsaved_changes(), 1);
|
QCOMPARE(unsaved_changes(), 1);
|
||||||
mark_divelist_changed(false);
|
mark_divelist_changed(false);
|
||||||
|
@ -27,7 +27,7 @@ void TestRenumber::testMergeAndAppend()
|
||||||
struct dive_table table = { 0 };
|
struct dive_table table = { 0 };
|
||||||
struct trip_table trips = { 0 };
|
struct trip_table trips = { 0 };
|
||||||
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47c.xml", &table, &trip_table), 0);
|
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47c.xml", &table, &trip_table), 0);
|
||||||
process_imported_dives(&table, &trips, false, false, true);
|
add_imported_dives(&table, &trips, false, false, true);
|
||||||
QCOMPARE(dive_table.nr, 2);
|
QCOMPARE(dive_table.nr, 2);
|
||||||
QCOMPARE(unsaved_changes(), 1);
|
QCOMPARE(unsaved_changes(), 1);
|
||||||
struct dive *d = get_dive(1);
|
struct dive *d = get_dive(1);
|
||||||
|
|
Loading…
Reference in a new issue