diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2019-03-03 15:12:22 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2019-04-12 18:19:07 +0300 |
commit | 82af1b2377cec03a989f86b8009d4ac226c6541e (patch) | |
tree | a875f194f7174c8673b2f7bd5cc43aa8ca3c51c6 /core | |
parent | 37146c5742503becf75468fb07aab56011cb9101 (diff) | |
download | subsurface-82af1b2377cec03a989f86b8009d4ac226c6541e.tar.gz |
Undo: make undo-system dive site-aware
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>
Diffstat (limited to 'core')
-rw-r--r-- | core/dive.h | 8 | ||||
-rw-r--r-- | core/divelist.c | 65 | ||||
-rw-r--r-- | core/divelist.h | 8 | ||||
-rw-r--r-- | core/divesite.c | 67 | ||||
-rw-r--r-- | core/divesite.h | 9 | ||||
-rw-r--r-- | core/downloadfromdcthread.cpp | 5 | ||||
-rw-r--r-- | core/downloadfromdcthread.h | 2 |
7 files changed, 134 insertions, 30 deletions
diff --git a/core/dive.h b/core/dive.h index d40e53043..03d6fc2df 100644 --- a/core/dive.h +++ b/core/dive.h @@ -758,15 +758,17 @@ extern void average_max_depth(struct diveplan *dive, int *avg_depth, int *max_de #ifdef __cplusplus } -/* Make pointers to dive, dive_trip and dive_table "Qt metatypes" so that they can - * be passed through QVariants and through QML. +/* Make pointers to dive, dive_trip, dive_table, trip_table and dive_site_table + * "Qt metatypes" so that they can be passed through QVariants and through QML. * Note: we have to use the typedef "dive_table_t" instead of "struct dive_table", * because MOC removes the "struct", but dive_table is already the name of a global - * variable, leading to compilation errors. Likewise for "struct trip_table". */ + * variable, leading to compilation errors. Likewise for "struct trip_table" and + * "struct dive_site_table". */ Q_DECLARE_METATYPE(struct dive *); Q_DECLARE_METATYPE(struct dive_trip *); Q_DECLARE_METATYPE(dive_table_t *); Q_DECLARE_METATYPE(trip_table_t *); +Q_DECLARE_METATYPE(dive_site_table_t *); #endif diff --git a/core/divelist.c b/core/divelist.c index 8e1ba1628..09f08acd0 100644 --- a/core/divelist.c +++ b/core/divelist.c @@ -1518,17 +1518,18 @@ 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" * and dive_table "dives_to". If "prefer_imported" is true, dive data of "from" takes * precedence */ -void add_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, int flags) +void add_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, struct dive_site_table *import_sites_table, int flags) { int i, idx; struct dive_table dives_to_add = { 0 }; struct dive_table dives_to_remove = { 0 }; struct trip_table trips_to_add = { 0 }; + struct dive_site_table dive_sites_to_add = { 0 }; /* Process imported dives and generate lists of dives * to-be-added and to-be-removed */ - process_imported_dives(import_table, import_trip_table, flags, - &dives_to_add, &dives_to_remove, &trips_to_add); + process_imported_dives(import_table, import_trip_table, import_sites_table, flags, + &dives_to_add, &dives_to_remove, &trips_to_add, &dive_sites_to_add); /* Add new dives to trip, so that trips don't get deleted * on deletion of old dives */ @@ -1560,6 +1561,11 @@ void add_imported_dives(struct dive_table *import_table, struct trip_table *impo insert_trip(trips_to_add.trips[i], &trip_table); trips_to_add.nr = 0; + /* Add new dive sites */ + for (i = 0; i < dive_sites_to_add.nr; i++) + register_dive_site(dive_sites_to_add.dive_sites[i]); + dive_sites_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; @@ -1600,21 +1606,23 @@ bool try_to_merge_trip(struct dive_trip *trip_import, struct dive_table *import_ } /* Process imported dives: take a table of dives to be imported and - * generate three lists: + * generate four lists: * 1) Dives to be added * 2) Dives to be removed * 3) Trips to be added + * 4) Dive sites 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. - * "import_trip_table" may be NULL if all dives are not associated + * The dives, trips and sites in "import_table", "import_trip_table" + * and "import_sites_table" are consumed. On return, the tables have + * size 0. "import_trip_table" may be NULL if all dives are not associated * with a trip. - * The output parameters should be empty - if not, their content + * The output tables 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. + * Note: The new dives will have their divetrip- and divesites-fields + * set, but will *not* be part of the trip and site. The caller has to + * add them to the trip and site. * * The lists are generated by merging dives if possible. This is * performed trip-wise. Finer control on merging is provided by @@ -1629,10 +1637,11 @@ bool try_to_merge_trip(struct dive_trip *trip_import, struct dive_table *import_ * - If IMPORT_ADD_TO_NEW_TRIP is true, dives that are not assigned * to a trip will be added to a newly generated trip. */ -void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, int flags, +void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, + struct dive_site_table *import_sites_table, int flags, /* output parameters: */ struct dive_table *dives_to_add, struct dive_table *dives_to_remove, - struct trip_table *trips_to_add) + struct trip_table *trips_to_add, struct dive_site_table *sites_to_add) { int i, j, nr, start_renumbering_at = 0; struct dive_trip *trip_import, *new_trip; @@ -1651,6 +1660,7 @@ void process_imported_dives(struct dive_table *import_table, struct trip_table * clear_table(dives_to_add); clear_table(dives_to_remove); clear_trip_table(trips_to_add); + clear_dive_site_table(sites_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 @@ -1687,6 +1697,37 @@ void process_imported_dives(struct dive_table *import_table, struct trip_table * preexisting = dive_table.nr; /* Remember old size for renumbering */ + /* If dive sites already exist, use the existing versions. */ + for (i = 0; i < import_sites_table->nr; i++) { + struct dive_site *new_ds = import_sites_table->dive_sites[i]; + struct dive_site *old_ds = get_same_dive_site(new_ds); + + /* Check if it dive site is actually used by new dives. */ + for (j = 0; j < import_table->nr; j++) { + if (import_table->dives[j]->dive_site == new_ds) + break; + } + + if (j == import_table->nr) { + /* Dive site not even used - free it and go to next. */ + free_dive_site(new_ds); + continue; + } + + if (!old_ds) { + /* Dive site doesn't exist. Add it to list of dive sites to be added. */ + add_dive_site_to_table(new_ds, sites_to_add); + continue; + } + /* Dive site already exists - use the old and free the new. */ + for (j = 0; j < import_table->nr; j++) { + if (import_table->dives[j]->dive_site == new_ds) + import_table->dives[j]->dive_site = old_ds; + } + free_dive_site(new_ds); + } + import_sites_table->nr = 0; /* All dive sites were consumed */ + /* Merge overlapping trips. Since both trip tables are sorted, we * could be smarter here, but realistically not a whole lot of trips * will be imported so do a simple n*m loop until someone complains. diff --git a/core/divelist.h b/core/divelist.h index e1ff706f7..1880856df 100644 --- a/core/divelist.h +++ b/core/divelist.h @@ -23,10 +23,12 @@ extern void process_loaded_dives(); #define IMPORT_IS_DOWNLOADED (1 << 1) #define IMPORT_MERGE_ALL_TRIPS (1 << 2) #define IMPORT_ADD_TO_NEW_TRIP (1 << 3) -extern void add_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, int flags); -extern void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, int flags, +extern void add_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, struct dive_site_table *import_sites_table, + int flags); +extern void process_imported_dives(struct dive_table *import_table, struct trip_table *import_trip_table, struct dive_site_table *import_sites_table, + int flags, struct dive_table *dives_to_add, struct dive_table *dives_to_remove, - struct trip_table *trips_to_add); + struct trip_table *trips_to_add, struct dive_site_table *sites_to_add); extern char *get_dive_gas_string(const struct dive *dive); extern struct dive **grow_dive_table(struct dive_table *table); diff --git a/core/divesite.c b/core/divesite.c index 9baabd872..bf99ed395 100644 --- a/core/divesite.c +++ b/core/divesite.c @@ -117,14 +117,13 @@ static uint32_t dive_site_getUniqId(struct dive_site_table *ds_table) return id; } -/* we never allow a second dive site with the same uuid */ -struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table) +void register_dive_site(struct dive_site *ds) { - struct dive_site *ds; - - if (uuid && (ds = get_dive_site_by_uuid(uuid, ds_table)) != NULL) - return ds; + add_dive_site_to_table(ds, &dive_site_table); +} +void add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table) +{ int nr = ds_table->nr; int allocated = ds_table->allocated; struct dive_site **sites = ds_table->dive_sites; @@ -137,11 +136,23 @@ struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table * ds_table->dive_sites = sites; ds_table->allocated = allocated; } + sites[nr] = ds; + ds_table->nr = nr + 1; +} + +/* we never allow a second dive site with the same uuid */ +struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table) +{ + struct dive_site *ds; + + if (uuid && (ds = get_dive_site_by_uuid(uuid, ds_table)) != NULL) + return ds; + ds = calloc(1, sizeof(*ds)); if (!ds) exit(1); - sites[nr] = ds; - ds_table->nr = nr + 1; + add_dive_site_to_table(ds, ds_table); + // we should always be called with a valid uuid except in the special // case where we want to copy a dive site into the memory we allocated // here - then we need to pass in 0 and create a temporary uuid here @@ -195,12 +206,16 @@ void free_dive_site(struct dive_site *ds) } } -void delete_dive_site(struct dive_site *ds, struct dive_site_table *ds_table) +void unregister_dive_site(struct dive_site *ds) +{ + remove_dive_site_from_table(ds, &dive_site_table); +} + +void remove_dive_site_from_table(struct dive_site *ds, struct dive_site_table *ds_table) { int nr = ds_table->nr; for (int i = 0; i < nr; i++) { if (ds == get_dive_site(i, ds_table)) { - free_dive_site(ds); if (nr - 1 > i) memmove(&ds_table->dive_sites[i], &ds_table->dive_sites[i+1], @@ -211,6 +226,14 @@ void delete_dive_site(struct dive_site *ds, struct dive_site_table *ds_table) } } +void delete_dive_site(struct dive_site *ds, struct dive_site_table *ds_table) +{ + if (!ds) + return; + remove_dive_site_from_table(ds, ds_table); + free_dive_site(ds); +} + static uint32_t create_divesite_uuid(const char *name, timestamp_t divetime) { if (name == NULL) @@ -291,6 +314,30 @@ static void merge_string(char **a, char **b) free(s1); } +/* Used to check on import if two dive sites are equivalent. + * Since currently no merging is performed, be very conservative + * and only consider equal dive sites that are exactly the same. + * Taxonomy is not compared, as no taxonomy is generated on + * import. + */ +static bool same_dive_site(const struct dive_site *a, const struct dive_site *b) +{ + return same_string(a->name, b->name) + && same_location(&a->location, &b->location) + && same_string(a->description, b->description) + && same_string(a->notes, b->notes); +} + +struct dive_site *get_same_dive_site(const struct dive_site *site) +{ + int i; + struct dive_site *ds; + for_each_dive_site (i, ds, &dive_site_table) + if (same_dive_site(ds, site)) + return ds; + return NULL; +} + void merge_dive_site(struct dive_site *a, struct dive_site *b) { if (!has_location(&a->location)) a->location = b->location; diff --git a/core/divesite.h b/core/divesite.h index ba4cd32a5..1f841a7d2 100644 --- a/core/divesite.h +++ b/core/divesite.h @@ -24,10 +24,10 @@ struct dive_site struct taxonomy_data taxonomy; }; -struct dive_site_table { +typedef struct dive_site_table { int nr, allocated; struct dive_site **dive_sites; -}; +} dive_site_table_t; extern struct dive_site_table dive_site_table; @@ -45,6 +45,10 @@ static inline struct dive_site *get_dive_site(int nr, struct dive_site_table *ds int get_divesite_idx(const struct dive_site *ds, struct dive_site_table *ds_table); struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_site_table *ds_table); void dive_site_table_sort(struct dive_site_table *ds_table); +void add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table); +void remove_dive_site_from_table(struct dive_site *ds, struct dive_site_table *ds_table); +void register_dive_site(struct dive_site *ds); +void unregister_dive_site(struct dive_site *ds); struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table); int nr_of_dives_at_dive_site(struct dive_site *ds, bool select_only); bool is_dive_site_used(struct dive_site *ds, bool select_only); @@ -56,6 +60,7 @@ struct dive_site *get_dive_site_by_name(const char *name, struct dive_site_table struct dive_site *get_dive_site_by_gps(const location_t *, struct dive_site_table *ds_table); struct dive_site *get_dive_site_by_gps_and_name(char *name, const location_t *, struct dive_site_table *ds_table); struct dive_site *get_dive_site_by_gps_proximity(const location_t *, int distance, struct dive_site_table *ds_table); +struct dive_site *get_same_dive_site(const struct dive_site *); bool dive_site_is_empty(struct dive_site *ds); void copy_dive_site_taxonomy(struct dive_site *orig, struct dive_site *copy); void copy_dive_site(struct dive_site *orig, struct dive_site *copy); diff --git a/core/downloadfromdcthread.cpp b/core/downloadfromdcthread.cpp index 5b336dee5..f2a65ac5f 100644 --- a/core/downloadfromdcthread.cpp +++ b/core/downloadfromdcthread.cpp @@ -306,6 +306,11 @@ struct dive_table *DownloadThread::table() return &downloadTable; } +struct dive_site_table *DownloadThread::sites() +{ + return &diveSiteTable; +} + QString DCDeviceData::vendor() const { return data.vendor; diff --git a/core/downloadfromdcthread.h b/core/downloadfromdcthread.h index e4cfb2351..d14a5402b 100644 --- a/core/downloadfromdcthread.h +++ b/core/downloadfromdcthread.h @@ -59,6 +59,7 @@ private: class DownloadThread : public QThread { Q_OBJECT Q_PROPERTY(dive_table_t *table READ table CONSTANT) + Q_PROPERTY(dive_site_table_t *sites READ sites CONSTANT) public: DownloadThread(); @@ -66,6 +67,7 @@ public: DCDeviceData *data(); struct dive_table *table(); + struct dive_site_table *sites(); QString error; private: |