diff --git a/core/dive.h b/core/dive.h index a6210810d..d0666f724 100644 --- a/core/dive.h +++ b/core/dive.h @@ -286,11 +286,13 @@ typedef struct dive_trip /* Used by the io-routines to mark trips that have already been written. */ bool saved; bool autogen; - struct dive_trip *next; } dive_trip_t; -/* List of dive trips (sorted by date) */ -extern dive_trip_t *dive_trip_list; +struct trip_table { + int nr, allocated; + struct dive_trip **trips; +}; + struct picture; struct dive { int number; @@ -420,6 +422,7 @@ extern const struct units *get_units(void); extern int run_survey, verbose, quit, force_root; extern struct dive_table dive_table; +extern struct trip_table trip_table; extern struct dive displayed_dive; extern unsigned int dc_number; extern struct dive *current_dive; @@ -543,6 +546,7 @@ extern bool dive_less_than(const struct dive *a, const struct dive *b); extern bool trip_less_than(const struct dive_trip *a, const struct dive_trip *b); extern bool dive_or_trip_less_than(struct dive_or_trip a, struct dive_or_trip b); extern void sort_dive_table(struct dive_table *table); +extern void sort_trip_table(struct trip_table *table); extern struct dive *fixup_dive(struct dive *dive); extern void fixup_dc_duration(struct divecomputer *dc); extern int dive_getUniqID(); diff --git a/core/divelist.c b/core/divelist.c index 100266eb1..fbad84981 100644 --- a/core/divelist.c +++ b/core/divelist.c @@ -3,10 +3,10 @@ /* core logic for the dive list - * accessed through the following interfaces: * - * void process_loaded_dives(); - * void process_imported_dives(bool prefer_imported); - * dive_trip_t *dive_trip_list; - * unsigned int amount_selected; + * struct trip_table trip_table + * void process_loaded_dives() + * void process_imported_dives(bool prefer_imported) + * unsigned int amount_selected * void dump_selection(void) * void get_dive_gas(const struct dive *dive, int *o2_p, int *he_p, int *o2low_p) * char *get_dive_gas_string(const struct dive *dive) @@ -38,6 +38,7 @@ * bool trip_less_than(const struct dive_trip *a, const struct dive_trip *b) * bool dive_or_trip_less_than(struct dive_or_trip a, struct dive_or_trip b) * void sort_dive_table(struct dive_table *table) + * void sort_trip_table(struct trip_table *table) * bool is_trip_before_after(const struct dive *dive, bool before) * void delete_dive_from_table(struct dive_table *table, int idx) * int find_next_visible_dive(timestamp_t when); @@ -69,7 +70,7 @@ static bool dive_list_changed = false; bool autogroup = false; -dive_trip_t *dive_trip_list; +struct trip_table trip_table; unsigned int amount_selected; @@ -748,14 +749,15 @@ void dump_trip_list(void) int i = 0; timestamp_t last_time = 0; - for (trip = dive_trip_list; trip; trip = trip->next) { + for (i = 0; i < trip_table.nr; ++i) { struct tm tm; + trip = trip_table.trips[i]; utc_mkdate(trip_date(trip), &tm); if (trip_date(trip) < last_time) - printf("\n\ndive_trip_list OUT OF ORDER!!!\n\n\n"); + printf("\n\ntrip_table 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, + i + 1, trip->location, tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, trip->dives.nr, trip); last_time = trip_date(trip); @@ -764,23 +766,6 @@ void dump_trip_list(void) } #endif -/* insert the trip into the dive_trip_list */ -void insert_trip(dive_trip_t *dive_trip) -{ - dive_trip_t **p = &dive_trip_list; - dive_trip_t *trip; - - /* Walk the dive trip list looking for the right location.. */ - while ((trip = *p) != NULL && trip_less_than(trip, dive_trip)) - p = &trip->next; - - dive_trip->next = trip; - *p = dive_trip; -#ifdef DEBUG_TRIP - dump_trip_list(); -#endif -} - /* free resources associated with a trip structure */ void free_trip(dive_trip_t *trip) { @@ -791,32 +776,6 @@ void free_trip(dive_trip_t *trip) } } -/* remove trip from the trip-list, but don't free its memory. - * caller takes ownership of the trip. */ -void unregister_trip(dive_trip_t *trip) -{ - dive_trip_t **p, *tmp; - - assert(!trip->dives.nr); - - /* 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; - } -} - -static void delete_trip(dive_trip_t *trip) -{ - unregister_trip(trip); - free_trip(trip); -} - - timestamp_t trip_date(const struct dive_trip *trip) { if (!trip || trip->dives.nr == 0) @@ -902,6 +861,18 @@ static int comp_dives(const struct dive *a, const struct dive *b) return 0; /* this should not happen for a != b */ } +/* Trips are compared according to the first dive in the trip. */ +static int comp_trips(const struct dive_trip *a, const struct dive_trip *b) +{ + /* This should never happen, nevertheless don't crash on trips + * with no (or worse a negative number of) dives. */ + if (a->dives.nr <= 0) + return b->dives.nr <= 0 ? 0 : -1; + if (b->dives.nr <= 0) + return 1; + return comp_dives(a->dives.dives[0], b->dives.dives[0]); +} + #define MAKE_GROW_TABLE(table_type, item_type, array_name) \ item_type *grow_##table_type(struct table_type *table) \ { \ @@ -920,6 +891,7 @@ static int comp_dives(const struct dive *a, const struct dive *b) } MAKE_GROW_TABLE(dive_table, struct dive *, dives) +static MAKE_GROW_TABLE(trip_table, struct dive_trip *, trips) /* get the index where we want to insert an object so that everything stays * ordered according to a comparison function() */ @@ -935,6 +907,7 @@ MAKE_GROW_TABLE(dive_table, struct dive *, dives) } MAKE_GET_INSERTION_INDEX(dive_table, struct dive *, dives, dive_less_than) +static MAKE_GET_INSERTION_INDEX(trip_table, struct dive_trip *, trips, trip_less_than) /* add object at the given index to a table. */ #define MAKE_ADD_TO(table_type, item_type, array_name) \ @@ -952,6 +925,7 @@ MAKE_GET_INSERTION_INDEX(dive_table, struct dive *, dives, dive_less_than) } static MAKE_ADD_TO(dive_table, struct dive *, dives) +static MAKE_ADD_TO(trip_table, struct dive_trip *, trips) #define MAKE_REMOVE_FROM(table_type, array_name) \ void remove_from_##table_type(struct table_type *table, int idx) \ @@ -963,6 +937,7 @@ static MAKE_ADD_TO(dive_table, struct dive *, dives) } static MAKE_REMOVE_FROM(dive_table, dives) +static MAKE_REMOVE_FROM(trip_table, trips) #define MAKE_GET_IDX(table_type, item_type, array_name) \ int get_idx_in_##table_type(const struct table_type *table, const item_type item) \ @@ -975,6 +950,7 @@ static MAKE_REMOVE_FROM(dive_table, dives) } static MAKE_GET_IDX(dive_table, struct dive *, dives) +static MAKE_GET_IDX(trip_table, struct dive_trip *, trips) #define MAKE_SORT(table_type, item_type, array_name, fun) \ static int sortfn_##table_type(const void *_a, const void *_b) \ @@ -990,6 +966,7 @@ static MAKE_GET_IDX(dive_table, struct dive *, dives) } MAKE_SORT(dive_table, struct dive *, dives, comp_dives) +MAKE_SORT(trip_table, struct dive_trip *, trips, comp_trips) /* remove a dive from the trip it's associated to, but don't delete the * trip if this was the last dive in the trip. the caller is responsible @@ -1010,6 +987,12 @@ struct dive_trip *unregister_dive_from_trip(struct dive *dive) return trip; } +static void delete_trip(dive_trip_t *trip) +{ + unregister_trip(trip); + free_trip(trip); +} + void remove_dive_from_trip(struct dive *dive) { struct dive_trip *trip = unregister_dive_from_trip(dive); @@ -1036,6 +1019,16 @@ dive_trip_t *alloc_trip(void) return calloc(1, sizeof(dive_trip_t)); } +/* insert the trip into the trip table */ +void insert_trip(dive_trip_t *dive_trip) +{ + int idx = trip_table_get_insertion_index(&trip_table, dive_trip); + add_to_trip_table(&trip_table, idx, dive_trip); +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif +} + dive_trip_t *create_trip_from_dive(struct dive *dive) { dive_trip_t *trip; @@ -1051,12 +1044,22 @@ dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) dive_trip_t *dive_trip = alloc_trip(); dive_trip = create_trip_from_dive(dive); - insert_trip(dive_trip); add_dive_to_trip(dive, dive_trip); + insert_trip(dive_trip); return dive_trip; } +/* remove trip from the trip-list, but don't free its memory. + * caller takes ownership of the trip. */ +void unregister_trip(dive_trip_t *trip) +{ + int idx = get_idx_in_trip_table(&trip_table, trip); + assert(!trip->dives.nr); + if (idx >= 0) + remove_from_trip_table(&trip_table, idx); +} + /* * Find a trip a new dive should be autogrouped with. If no such trips * exist, allocate a new trip. The bool "*allocated" is set to true @@ -1153,7 +1156,7 @@ dive_trip_t *get_dives_to_autogroup(struct dive_table *table, int start, int *fr } /* - * Walk the dives from the oldest dive in the given tabe, and see if we + * Walk the dives from the oldest dive in the given table, and see if we * can autogroup them. But only do this when the user selected autogrouping. */ static void autogroup_dives(struct dive_table *table) @@ -1167,12 +1170,13 @@ static void autogroup_dives(struct dive_table *table) return; for (i = 0; (trip = get_dives_to_autogroup(&dive_table, i, &from, &to, &alloc)) != NULL; i = to) { + for (j = from; j < to; ++j) + add_dive_to_trip(get_dive(j), trip); /* If this was newly allocated, add trip to list */ if (alloc) insert_trip(trip); - for (j = from; j < to; ++j) - add_dive_to_trip(get_dive(j), trip); } + sort_trip_table(&trip_table); #ifdef DEBUG_TRIP dump_trip_list(); #endif @@ -1423,6 +1427,7 @@ void process_loaded_dives() set_dc_nickname(dive); sort_dive_table(&dive_table); + sort_trip_table(&trip_table); /* Autogroup dives if desired by user. */ autogroup_dives(&dive_table); @@ -1577,6 +1582,9 @@ void process_imported_dives(struct dive_table *import_table, bool prefer_importe /* Autogroup dives if desired by user. */ autogroup_dives(&dive_table); + /* Trips may have changed - make sure that they are still ordered */ + sort_trip_table(&trip_table); + /* 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; @@ -1660,6 +1668,10 @@ void clear_dive_file_data() delete_single_dive(0); while (dive_site_table.nr) delete_dive_site(get_dive_site(0)); + if (trip_table.nr != 0) { + fprintf(stderr, "Warning: trip table not empty in clear_dive_file_data()!\n"); + trip_table.nr = 0; + } clear_dive(&displayed_dive); @@ -1682,18 +1694,6 @@ bool dive_less_than(const struct dive *a, const struct dive *b) return comp_dives(a, b) < 0; } -/* Trips are compared according to the first dive in the trip. */ -static int comp_trips(const struct dive_trip *a, const struct dive_trip *b) -{ - /* This should never happen, nevertheless don't crash on trips - * with no (or worse a negative number of) dives. */ - if (a->dives.nr <= 0) - return b->dives.nr <= 0 ? 0 : -1; - if (b->dives.nr <= 0) - return 1; - return comp_dives(a->dives.dives[0], b->dives.dives[0]); -} - bool trip_less_than(const struct dive_trip *a, const struct dive_trip *b) { return comp_trips(a, b) < 0; diff --git a/core/save-git.c b/core/save-git.c index cdc0ca980..33c01ab83 100644 --- a/core/save-git.c +++ b/core/save-git.c @@ -930,8 +930,8 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o save_divesites(repo, root); - for (trip = dive_trip_list; trip != NULL; trip = trip->next) - trip->saved = 0; + for (i = 0; i < trip_table.nr; ++i) + trip_table.trips[i]->saved = 0; /* save the dives */ git_storage_update_progress(translate("gettextFromC", "Start saving dives")); diff --git a/core/save-html.c b/core/save-html.c index ec5751453..aeb74bf95 100644 --- a/core/save-html.c +++ b/core/save-html.c @@ -439,8 +439,8 @@ void write_trips(struct membuffer *b, const char *photos_dir, bool selected_only char sep_ = ' '; char *sep = &sep_; - for (trip = dive_trip_list; trip != NULL; trip = trip->next) - trip->saved = 0; + for (i = 0; i < trip_table.nr; ++i) + trip_table.trips[i]->saved = 0; for_each_dive (i, dive) { trip = dive->divetrip; diff --git a/core/save-xml.c b/core/save-xml.c index e49e186f4..cae18f8c7 100644 --- a/core/save-xml.c +++ b/core/save-xml.c @@ -637,8 +637,8 @@ void save_dives_buffer(struct membuffer *b, const bool select_only, bool anonymi put_format(b, "\n"); } put_format(b, "\n\n"); - for (trip = dive_trip_list; trip != NULL; trip = trip->next) - trip->saved = 0; + for (i = 0; i < trip_table.nr; ++i) + trip_table.trips[i]->saved = 0; /* save the dives */ for_each_dive(i, dive) { diff --git a/desktop-widgets/command_divelist.cpp b/desktop-widgets/command_divelist.cpp index 5e3f30ce2..b3c4f24e3 100644 --- a/desktop-widgets/command_divelist.cpp +++ b/desktop-widgets/command_divelist.cpp @@ -81,10 +81,10 @@ DiveToAdd DiveListBase::removeDive(struct dive *d) // Returns pointer to added dive (which is owned by the backend!) dive *DiveListBase::addDive(DiveToAdd &d) { - if (d.tripToAdd) - insert_trip(d.tripToAdd.release()); // Return ownership to backend if (d.trip) add_dive_to_trip(d.dive.get(), d.trip); + if (d.tripToAdd) + insert_trip(d.tripToAdd.release()); // Return ownership to backend dive *res = d.dive.release(); // Give up ownership of dive // Set the filter flag according to current filter settings @@ -530,6 +530,7 @@ void AddDive::redoit() currentDive = current_dive; divesToRemove = addDives(divesToAdd); + sort_trip_table(&trip_table); // Though unlikely, adding a dive may reorder trips mark_divelist_changed(true); // Select the newly added dive @@ -544,6 +545,7 @@ void AddDive::undoit() { // Simply remove the dive that was previously added... divesToAdd = removeDives(divesToRemove); + sort_trip_table(&trip_table); // Though unlikely, removing a dive may reorder trips // ...and restore the selection restoreSelection(selection, currentDive); @@ -566,6 +568,7 @@ bool DeleteDive::workToBeDone() void DeleteDive::undoit() { divesToDelete = addDives(divesToAdd); + sort_trip_table(&trip_table); // Though unlikely, removing a dive may reorder trips mark_divelist_changed(true); // Select all re-added dives and make the first one current @@ -576,6 +579,7 @@ void DeleteDive::undoit() void DeleteDive::redoit() { divesToAdd = removeDives(divesToDelete); + sort_trip_table(&trip_table); // Though unlikely, adding a dive may reorder trips mark_divelist_changed(true); // Deselect all dives and select dive that was close to the first deleted dive @@ -604,6 +608,7 @@ void ShiftTime::redoit() // Changing times may have unsorted the dive table sort_dive_table(&dive_table); + sort_trip_table(&trip_table); // We send one time changed signal per trip (see comments in DiveListNotifier.h). // Therefore, collect all dives in an array and sort by trip. @@ -667,6 +672,7 @@ bool TripBase::workToBeDone() void TripBase::redoit() { moveDivesBetweenTrips(divesToMove); + sort_trip_table(&trip_table); // Though unlikely, moving dives may reorder trips mark_divelist_changed(true); } diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index cdcbedecf..75d44deb1 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -1131,6 +1131,7 @@ void QMLManager::commitChanges(QString diveId, QString date, QString location, Q // we know that the only thing that might happen in a resort is that // this one dive moves to a different spot in the dive list sort_dive_table(&dive_table); + sort_trip_table(&trip_table); int newIdx = get_idx_by_uniq_id(d->id); if (newIdx != oldIdx) { DiveListModel::instance()->removeDive(modelIdx);