core: convert taxonomy.c to C++

Since the taxonomy is now a real C++ struct with constructor
and destructor, dive_site has to be converted to C++ as well.

A bit hairy for now, but will ultimately be distinctly simpler.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-05-04 13:39:04 +02:00 committed by bstoeger
parent 3c1401785b
commit 3f8b4604be
39 changed files with 259 additions and 336 deletions

View file

@ -95,7 +95,7 @@ SOURCES += subsurface-mobile-main.cpp \
core/string-format.cpp \ core/string-format.cpp \
core/strtod.cpp \ core/strtod.cpp \
core/tag.cpp \ core/tag.cpp \
core/taxonomy.c \ core/taxonomy.cpp \
core/time.cpp \ core/time.cpp \
core/trip.c \ core/trip.c \
core/units.cpp \ core/units.cpp \

View file

@ -145,10 +145,10 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
struct tm tm; struct tm tm;
utc_mkdate(dive->when, &tm); utc_mkdate(dive->when, &tm);
const char *country = NULL; std::string country;
dive_site *site = dive->dive_site; dive_site *site = dive->dive_site;
if (site) if (site)
country = taxonomy_get_country(&site->taxonomy); country = taxonomy_get_country(site->taxonomy);
pressure_t delta_p = {.mbar = 0}; pressure_t delta_p = {.mbar = 0};
QString star = "*"; QString star = "*";
@ -180,7 +180,7 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
site ? put_format(&buf, "\\def\\%sgpslat{%f}\n", ssrf, site->location.lat.udeg / 1000000.0) : put_format(&buf, "\\def\\%sgpslat{}\n", ssrf); site ? put_format(&buf, "\\def\\%sgpslat{%f}\n", ssrf, site->location.lat.udeg / 1000000.0) : put_format(&buf, "\\def\\%sgpslat{}\n", ssrf);
site ? put_format(&buf, "\\def\\%sgpslon{%f}\n", ssrf, site->location.lon.udeg / 1000000.0) : put_format(&buf, "\\def\\gpslon{}\n"); site ? put_format(&buf, "\\def\\%sgpslon{%f}\n", ssrf, site->location.lon.udeg / 1000000.0) : put_format(&buf, "\\def\\gpslon{}\n");
put_format(&buf, "\\def\\%scomputer{%s}\n", ssrf, dive->dc.model); put_format(&buf, "\\def\\%scomputer{%s}\n", ssrf, dive->dc.model);
put_format(&buf, "\\def\\%scountry{%s}\n", ssrf, country ?: ""); put_format(&buf, "\\def\\%scountry{%s}\n", ssrf, country.c_str());
put_format(&buf, "\\def\\%stime{%u:%02u}\n", ssrf, FRACTION_TUPLE(dive->duration.seconds, 60)); put_format(&buf, "\\def\\%stime{%u:%02u}\n", ssrf, FRACTION_TUPLE(dive->duration.seconds, 60));
put_format(&buf, "\n%% Dive Profile Details:\n"); put_format(&buf, "\n%% Dive Profile Details:\n");

View file

@ -125,7 +125,7 @@ DivesAndTripsToAdd DiveListBase::removeDives(DivesAndSitesToRemove &divesAndSite
{ {
std::vector<DiveToAdd> divesToAdd; std::vector<DiveToAdd> divesToAdd;
std::vector<OwningTripPtr> tripsToAdd; std::vector<OwningTripPtr> tripsToAdd;
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
divesToAdd.reserve(divesAndSitesToDelete.dives.size()); divesToAdd.reserve(divesAndSitesToDelete.dives.size());
sitesToAdd.reserve(divesAndSitesToDelete.sites.size()); sitesToAdd.reserve(divesAndSitesToDelete.sites.size());
@ -216,7 +216,7 @@ DivesAndSitesToRemove DiveListBase::addDives(DivesAndTripsToAdd &toAdd)
toAdd.trips.clear(); toAdd.trips.clear();
// Finally, add any necessary dive sites // Finally, add any necessary dive sites
for (OwningDiveSitePtr &ds: toAdd.sites) { for (std::unique_ptr<dive_site> &ds: toAdd.sites) {
sites.push_back(ds.get()); sites.push_back(ds.get());
int idx = register_dive_site(ds.release()); // Return ownership to backend int idx = register_dive_site(ds.release()); // Return ownership to backend
emit diveListNotifier.diveSiteAdded(sites.back(), idx); emit diveListNotifier.diveSiteAdded(sites.back(), idx);

View file

@ -24,7 +24,7 @@ struct DiveToAdd {
struct DivesAndTripsToAdd { struct DivesAndTripsToAdd {
std::vector<DiveToAdd> dives; std::vector<DiveToAdd> dives;
std::vector<OwningTripPtr> trips; std::vector<OwningTripPtr> trips;
std::vector<OwningDiveSitePtr> sites; std::vector<std::unique_ptr<dive_site>> sites;
}; };
// Dives and sites that have to be removed for a command // Dives and sites that have to be removed for a command
@ -111,7 +111,7 @@ private:
struct device_table devicesToAddAndRemove; struct device_table devicesToAddAndRemove;
// For redo // For redo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
std::vector<std::pair<std::string,FilterData>> std::vector<std::pair<std::string,FilterData>>
filterPresetsToAdd; filterPresetsToAdd;

View file

@ -15,13 +15,13 @@ namespace Command {
// Add a set of dive sites to the core. The dives that were associated with // Add a set of dive sites to the core. The dives that were associated with
// that dive site will be restored to that dive site. // that dive site will be restored to that dive site.
static std::vector<dive_site *> addDiveSites(std::vector<OwningDiveSitePtr> &sites) static std::vector<dive_site *> addDiveSites(std::vector<std::unique_ptr<dive_site>> &sites)
{ {
std::vector<dive_site *> res; std::vector<dive_site *> res;
QVector<dive *> changedDives; QVector<dive *> changedDives;
res.reserve(sites.size()); res.reserve(sites.size());
for (OwningDiveSitePtr &ds: sites) { for (std::unique_ptr<dive_site> &ds: sites) {
// Readd the dives that belonged to this site // Readd the dives that belonged to this site
for (int i = 0; i < ds->dives.nr; ++i) { for (int i = 0; i < ds->dives.nr; ++i) {
// TODO: send dive site changed signal // TODO: send dive site changed signal
@ -47,9 +47,9 @@ static std::vector<dive_site *> addDiveSites(std::vector<OwningDiveSitePtr> &sit
// Remove a set of dive sites. Get owning pointers to them. The dives are set to // Remove a set of dive sites. Get owning pointers to them. The dives are set to
// being at no dive site, but the dive site will retain a list of dives, so // being at no dive site, but the dive site will retain a list of dives, so
// that the dives can be readded to the site on undo. // that the dives can be readded to the site on undo.
static std::vector<OwningDiveSitePtr> removeDiveSites(std::vector<dive_site *> &sites) static std::vector<std::unique_ptr<dive_site>> removeDiveSites(std::vector<dive_site *> &sites)
{ {
std::vector<OwningDiveSitePtr> res; std::vector<std::unique_ptr<dive_site>> res;
QVector<dive *> changedDives; QVector<dive *> changedDives;
res.reserve(sites.size()); res.reserve(sites.size());
@ -77,7 +77,7 @@ static std::vector<OwningDiveSitePtr> removeDiveSites(std::vector<dive_site *> &
AddDiveSite::AddDiveSite(const QString &name) AddDiveSite::AddDiveSite(const QString &name)
{ {
setText(Command::Base::tr("add dive site")); setText(Command::Base::tr("add dive site"));
sitesToAdd.emplace_back(alloc_dive_site()); sitesToAdd.push_back(std::make_unique<dive_site>());
sitesToAdd.back()->name = copy_qstring(name); sitesToAdd.back()->name = copy_qstring(name);
} }
@ -107,7 +107,7 @@ ImportDiveSites::ImportDiveSites(struct dive_site_table *sites, const QString &s
// the same name. We might want to be smarter here and merge dive site data, etc. // the same name. We might want to be smarter here and merge dive site data, etc.
struct dive_site *old_ds = get_same_dive_site(new_ds); struct dive_site *old_ds = get_same_dive_site(new_ds);
if (old_ds) { if (old_ds) {
free_dive_site(new_ds); delete new_ds;
continue; continue;
} }
sitesToAdd.emplace_back(new_ds); sitesToAdd.emplace_back(new_ds);
@ -256,20 +256,20 @@ void EditDiveSiteNotes::undo()
} }
EditDiveSiteCountry::EditDiveSiteCountry(dive_site *dsIn, const QString &country) : ds(dsIn), EditDiveSiteCountry::EditDiveSiteCountry(dive_site *dsIn, const QString &country) : ds(dsIn),
value(country) value(country.toStdString())
{ {
setText(Command::Base::tr("Edit dive site country")); setText(Command::Base::tr("Edit dive site country"));
} }
bool EditDiveSiteCountry::workToBeDone() bool EditDiveSiteCountry::workToBeDone()
{ {
return !same_string(qPrintable(value), taxonomy_get_country(&ds->taxonomy)); return value == taxonomy_get_country(ds->taxonomy);
} }
void EditDiveSiteCountry::redo() void EditDiveSiteCountry::redo()
{ {
QString old = taxonomy_get_country(&ds->taxonomy); std::string old = taxonomy_get_country(ds->taxonomy);
taxonomy_set_country(&ds->taxonomy, qPrintable(value), taxonomy_origin::GEOMANUAL); taxonomy_set_country(ds->taxonomy, value, taxonomy_origin::GEOMANUAL);
value = old; value = old;
emit diveListNotifier.diveSiteChanged(ds, LocationInformationModel::TAXONOMY); // Inform frontend of changed dive site. emit diveListNotifier.diveSiteChanged(ds, LocationInformationModel::TAXONOMY); // Inform frontend of changed dive site.
} }
@ -310,14 +310,11 @@ void EditDiveSiteLocation::undo()
EditDiveSiteTaxonomy::EditDiveSiteTaxonomy(dive_site *dsIn, taxonomy_data &taxonomy) : ds(dsIn), EditDiveSiteTaxonomy::EditDiveSiteTaxonomy(dive_site *dsIn, taxonomy_data &taxonomy) : ds(dsIn),
value(taxonomy) value(taxonomy)
{ {
// We did a dumb copy. Erase the source to remove double references to strings.
memset(&taxonomy, 0, sizeof(taxonomy));
setText(Command::Base::tr("Edit dive site taxonomy")); setText(Command::Base::tr("Edit dive site taxonomy"));
} }
EditDiveSiteTaxonomy::~EditDiveSiteTaxonomy() EditDiveSiteTaxonomy::~EditDiveSiteTaxonomy()
{ {
free_taxonomy(&value);
} }
bool EditDiveSiteTaxonomy::workToBeDone() bool EditDiveSiteTaxonomy::workToBeDone()
@ -364,7 +361,7 @@ void MergeDiveSites::redo()
// The dives of the above dive sites were reset to no dive sites. // The dives of the above dive sites were reset to no dive sites.
// Add them to the merged-into dive site. Thankfully, we remember // Add them to the merged-into dive site. Thankfully, we remember
// the dives in the sitesToAdd vector. // the dives in the sitesToAdd vector.
for (const OwningDiveSitePtr &site: sitesToAdd) { for (const std::unique_ptr<dive_site> &site: sitesToAdd) {
for (int i = 0; i < site->dives.nr; ++i) { for (int i = 0; i < site->dives.nr; ++i) {
add_dive_to_dive_site(site->dives.dives[i], ds); add_dive_to_dive_site(site->dives.dives[i], ds);
divesChanged.push_back(site->dives.dives[i]); divesChanged.push_back(site->dives.dives[i]);
@ -380,7 +377,7 @@ void MergeDiveSites::undo()
// Before readding the dive sites, unregister the corresponding dives so that they can be // Before readding the dive sites, unregister the corresponding dives so that they can be
// readded to their old dive sites. // readded to their old dive sites.
for (const OwningDiveSitePtr &site: sitesToAdd) { for (const std::unique_ptr<dive_site> &site: sitesToAdd) {
for (int i = 0; i < site->dives.nr; ++i) { for (int i = 0; i < site->dives.nr; ++i) {
unregister_dive_from_dive_site(site->dives.dives[i]); unregister_dive_from_dive_site(site->dives.dives[i]);
divesChanged.push_back(site->dives.dives[i]); divesChanged.push_back(site->dives.dives[i]);

View file

@ -31,7 +31,7 @@ private:
std::vector<dive_site *> sitesToRemove; std::vector<dive_site *> sitesToRemove;
// For redo // For redo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
}; };
class ImportDiveSites : public Base { class ImportDiveSites : public Base {
@ -47,7 +47,7 @@ private:
std::vector<dive_site *> sitesToRemove; std::vector<dive_site *> sitesToRemove;
// For redo // For redo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
}; };
class DeleteDiveSites : public Base { class DeleteDiveSites : public Base {
@ -62,7 +62,7 @@ private:
std::vector<dive_site *> sitesToRemove; std::vector<dive_site *> sitesToRemove;
// For undo // For undo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
}; };
class PurgeUnusedDiveSites : public Base { class PurgeUnusedDiveSites : public Base {
@ -77,7 +77,7 @@ private:
std::vector<dive_site *> sitesToRemove; std::vector<dive_site *> sitesToRemove;
// For undo // For undo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
}; };
class EditDiveSiteName : public Base { class EditDiveSiteName : public Base {
@ -125,7 +125,7 @@ private:
void redo() override; void redo() override;
dive_site *ds; dive_site *ds;
QString value; // Value to be set std::string value; // Value to be set
}; };
class EditDiveSiteLocation : public Base { class EditDiveSiteLocation : public Base {
@ -167,7 +167,7 @@ private:
std::vector<dive_site *> sitesToRemove; std::vector<dive_site *> sitesToRemove;
// For undo // For undo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
}; };
class ApplyGPSFixes : public Base { class ApplyGPSFixes : public Base {
@ -183,7 +183,7 @@ private:
std::vector<dive_site *> sitesToRemove; std::vector<dive_site *> sitesToRemove;
// For redo // For redo
std::vector<OwningDiveSitePtr> sitesToAdd; std::vector<std::unique_ptr<dive_site>> sitesToAdd;
// For redo and undo // For redo and undo
struct SiteAndLocation { struct SiteAndLocation {

View file

@ -376,7 +376,7 @@ void EditDiveSite::redo()
static struct dive_site *createDiveSite(const QString &name) static struct dive_site *createDiveSite(const QString &name)
{ {
struct dive_site *ds = alloc_dive_site(); struct dive_site *ds = new dive_site;
struct dive_site *old = current_dive ? current_dive->dive_site : nullptr; struct dive_site *old = current_dive ? current_dive->dive_site : nullptr;
if (old) { if (old) {
copy_dive_site(old, ds); copy_dive_site(old, ds);

View file

@ -208,7 +208,7 @@ public:
// deriving from it and hooks into undo() and redo() to add / remove the dive site. // deriving from it and hooks into undo() and redo() to add / remove the dive site.
class EditDiveSiteNew : public EditDiveSite { class EditDiveSiteNew : public EditDiveSite {
public: public:
OwningDiveSitePtr diveSiteToAdd; std::unique_ptr<dive_site> diveSiteToAdd;
struct dive_site *diveSiteToRemove; struct dive_site *diveSiteToRemove;
EditDiveSiteNew(const QString &newName, bool currentDiveOnly); EditDiveSiteNew(const QString &newName, bool currentDiveOnly);
void undo() override; void undo() override;
@ -470,7 +470,7 @@ private:
int changedFields; int changedFields;
dive_site *siteToRemove; dive_site *siteToRemove;
OwningDiveSitePtr siteToAdd; std::unique_ptr<dive_site> siteToAdd;
dive_site *siteToEdit; dive_site *siteToEdit;
location_t dsLocation; location_t dsLocation;

View file

@ -171,9 +171,8 @@ AddPictures::AddPictures(const std::vector<PictureListForAddition> &pictures) :
if (!ds) { if (!ds) {
// This dive doesn't yet have a dive site -> add a new dive site. // This dive doesn't yet have a dive site -> add a new dive site.
QString name = Command::Base::tr("unnamed dive site"); QString name = Command::Base::tr("unnamed dive site");
dive_site *ds = alloc_dive_site_with_gps(qPrintable(name), &it->location); sitesToAdd.push_back(std::make_unique<dive_site>(qPrintable(name), &it->location));
sitesToAdd.emplace_back(ds); sitesToSet.push_back({ p.d, sitesToAdd.back().get() });
sitesToSet.push_back({ p.d, ds });
} else if (!dive_site_has_gps_location(ds)) { } else if (!dive_site_has_gps_location(ds)) {
// This dive has a dive site, but without coordinates. Let's add them. // This dive has a dive site, but without coordinates. Let's add them.
sitesToEdit.push_back({ ds, it->location }); sitesToEdit.push_back({ ds, it->location });
@ -228,7 +227,7 @@ void AddPictures::undo()
void AddPictures::redo() void AddPictures::redo()
{ {
// Add dive sites // Add dive sites
for (OwningDiveSitePtr &siteToAdd: sitesToAdd) { for (std::unique_ptr<dive_site> &siteToAdd: sitesToAdd) {
sitesToRemove.push_back(siteToAdd.get()); sitesToRemove.push_back(siteToAdd.get());
int idx = register_dive_site(siteToAdd.release()); // Return ownership to backend. int idx = register_dive_site(siteToAdd.release()); // Return ownership to backend.
emit diveListNotifier.diveSiteAdded(sitesToRemove.back(), idx); // Inform frontend of new dive site. emit diveListNotifier.diveSiteAdded(sitesToRemove.back(), idx); // Inform frontend of new dive site.

View file

@ -48,7 +48,7 @@ private:
location_t location; location_t location;
}; };
std::vector<PictureListForAddition> picturesToAdd; // for redo std::vector<PictureListForAddition> picturesToAdd; // for redo
std::vector<OwningDiveSitePtr> sitesToAdd; //for redo std::vector<std::unique_ptr<dive_site>> sitesToAdd; //for redo
std::vector<PictureListForDeletion> picturesToRemove; // for undo std::vector<PictureListForDeletion> picturesToRemove; // for undo
std::vector<dive_site *> sitesToRemove; // for undo std::vector<dive_site *> sitesToRemove; // for undo
std::vector<DiveSiteEntry> sitesToSet; // for redo and undo std::vector<DiveSiteEntry> sitesToSet; // for redo and undo

View file

@ -179,7 +179,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
subsurfacesysinfo.h subsurfacesysinfo.h
tag.cpp tag.cpp
tag.h tag.h
taxonomy.c taxonomy.cpp
taxonomy.h taxonomy.h
time.cpp time.cpp
trip.c trip.c

View file

@ -3335,10 +3335,10 @@ extern "C" struct dive_site *get_dive_site_for_dive(const struct dive *dive)
return dive->dive_site; return dive->dive_site;
} }
extern "C" const char *get_dive_country(const struct dive *dive) std::string get_dive_country(const struct dive *dive)
{ {
struct dive_site *ds = dive->dive_site; struct dive_site *ds = dive->dive_site;
return ds ? taxonomy_get_country(&ds->taxonomy) : NULL; return ds ? taxonomy_get_country(ds->taxonomy) : std::string();
} }
extern "C" const char *get_dive_location(const struct dive *dive) extern "C" const char *get_dive_location(const struct dive *dive)

View file

@ -13,6 +13,7 @@
#include <stdlib.h> #include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
#include <string>
extern "C" { extern "C" {
#endif #endif
@ -114,7 +115,11 @@ extern depth_t gas_mnd(struct gasmix mix, depth_t end, const struct dive *dive,
extern struct dive *get_dive(int nr); extern struct dive *get_dive(int nr);
extern struct dive *get_dive_from_table(int nr, const struct dive_table *dt); extern struct dive *get_dive_from_table(int nr, const struct dive_table *dt);
extern struct dive_site *get_dive_site_for_dive(const struct dive *dive); extern struct dive_site *get_dive_site_for_dive(const struct dive *dive);
extern const char *get_dive_country(const struct dive *dive); #ifdef __cplusplus
} // TODO: remove
extern std::string get_dive_country(const struct dive *dive);
extern "C" {
#endif
extern const char *get_dive_location(const struct dive *dive); extern const char *get_dive_location(const struct dive *dive);
extern unsigned int number_of_computers(const struct dive *dive); extern unsigned int number_of_computers(const struct dive *dive);
extern struct divecomputer *get_dive_dc(struct dive *dive, int nr); extern struct divecomputer *get_dive_dc(struct dive *dive, int nr);
@ -227,7 +232,6 @@ extern void update_setpoint_events(const struct dive *dive, struct divecomputer
* QVariants and through QML. * QVariants and through QML.
*/ */
#include <QObject> #include <QObject>
#include <string>
Q_DECLARE_METATYPE(struct dive *); Q_DECLARE_METATYPE(struct dive *);
extern std::string existing_filename; extern std::string existing_filename;

View file

@ -1144,7 +1144,7 @@ void process_imported_dives(struct divelog *import_log, int flags,
if (j == import_log->dives->nr) { if (j == import_log->dives->nr) {
/* Dive site not even used - free it and go to next. */ /* Dive site not even used - free it and go to next. */
free_dive_site(new_ds); delete new_ds;
continue; continue;
} }
@ -1159,7 +1159,7 @@ void process_imported_dives(struct divelog *import_log, int flags,
if (import_log->dives->dives[j]->dive_site == new_ds) if (import_log->dives->dives[j]->dive_site == new_ds)
import_log->dives->dives[j]->dive_site = old_ds; import_log->dives->dives[j]->dive_site = old_ds;
} }
free_dive_site(new_ds); delete new_ds;
} }
import_log->sites->nr = 0; /* All dive sites were consumed */ import_log->sites->nr = 0; /* All dive sites were consumed */

View file

@ -3,11 +3,11 @@
#include "pref.h" #include "pref.h"
#include "gettextfromc.h" #include "gettextfromc.h"
QString constructLocationTags(struct taxonomy_data *taxonomy, bool for_maintab) QString constructLocationTags(taxonomy_data &taxonomy, bool for_maintab)
{ {
QString locationTag; QString locationTag;
if (!taxonomy->nr) if (taxonomy.empty())
return locationTag; return locationTag;
/* Check if the user set any of the 3 geocoding categories */ /* Check if the user set any of the 3 geocoding categories */
@ -33,11 +33,10 @@ QString constructLocationTags(struct taxonomy_data *taxonomy, bool for_maintab)
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (prefs.geocoding.category[i] == TC_NONE) if (prefs.geocoding.category[i] == TC_NONE)
continue; continue;
for (int j = 0; j < taxonomy->nr; j++) { for (auto const &t: taxonomy) {
if (taxonomy->category[j].category == prefs.geocoding.category[i]) { if (t.category == prefs.geocoding.category[i]) {
QString tag = taxonomy->category[j].value; if (!t.value.empty()) {
if (!tag.isEmpty()) { locationTag += connector + QString::fromStdString(t.value);
locationTag += connector + tag;
connector = " / "; connector = " / ";
} }
break; break;

View file

@ -12,7 +12,7 @@
#include <math.h> #include <math.h>
extern "C" int get_divesite_idx(const struct dive_site *ds, struct dive_site_table *ds_table) int get_divesite_idx(const struct dive_site *ds, struct dive_site_table *ds_table)
{ {
int i; int i;
const struct dive_site *d; const struct dive_site *d;
@ -26,7 +26,7 @@ extern "C" int get_divesite_idx(const struct dive_site *ds, struct dive_site_tab
} }
// TODO: keep table sorted by UUID and do a binary search? // TODO: keep table sorted by UUID and do a binary search?
extern "C" struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_site_table *ds_table) struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_site_table *ds_table)
{ {
int i; int i;
struct dive_site *ds; struct dive_site *ds;
@ -37,7 +37,7 @@ extern "C" struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_si
} }
/* there could be multiple sites of the same name - return the first one */ /* there could be multiple sites of the same name - return the first one */
extern "C" struct dive_site *get_dive_site_by_name(const char *name, struct dive_site_table *ds_table) struct dive_site *get_dive_site_by_name(const char *name, struct dive_site_table *ds_table)
{ {
int i; int i;
struct dive_site *ds; struct dive_site *ds;
@ -49,7 +49,7 @@ extern "C" struct dive_site *get_dive_site_by_name(const char *name, struct dive
} }
/* there could be multiple sites at the same GPS fix - return the first one */ /* there could be multiple sites at the same GPS fix - return the first one */
extern "C" struct dive_site *get_dive_site_by_gps(const location_t *loc, struct dive_site_table *ds_table) struct dive_site *get_dive_site_by_gps(const location_t *loc, struct dive_site_table *ds_table)
{ {
int i; int i;
struct dive_site *ds; struct dive_site *ds;
@ -63,7 +63,7 @@ extern "C" struct dive_site *get_dive_site_by_gps(const location_t *loc, struct
/* to avoid a bug where we have two dive sites with different name and the same GPS coordinates /* to avoid a bug where we have two dive sites with different name and the same GPS coordinates
* and first get the gps coordinates (reading a V2 file) and happen to get back "the other" name, * and first get the gps coordinates (reading a V2 file) and happen to get back "the other" name,
* this function allows us to verify if a very specific name/GPS combination already exists */ * this function allows us to verify if a very specific name/GPS combination already exists */
extern "C" struct dive_site *get_dive_site_by_gps_and_name(const char *name, const location_t *loc, struct dive_site_table *ds_table) struct dive_site *get_dive_site_by_gps_and_name(const char *name, const location_t *loc, struct dive_site_table *ds_table)
{ {
int i; int i;
struct dive_site *ds; struct dive_site *ds;
@ -75,7 +75,7 @@ extern "C" struct dive_site *get_dive_site_by_gps_and_name(const char *name, con
} }
// Calculate the distance in meters between two coordinates. // Calculate the distance in meters between two coordinates.
extern "C" unsigned int get_distance(const location_t *loc1, const location_t *loc2) unsigned int get_distance(const location_t *loc1, const location_t *loc2)
{ {
double lat1_r = udeg_to_radians(loc1->lat.udeg); double lat1_r = udeg_to_radians(loc1->lat.udeg);
double lat2_r = udeg_to_radians(loc2->lat.udeg); double lat2_r = udeg_to_radians(loc2->lat.udeg);
@ -93,7 +93,7 @@ extern "C" unsigned int get_distance(const location_t *loc1, const location_t *l
} }
/* find the closest one, no more than distance meters away - if more than one at same distance, pick the first */ /* find the closest one, no more than distance meters away - if more than one at same distance, pick the first */
extern "C" struct dive_site *get_dive_site_by_gps_proximity(const location_t *loc, int distance, struct dive_site_table *ds_table) struct dive_site *get_dive_site_by_gps_proximity(const location_t *loc, int distance, struct dive_site_table *ds_table)
{ {
int i; int i;
struct dive_site *ds, *res = NULL; struct dive_site *ds, *res = NULL;
@ -108,7 +108,7 @@ extern "C" struct dive_site *get_dive_site_by_gps_proximity(const location_t *lo
return res; return res;
} }
extern "C" int register_dive_site(struct dive_site *ds) int register_dive_site(struct dive_site *ds)
{ {
return add_dive_site_to_table(ds, divelog.sites); return add_dive_site_to_table(ds, divelog.sites);
} }
@ -123,6 +123,11 @@ static int site_less_than(const struct dive_site *a, const struct dive_site *b)
return compare_sites(a, b) < 0; return compare_sites(a, b) < 0;
} }
static void free_dive_site(struct dive_site *ds)
{
delete ds;
}
static MAKE_GROW_TABLE(dive_site_table, struct dive_site *, dive_sites) static MAKE_GROW_TABLE(dive_site_table, struct dive_site *, dive_sites)
static MAKE_GET_INSERTION_INDEX(dive_site_table, struct dive_site *, dive_sites, site_less_than) static MAKE_GET_INSERTION_INDEX(dive_site_table, struct dive_site *, dive_sites, site_less_than)
static MAKE_ADD_TO(dive_site_table, struct dive_site *, dive_sites) static MAKE_ADD_TO(dive_site_table, struct dive_site *, dive_sites)
@ -133,7 +138,7 @@ static MAKE_REMOVE(dive_site_table, struct dive_site *, dive_site)
MAKE_CLEAR_TABLE(dive_site_table, dive_sites, dive_site) MAKE_CLEAR_TABLE(dive_site_table, dive_sites, dive_site)
MAKE_MOVE_TABLE(dive_site_table, dive_sites) MAKE_MOVE_TABLE(dive_site_table, dive_sites)
extern "C" int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table) int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table)
{ {
/* If the site doesn't yet have an UUID, create a new one. /* If the site doesn't yet have an UUID, create a new one.
* Make this deterministic for testing. */ * Make this deterministic for testing. */
@ -158,35 +163,35 @@ extern "C" int add_dive_site_to_table(struct dive_site *ds, struct dive_site_tab
return idx; return idx;
} }
extern "C" struct dive_site *alloc_dive_site() dive_site::dive_site()
{ {
return (struct dive_site *)calloc(1, sizeof(struct dive_site));
} }
extern "C" struct dive_site *alloc_dive_site_with_name(const char *name) dive_site::dive_site(const char *name) : name(copy_string(name))
{ {
struct dive_site *ds = alloc_dive_site();
ds->name = copy_string(name);
return ds;
} }
extern "C" struct dive_site *alloc_dive_site_with_gps(const char *name, const location_t *loc) dive_site::dive_site(const char *name, const location_t *loc) : name(copy_string(name)), location(*loc)
{ {
struct dive_site *ds = alloc_dive_site_with_name(name); }
ds->location = *loc;
return ds; dive_site::~dive_site()
{
free(name);
free(notes);
free(description);
free(dives.dives);
} }
/* when parsing, dive sites are identified by uuid */ /* when parsing, dive sites are identified by uuid */
extern "C" struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table) struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table)
{ {
struct dive_site *ds; struct dive_site *ds;
if (uuid && (ds = get_dive_site_by_uuid(uuid, ds_table)) != NULL) if (uuid && (ds = get_dive_site_by_uuid(uuid, ds_table)) != NULL)
return ds; return ds;
ds = alloc_dive_site(); ds = new dive_site;
ds->uuid = uuid; ds->uuid = uuid;
add_dive_site_to_table(ds, ds_table); add_dive_site_to_table(ds, ds_table);
@ -194,12 +199,12 @@ extern "C" struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_s
return ds; return ds;
} }
extern "C" int nr_of_dives_at_dive_site(struct dive_site *ds) int nr_of_dives_at_dive_site(struct dive_site *ds)
{ {
return ds->dives.nr; return ds->dives.nr;
} }
extern "C" bool is_dive_site_selected(struct dive_site *ds) bool is_dive_site_selected(struct dive_site *ds)
{ {
int i; int i;
@ -210,49 +215,37 @@ extern "C" bool is_dive_site_selected(struct dive_site *ds)
return false; return false;
} }
extern "C" void free_dive_site(struct dive_site *ds) int unregister_dive_site(struct dive_site *ds)
{
if (ds) {
free(ds->name);
free(ds->notes);
free(ds->description);
free(ds->dives.dives);
free_taxonomy(&ds->taxonomy);
free(ds);
}
}
extern "C" int unregister_dive_site(struct dive_site *ds)
{ {
return remove_dive_site(ds, divelog.sites); return remove_dive_site(ds, divelog.sites);
} }
extern "C" 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) if (!ds)
return; return;
remove_dive_site(ds, ds_table); remove_dive_site(ds, ds_table);
free_dive_site(ds); delete ds;
} }
/* allocate a new site and add it to the table */ /* allocate a new site and add it to the table */
extern "C" struct dive_site *create_dive_site(const char *name, struct dive_site_table *ds_table) struct dive_site *create_dive_site(const char *name, struct dive_site_table *ds_table)
{ {
struct dive_site *ds = alloc_dive_site_with_name(name); struct dive_site *ds = new dive_site(name);
add_dive_site_to_table(ds, ds_table); add_dive_site_to_table(ds, ds_table);
return ds; return ds;
} }
/* same as before, but with GPS data */ /* same as before, but with GPS data */
extern "C" struct dive_site *create_dive_site_with_gps(const char *name, const location_t *loc, struct dive_site_table *ds_table) struct dive_site *create_dive_site_with_gps(const char *name, const location_t *loc, struct dive_site_table *ds_table)
{ {
struct dive_site *ds = alloc_dive_site_with_gps(name, loc); struct dive_site *ds = new dive_site(name, loc);
add_dive_site_to_table(ds, ds_table); add_dive_site_to_table(ds, ds_table);
return ds; return ds;
} }
/* if all fields are empty, the dive site is pointless */ /* if all fields are empty, the dive site is pointless */
extern "C" bool dive_site_is_empty(struct dive_site *ds) bool dive_site_is_empty(struct dive_site *ds)
{ {
return !ds || return !ds ||
(empty_string(ds->name) && (empty_string(ds->name) &&
@ -261,7 +254,7 @@ extern "C" bool dive_site_is_empty(struct dive_site *ds)
!has_location(&ds->location)); !has_location(&ds->location));
} }
extern "C" void copy_dive_site(struct dive_site *orig, struct dive_site *copy) void copy_dive_site(struct dive_site *orig, struct dive_site *copy)
{ {
free(copy->name); free(copy->name);
free(copy->notes); free(copy->notes);
@ -271,7 +264,7 @@ extern "C" void copy_dive_site(struct dive_site *orig, struct dive_site *copy)
copy->name = copy_string(orig->name); copy->name = copy_string(orig->name);
copy->notes = copy_string(orig->notes); copy->notes = copy_string(orig->notes);
copy->description = copy_string(orig->description); copy->description = copy_string(orig->description);
copy_taxonomy(&orig->taxonomy, &copy->taxonomy); copy->taxonomy = orig->taxonomy;
} }
static void merge_string(char **a, char **b) static void merge_string(char **a, char **b)
@ -307,7 +300,7 @@ static bool same_dive_site(const struct dive_site *a, const struct dive_site *b)
&& same_string(a->notes, b->notes); && same_string(a->notes, b->notes);
} }
extern "C" struct dive_site *get_same_dive_site(const struct dive_site *site) struct dive_site *get_same_dive_site(const struct dive_site *site)
{ {
int i; int i;
struct dive_site *ds; struct dive_site *ds;
@ -317,20 +310,18 @@ extern "C" struct dive_site *get_same_dive_site(const struct dive_site *site)
return NULL; return NULL;
} }
extern "C" void merge_dive_site(struct dive_site *a, struct dive_site *b) void merge_dive_site(struct dive_site *a, struct dive_site *b)
{ {
if (!has_location(&a->location)) a->location = b->location; if (!has_location(&a->location)) a->location = b->location;
merge_string(&a->name, &b->name); merge_string(&a->name, &b->name);
merge_string(&a->notes, &b->notes); merge_string(&a->notes, &b->notes);
merge_string(&a->description, &b->description); merge_string(&a->description, &b->description);
if (!a->taxonomy.category) { if (a->taxonomy.empty())
a->taxonomy = b->taxonomy; a->taxonomy = std::move(b->taxonomy);
memset(&b->taxonomy, 0, sizeof(b->taxonomy));
}
} }
extern "C" struct dive_site *find_or_create_dive_site_with_name(const char *name, struct dive_site_table *ds_table) struct dive_site *find_or_create_dive_site_with_name(const char *name, struct dive_site_table *ds_table)
{ {
int i; int i;
struct dive_site *ds; struct dive_site *ds;
@ -343,7 +334,7 @@ extern "C" struct dive_site *find_or_create_dive_site_with_name(const char *name
return create_dive_site(name, ds_table); return create_dive_site(name, ds_table);
} }
extern "C" void purge_empty_dive_sites(struct dive_site_table *ds_table) void purge_empty_dive_sites(struct dive_site_table *ds_table)
{ {
int i, j; int i, j;
struct dive *d; struct dive *d;
@ -360,7 +351,7 @@ extern "C" void purge_empty_dive_sites(struct dive_site_table *ds_table)
} }
} }
extern "C" void add_dive_to_dive_site(struct dive *d, struct dive_site *ds) void add_dive_to_dive_site(struct dive *d, struct dive_site *ds)
{ {
int idx; int idx;
if (!d) { if (!d) {
@ -382,7 +373,7 @@ extern "C" void add_dive_to_dive_site(struct dive *d, struct dive_site *ds)
d->dive_site = ds; d->dive_site = ds;
} }
extern "C" struct dive_site *unregister_dive_from_dive_site(struct dive *d) struct dive_site *unregister_dive_from_dive_site(struct dive *d)
{ {
struct dive_site *ds = d->dive_site; struct dive_site *ds = d->dive_site;
if (!ds) if (!ds)

View file

@ -10,20 +10,20 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <QString> #include <QString>
#include <QObject> #include <QObject>
extern "C" {
#else
#include <stdbool.h>
#endif
struct dive_site struct dive_site
{ {
uint32_t uuid; uint32_t uuid = 0;
char *name; char *name = nullptr;
struct dive_table dives; struct dive_table dives = { 0, 0, nullptr };
location_t location; location_t location = { { 9 }, { 0 } };
char *description; char *description = nullptr;
char *notes; char *notes = nullptr;
struct taxonomy_data taxonomy; taxonomy_data taxonomy;
dive_site();
dive_site(const char *name);
dive_site(const char *name, const location_t *loc);
~dive_site();
}; };
typedef struct dive_site_table { typedef struct dive_site_table {
@ -50,11 +50,8 @@ void sort_dive_site_table(struct dive_site_table *ds_table);
int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table); int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table);
struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table); struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table);
struct dive_site *alloc_dive_site(); struct dive_site *alloc_dive_site();
struct dive_site *alloc_dive_site_with_name(const char *name);
struct dive_site *alloc_dive_site_with_gps(const char *name, const location_t *loc);
int nr_of_dives_at_dive_site(struct dive_site *ds); int nr_of_dives_at_dive_site(struct dive_site *ds);
bool is_dive_site_selected(struct dive_site *ds); bool is_dive_site_selected(struct dive_site *ds);
void free_dive_site(struct dive_site *ds);
int unregister_dive_site(struct dive_site *ds); int unregister_dive_site(struct dive_site *ds);
int register_dive_site(struct dive_site *ds); int register_dive_site(struct dive_site *ds);
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);
@ -77,9 +74,7 @@ void move_dive_site_table(struct dive_site_table *src, struct dive_site_table *d
void add_dive_to_dive_site(struct dive *d, struct dive_site *ds); void add_dive_to_dive_site(struct dive *d, struct dive_site *ds);
struct dive_site *unregister_dive_from_dive_site(struct dive *d); struct dive_site *unregister_dive_from_dive_site(struct dive *d);
#ifdef __cplusplus QString constructLocationTags(taxonomy_data &taxonomy, bool for_maintab);
}
QString constructLocationTags(struct taxonomy_data *taxonomy, bool for_maintab);
/* Make pointer-to-dive_site a "Qt metatype" so that we can pass it through QVariants */ /* Make pointer-to-dive_site a "Qt metatype" so that we can pass it through QVariants */
Q_DECLARE_METATYPE(dive_site *); Q_DECLARE_METATYPE(dive_site *);

View file

@ -84,14 +84,14 @@ taxonomy_data reverseGeoLookup(degrees_t latitude, degrees_t longitude)
QString url; QString url;
QJsonObject obj; QJsonObject obj;
taxonomy_data taxonomy = { 0, 0 }; taxonomy_data taxonomy;
// check the oceans API to figure out the body of water // check the oceans API to figure out the body of water
url = geonamesOceanURL.arg(getUiLanguage().section(QRegularExpression("[-_ ]"), 0, 0)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0); url = geonamesOceanURL.arg(getUiLanguage().section(QRegularExpression("[-_ ]"), 0, 0)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0);
obj = doAsyncRESTGetRequest(url, 5000); // 5 secs. timeout obj = doAsyncRESTGetRequest(url, 5000); // 5 secs. timeout
QVariantMap oceanName = obj.value("ocean").toVariant().toMap(); QVariantMap oceanName = obj.value("ocean").toVariant().toMap();
if (oceanName["name"].isValid()) if (oceanName["name"].isValid())
taxonomy_set_category(&taxonomy, TC_OCEAN, qPrintable(oceanName["name"].toString()), taxonomy_origin::GEOCODED); taxonomy_set_category(taxonomy, TC_OCEAN, oceanName["name"].toString().toStdString(), taxonomy_origin::GEOCODED);
// check the findNearbyPlaces API from geonames - that should give us country, state, city // check the findNearbyPlaces API from geonames - that should give us country, state, city
url = geonamesNearbyPlaceNameURL.arg(getUiLanguage().section(QRegularExpression("[-_ ]"), 0, 0)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0); url = geonamesNearbyPlaceNameURL.arg(getUiLanguage().section(QRegularExpression("[-_ ]"), 0, 0)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0);
@ -110,16 +110,16 @@ taxonomy_data reverseGeoLookup(degrees_t latitude, degrees_t longitude)
for (int idx = TC_COUNTRY; idx < TC_NR_CATEGORIES; idx++) { for (int idx = TC_COUNTRY; idx < TC_NR_CATEGORIES; idx++) {
if (firstData[taxonomy_api_names[idx]].isValid()) { if (firstData[taxonomy_api_names[idx]].isValid()) {
QString value = firstData[taxonomy_api_names[idx]].toString(); QString value = firstData[taxonomy_api_names[idx]].toString();
taxonomy_set_category(&taxonomy, (taxonomy_category)idx, qPrintable(value), taxonomy_origin::GEOCODED); taxonomy_set_category(taxonomy, (taxonomy_category)idx, value.toStdString(), taxonomy_origin::GEOCODED);
} }
} }
const char *l3 = taxonomy_get_value(&taxonomy, TC_ADMIN_L3); std::string l3 = taxonomy_get_value(taxonomy, TC_ADMIN_L3);
const char *lt = taxonomy_get_value(&taxonomy, TC_LOCALNAME); std::string lt = taxonomy_get_value(taxonomy, TC_LOCALNAME);
if (empty_string(l3) && !empty_string(lt)) { if (!l3.empty() && !lt.empty()) {
// basically this means we did get a local name (what we call town), but just like most places // basically this means we did get a local name (what we call town), but just like most places
// we didn't get an adminName_3 - which in some regions is the actual city that town belongs to, // we didn't get an adminName_3 - which in some regions is the actual city that town belongs to,
// then we copy the town into the city // then we copy the town into the city
taxonomy_set_category(&taxonomy, TC_ADMIN_L3, lt, taxonomy_origin::GEOCOPIED); taxonomy_set_category(taxonomy, TC_ADMIN_L3, lt, taxonomy_origin::GEOCOPIED);
} }
} else { } else {
report_error("geonames.org did not provide reverse lookup information"); report_error("geonames.org did not provide reverse lookup information");

View file

@ -141,9 +141,9 @@ static std::vector<QString> getWords(const dive *d)
// take the tokens from a cache. // take the tokens from a cache.
if (d->dive_site) { if (d->dive_site) {
tokenize(d->dive_site->name, res); tokenize(d->dive_site->name, res);
const char *country = taxonomy_get_country(&d->dive_site->taxonomy); std::string country = taxonomy_get_country(d->dive_site->taxonomy);
if (country) if (!country.empty())
tokenize(country, res); tokenize(country.c_str(), res);
} }
// TODO: We should index trips separately! // TODO: We should index trips separately!
if (d->divetrip) if (d->divetrip)

View file

@ -332,8 +332,8 @@ static void parse_site_geo(char *line, struct git_parser_state *state)
int origin; int origin;
int category; int category;
sscanf(line, "cat %d origin %d \"", &category, &origin); sscanf(line, "cat %d origin %d \"", &category, &origin);
taxonomy_set_category(&state->active_site->taxonomy, (taxonomy_category)category, taxonomy_set_category(state->active_site->taxonomy, (taxonomy_category)category,
get_first_converted_string(state).c_str(), (taxonomy_origin)origin); get_first_converted_string(state), (taxonomy_origin)origin);
} }
static std::string pop_cstring(struct git_parser_state *state, const char *err) static std::string pop_cstring(struct git_parser_state *state, const char *err)

View file

@ -16,7 +16,6 @@ struct event;
extern "C" void free_dive(struct dive *); extern "C" void free_dive(struct dive *);
extern "C" void free_trip(struct dive_trip *); extern "C" void free_trip(struct dive_trip *);
extern "C" void free_dive_site(struct dive_site *);
// Classes used to automatically call the appropriate free_*() function for owning pointers that go out of scope. // Classes used to automatically call the appropriate free_*() function for owning pointers that go out of scope.
struct DiveDeleter { struct DiveDeleter {
@ -25,9 +24,6 @@ struct DiveDeleter {
struct TripDeleter { struct TripDeleter {
void operator()(dive_trip *t) { free_trip(t); } void operator()(dive_trip *t) { free_trip(t); }
}; };
struct DiveSiteDeleter {
void operator()(dive_site *ds) { free_dive_site(ds); }
};
struct EventDeleter { struct EventDeleter {
void operator()(event *ev) { free(ev); } void operator()(event *ev) { free(ev); }
}; };
@ -35,7 +31,6 @@ struct EventDeleter {
// Owning pointers to dive, dive_trip, dive_site and event objects. // Owning pointers to dive, dive_trip, dive_site and event objects.
using OwningDivePtr = std::unique_ptr<dive, DiveDeleter>; using OwningDivePtr = std::unique_ptr<dive, DiveDeleter>;
using OwningTripPtr = std::unique_ptr<dive_trip, TripDeleter>; using OwningTripPtr = std::unique_ptr<dive_trip, TripDeleter>;
using OwningDiveSitePtr = std::unique_ptr<dive_site, DiveSiteDeleter>;
using OwningEventPtr = std::unique_ptr<event, EventDeleter>; using OwningEventPtr = std::unique_ptr<event, EventDeleter>;
#endif #endif

View file

@ -1410,7 +1410,7 @@ static void try_to_fill_trip(dive_trip_t *dive_trip, const char *name, char *buf
/* We're processing a divesite entry - try to fill the components */ /* We're processing a divesite entry - try to fill the components */
static void try_to_fill_dive_site(struct parser_state *state, const char *name, char *buf) static void try_to_fill_dive_site(struct parser_state *state, const char *name, char *buf)
{ {
struct dive_site *ds = state->cur_dive_site; auto &ds = state->cur_dive_site;
std::string taxonomy_value; std::string taxonomy_value;
start_match("divesite", name, buf); start_match("divesite", name, buf);
@ -1423,7 +1423,7 @@ static void try_to_fill_dive_site(struct parser_state *state, const char *name,
return; return;
if (MATCH("notes", utf8_string, &ds->notes)) if (MATCH("notes", utf8_string, &ds->notes))
return; return;
if (MATCH("gps", gps_location, ds)) if (MATCH("gps", gps_location, ds.get()))
return; return;
if (MATCH("cat.geo", get_index, &state->taxonomy_category)) if (MATCH("cat.geo", get_index, &state->taxonomy_category))
return; return;
@ -1436,8 +1436,8 @@ static void try_to_fill_dive_site(struct parser_state *state, const char *name,
if (state->taxonomy_category < 0 || state->taxonomy_origin < 0) { if (state->taxonomy_category < 0 || state->taxonomy_origin < 0) {
report_error("Warning: taxonomy value without origin or category"); report_error("Warning: taxonomy value without origin or category");
} else { } else {
taxonomy_set_category(&ds->taxonomy, (taxonomy_category)state->taxonomy_category, taxonomy_set_category(ds->taxonomy, (taxonomy_category)state->taxonomy_category,
taxonomy_value.c_str(), (taxonomy_origin)state->taxonomy_origin); taxonomy_value, (taxonomy_origin)state->taxonomy_origin);
} }
state->taxonomy_category = state->taxonomy_origin = -1; state->taxonomy_category = state->taxonomy_origin = -1;
return; return;

View file

@ -19,11 +19,14 @@
#include "device.h" #include "device.h"
#include "gettext.h" #include "gettext.h"
parser_state::parser_state()
{
}
parser_state::~parser_state() parser_state::~parser_state()
{ {
free_dive(cur_dive); free_dive(cur_dive);
free_trip(cur_trip); free_trip(cur_trip);
free_dive_site(cur_dive_site);
} }
/* /*
@ -188,7 +191,7 @@ void dive_site_start(struct parser_state *state)
return; return;
state->taxonomy_category = -1; state->taxonomy_category = -1;
state->taxonomy_origin = -1; state->taxonomy_origin = -1;
state->cur_dive_site = (dive_site *)calloc(1, sizeof(struct dive_site)); state->cur_dive_site = std::make_unique<dive_site>();
} }
void dive_site_end(struct parser_state *state) void dive_site_end(struct parser_state *state)
@ -197,13 +200,12 @@ void dive_site_end(struct parser_state *state)
return; return;
struct dive_site *ds = alloc_or_get_dive_site(state->cur_dive_site->uuid, state->log->sites); struct dive_site *ds = alloc_or_get_dive_site(state->cur_dive_site->uuid, state->log->sites);
merge_dive_site(ds, state->cur_dive_site); merge_dive_site(ds, state->cur_dive_site.get());
if (verbose > 3) if (verbose > 3)
printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name); printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name);
free_dive_site(state->cur_dive_site); state->cur_dive_site.reset();
state->cur_dive_site = NULL;
} }
void filter_preset_start(struct parser_state *state) void filter_preset_start(struct parser_state *state)

View file

@ -64,7 +64,7 @@ struct parser_state {
struct divecomputer *cur_dc = nullptr; /* non-owning */ struct divecomputer *cur_dc = nullptr; /* non-owning */
struct dive *cur_dive = nullptr; /* owning */ struct dive *cur_dive = nullptr; /* owning */
struct dive_site *cur_dive_site = nullptr; /* owning */ std::unique_ptr<dive_site> cur_dive_site; /* owning */
location_t cur_location { 0 }; location_t cur_location { 0 };
struct dive_trip *cur_trip = nullptr; /* owning */ struct dive_trip *cur_trip = nullptr; /* owning */
struct sample *cur_sample = nullptr; /* non-owning */ struct sample *cur_sample = nullptr; /* non-owning */
@ -96,6 +96,7 @@ struct parser_state {
sqlite3 *sql_handle = nullptr; /* for SQL based parsers */ sqlite3 *sql_handle = nullptr; /* for SQL based parsers */
bool event_active = false; bool event_active = false;
event_allocation_t event_allocation; event_allocation_t event_allocation;
parser_state();
~parser_state(); ~parser_state();
}; };

View file

@ -2,15 +2,15 @@
#ifndef PREF_H #ifndef PREF_H
#define PREF_H #define PREF_H
#include "units.h"
#include "taxonomy.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#else #else
#include <stdbool.h> #include <stdbool.h>
#endif #endif
#include "units.h"
#include "taxonomy.h"
typedef struct typedef struct
{ {
bool po2; bool po2;

View file

@ -933,11 +933,10 @@ static void save_divesites(git_repository *repo, struct dir *tree)
show_utf8(&b, "description ", ds->description, "\n"); show_utf8(&b, "description ", ds->description, "\n");
show_utf8(&b, "notes ", ds->notes, "\n"); show_utf8(&b, "notes ", ds->notes, "\n");
put_location(&b, &ds->location, "gps ", "\n"); put_location(&b, &ds->location, "gps ", "\n");
for (int j = 0; j < ds->taxonomy.nr; j++) { for (const auto &t: ds->taxonomy) {
struct taxonomy *t = &ds->taxonomy.category[j]; if (t.category != TC_NONE && !t.value.empty()) {
if (t->category != TC_NONE && t->value) { put_format(&b, "geo cat %d origin %d ", t.category, t.origin);
put_format(&b, "geo cat %d origin %d ", t->category, t->origin); show_utf8(&b, "", t.value.c_str(), "\n" );
show_utf8(&b, "", t->value, "\n" );
} }
} }
blob_insert(repo, subdir, &b, mb_cstring(&site_file_name)); blob_insert(repo, subdir, &b, mb_cstring(&site_file_name));

View file

@ -716,17 +716,14 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym
show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize); show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize);
put_format(b, ">\n"); put_format(b, ">\n");
show_utf8_blanked(b, ds->notes, " <notes>", " </notes>\n", 0, anonymize); show_utf8_blanked(b, ds->notes, " <notes>", " </notes>\n", 0, anonymize);
if (ds->taxonomy.nr) { for (auto const &t: ds->taxonomy) {
for (int j = 0; j < ds->taxonomy.nr; j++) { if (t.category != TC_NONE && !t.value.empty()) {
struct taxonomy *t = &ds->taxonomy.category[j]; put_format(b, " <geo cat='%d'", t.category);
if (t->category != TC_NONE && t->value) { put_format(b, " origin='%d'", t.origin);
put_format(b, " <geo cat='%d'", t->category); show_utf8_blanked(b, t.value.c_str(), " value='", "'", 1, anonymize);
put_format(b, " origin='%d'", t->origin);
show_utf8_blanked(b, t->value, " value='", "'", 1, anonymize);
put_format(b, "/>\n"); put_format(b, "/>\n");
} }
} }
}
put_format(b, "</site>\n"); put_format(b, "</site>\n");
} }
put_format(b, "</divesites>\n<dives>\n"); put_format(b, "</divesites>\n<dives>\n");
@ -921,17 +918,14 @@ static void save_dive_sites_buffer(struct membuffer *b, const struct dive_site *
show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize); show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize);
put_format(b, ">\n"); put_format(b, ">\n");
show_utf8_blanked(b, ds->notes, " <notes>", " </notes>\n", 0, anonymize); show_utf8_blanked(b, ds->notes, " <notes>", " </notes>\n", 0, anonymize);
if (ds->taxonomy.nr) { for (const auto &t: ds->taxonomy) {
for (int j = 0; j < ds->taxonomy.nr; j++) { if (t.category != TC_NONE && !t.value.empty()) {
struct taxonomy *t = &ds->taxonomy.category[j]; put_format(b, " <geo cat='%d'", t.category);
if (t->category != TC_NONE && t->value) { put_format(b, " origin='%d'", t.origin);
put_format(b, " <geo cat='%d'", t->category); show_utf8_blanked(b, t.value.c_str(), " value='", "'", 1, anonymize);
put_format(b, " origin='%d'", t->origin);
show_utf8_blanked(b, t->value, " value='", "'", 1, anonymize);
put_format(b, "/>\n"); put_format(b, "/>\n");
} }
} }
}
put_format(b, "</site>\n"); put_format(b, "</site>\n");
} }
put_format(b, "</divesites>\n"); put_format(b, "</divesites>\n");

View file

@ -133,6 +133,12 @@ static void addStringToSortedList(QStringList &l, const std::string &s)
l.insert(it, qs); l.insert(it, qs);
} }
// Safely treat null-strings. Remove once everyhting is converted to std::string
static std::string c_to_std(const char *s)
{
return s ? std::string(s) : std::string();
}
QStringList formatFullCylinderList() QStringList formatFullCylinderList()
{ {
QStringList cylinders; QStringList cylinders;
@ -140,7 +146,7 @@ QStringList formatFullCylinderList()
int i = 0; int i = 0;
for_each_dive (i, d) { for_each_dive (i, d) {
for (int j = 0; j < d->cylinders.nr; j++) for (int j = 0; j < d->cylinders.nr; j++)
addStringToSortedList(cylinders, get_cylinder(d, j)->type.description); addStringToSortedList(cylinders, c_to_std(get_cylinder(d, j)->type.description));
} }
for (const auto &ti: tank_info_table) for (const auto &ti: tank_info_table)

View file

@ -1,111 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "taxonomy.h"
#include "gettext.h"
#include "subsurface-string.h"
#include <stdlib.h>
#include <stdio.h>
char *taxonomy_category_names[TC_NR_CATEGORIES] = {
QT_TRANSLATE_NOOP("gettextFromC", "None"),
QT_TRANSLATE_NOOP("gettextFromC", "Ocean"),
QT_TRANSLATE_NOOP("gettextFromC", "Country"),
QT_TRANSLATE_NOOP("gettextFromC", "State"),
QT_TRANSLATE_NOOP("gettextFromC", "County"),
QT_TRANSLATE_NOOP("gettextFromC", "Town"),
QT_TRANSLATE_NOOP("gettextFromC", "City")
};
// these are the names for geoname.org
char *taxonomy_api_names[TC_NR_CATEGORIES] = {
"none",
"name",
"countryName",
"adminName1",
"adminName2",
"toponymName",
"adminName3"
};
static void alloc_taxonomy_table(struct taxonomy_data *t)
{
if (!t->category)
t->category = calloc(TC_NR_CATEGORIES, sizeof(struct taxonomy));
}
void free_taxonomy(struct taxonomy_data *t)
{
if (t) {
for (int i = 0; i < t->nr; i++)
free((void *)t->category[i].value);
free(t->category);
t->category = NULL;
t->nr = 0;
}
}
void copy_taxonomy(const struct taxonomy_data *orig, struct taxonomy_data *copy)
{
if (orig->category == NULL) {
free_taxonomy(copy);
} else {
alloc_taxonomy_table(copy);
for (int i = 0; i < TC_NR_CATEGORIES; i++) {
if (i < copy->nr) {
free((void *)copy->category[i].value);
copy->category[i].value = NULL;
}
if (i < orig->nr) {
copy->category[i] = orig->category[i];
copy->category[i].value = copy_string(orig->category[i].value);
}
}
copy->nr = orig->nr;
}
}
static int taxonomy_index_for_category(const struct taxonomy_data *t, enum taxonomy_category cat)
{
for (int i = 0; i < t->nr; i++) {
if (t->category[i].category == cat)
return i;
}
return -1;
}
const char *taxonomy_get_value(const struct taxonomy_data *t, enum taxonomy_category cat)
{
int idx = taxonomy_index_for_category(t, cat);
return idx >= 0 ? t->category[idx].value : NULL;
}
const char *taxonomy_get_country(const struct taxonomy_data *t)
{
return taxonomy_get_value(t, TC_COUNTRY);
}
void taxonomy_set_category(struct taxonomy_data *t, enum taxonomy_category category, const char *value, enum taxonomy_origin origin)
{
int idx = taxonomy_index_for_category(t, category);
if (idx < 0) {
alloc_taxonomy_table(t); // make sure we have taxonomy data allocated
if (t->nr == TC_NR_CATEGORIES - 1) {
// can't add another one
fprintf(stderr, "Error adding taxonomy category\n");
return;
}
idx = t->nr++;
} else {
free((void *)t->category[idx].value);
t->category[idx].value = NULL;
}
t->category[idx].value = strdup(value);
t->category[idx].origin = origin;
t->category[idx].category = category;
}
void taxonomy_set_country(struct taxonomy_data *t, const char *country, enum taxonomy_origin origin)
{
fprintf(stderr, "%s: set the taxonomy country to %s\n", __func__, country);
taxonomy_set_category(t, TC_COUNTRY, country, origin);
}

59
core/taxonomy.cpp Normal file
View file

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0
#include "taxonomy.h"
#include "errorhelper.h"
#include "gettext.h"
#include "subsurface-string.h"
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <QtGlobal> // for QT_TRANSLATE_NOOP
const char *taxonomy_category_names[TC_NR_CATEGORIES] = {
QT_TRANSLATE_NOOP("gettextFromC", "None"),
QT_TRANSLATE_NOOP("gettextFromC", "Ocean"),
QT_TRANSLATE_NOOP("gettextFromC", "Country"),
QT_TRANSLATE_NOOP("gettextFromC", "State"),
QT_TRANSLATE_NOOP("gettextFromC", "County"),
QT_TRANSLATE_NOOP("gettextFromC", "Town"),
QT_TRANSLATE_NOOP("gettextFromC", "City")
};
// these are the names for geoname.org
const char *taxonomy_api_names[TC_NR_CATEGORIES] = {
"none",
"name",
"countryName",
"adminName1",
"adminName2",
"toponymName",
"adminName3"
};
std::string taxonomy_get_value(const taxonomy_data &t, enum taxonomy_category cat)
{
auto it = std::find_if(t.begin(), t.end(), [cat] (const taxonomy &tax) { return tax.category == cat; });
return it != t.end() ? it->value : std::string();
}
std::string taxonomy_get_country(const taxonomy_data &t)
{
return taxonomy_get_value(t, TC_COUNTRY);
}
void taxonomy_set_category(taxonomy_data &t, enum taxonomy_category cat, const std::string &value, enum taxonomy_origin origin)
{
auto it = std::find_if(t.begin(), t.end(), [cat] (const taxonomy &tax) { return tax.category == cat; });
if (it == t.end()) {
t.emplace_back();
it = std::prev(t.end());
}
it->value = value;
it->origin = origin;
it->category = cat;
}
void taxonomy_set_country(taxonomy_data &t, const std::string &country, enum taxonomy_origin origin)
{
report_info("%s: set the taxonomy country to %s\n", __func__, country.c_str());
taxonomy_set_category(t, TC_COUNTRY, country, origin);
}

View file

@ -3,8 +3,9 @@
#define TAXONOMY_H #define TAXONOMY_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" {
#endif #include <string>
#include <vector>
enum taxonomy_category { enum taxonomy_category {
TC_NONE, TC_NONE,
@ -24,29 +25,22 @@ enum taxonomy_origin {
GEOCOPIED GEOCOPIED
}; };
extern char *taxonomy_category_names[TC_NR_CATEGORIES]; extern const char *taxonomy_category_names[TC_NR_CATEGORIES];
extern char *taxonomy_api_names[TC_NR_CATEGORIES]; extern const char *taxonomy_api_names[TC_NR_CATEGORIES];
struct taxonomy { struct taxonomy {
int category; /* the category for this tag: ocean, country, admin_l1, admin_l2, localname, etc */ taxonomy_category category; /* the category for this tag: ocean, country, admin_l1, admin_l2, localname, etc */
const char *value; /* the value returned, parsed, or manually entered for that category */ std::string value; /* the value returned, parsed, or manually entered for that category */
enum taxonomy_origin origin; taxonomy_origin origin;
}; };
/* the data block contains 3 taxonomy structures - unused ones have a tag value of NONE */ /* the data block contains taxonomy structures - unused ones have a tag value of NONE */
struct taxonomy_data { using taxonomy_data = std::vector<taxonomy>;
int nr;
struct taxonomy *category;
};
void free_taxonomy(struct taxonomy_data *t); std::string taxonomy_get_value(const taxonomy_data &t, enum taxonomy_category cat);
void copy_taxonomy(const struct taxonomy_data *orig, struct taxonomy_data *copy); std::string taxonomy_get_country(const taxonomy_data &t);
const char *taxonomy_get_value(const struct taxonomy_data *t, enum taxonomy_category cat); void taxonomy_set_category(taxonomy_data &t, enum taxonomy_category category, const std::string &value, enum taxonomy_origin origin);
const char *taxonomy_get_country(const struct taxonomy_data *t); void taxonomy_set_country(taxonomy_data &t, const std::string &country, enum taxonomy_origin origin);
void taxonomy_set_category(struct taxonomy_data *t, enum taxonomy_category category, const char *value, enum taxonomy_origin origin);
void taxonomy_set_country(struct taxonomy_data *t, const char *country, enum taxonomy_origin origin);
#ifdef __cplusplus
}
#endif #endif
#endif // TAXONOMY_H #endif // TAXONOMY_H

View file

@ -116,13 +116,14 @@ bool uploadDiveLogsDE::prepareDives(const QString &tempfile, bool selected)
put_format(&mb, "'"); put_format(&mb, "'");
put_location(&mb, &ds->location, " gps='", "'"); put_location(&mb, &ds->location, " gps='", "'");
put_format(&mb, ">\n"); put_format(&mb, ">\n");
if (ds->taxonomy.nr) { for (int i = 0; i < 3; i++) {
for (int j = 0; j < ds->taxonomy.nr; j++) { if (prefs.geocoding.category[i] == TC_NONE)
struct taxonomy *t = &ds->taxonomy.category[j]; continue;
if (t->category != TC_NONE && t->category == prefs.geocoding.category[j] && t->value) { for (auto const &t: ds->taxonomy) {
put_format(&mb, " <geo cat='%d'", t->category); if (t.category == prefs.geocoding.category[i] && !t.value.empty()) {
put_format(&mb, " origin='%d' value='", t->origin); put_format(&mb, " <geo cat='%d'", t.category);
put_quoted(&mb, t->value, 1, 0); put_format(&mb, " origin='%d' value='", t.origin);
put_quoted(&mb, t.value.c_str(), 1, 0);
put_format(&mb, "'/>\n"); put_format(&mb, "'/>\n");
} }
} }

View file

@ -67,7 +67,7 @@ void DivesiteImportDialog::on_ok_clicked()
struct dive_site_table selectedSites = empty_dive_site_table; struct dive_site_table selectedSites = empty_dive_site_table;
for (int i = 0; i < importedSites.nr; i++) for (int i = 0; i < importedSites.nr; i++)
if (divesiteImportedModel->data(divesiteImportedModel->index(i, 0), Qt::CheckStateRole) == Qt::Checked) { if (divesiteImportedModel->data(divesiteImportedModel->index(i, 0), Qt::CheckStateRole) == Qt::Checked) {
struct dive_site *newSite = alloc_dive_site(); struct dive_site *newSite = new dive_site;
copy_dive_site(importedSites.dive_sites[i], newSite); copy_dive_site(importedSites.dive_sites[i], newSite);
add_dive_site_to_table(newSite, &selectedSites); add_dive_site_to_table(newSite, &selectedSites);
} }

View file

@ -133,9 +133,9 @@ void LocationInformationWidget::updateLabels()
ui.diveSiteName->setText(diveSite->name); ui.diveSiteName->setText(diveSite->name);
else else
ui.diveSiteName->clear(); ui.diveSiteName->clear();
const char *country = taxonomy_get_country(&diveSite->taxonomy); std::string country = taxonomy_get_country(diveSite->taxonomy);
if (country) if (!country.empty())
ui.diveSiteCountry->setText(country); ui.diveSiteCountry->setText(QString::fromStdString(country));
else else
ui.diveSiteCountry->clear(); ui.diveSiteCountry->clear();
if (diveSite->description) if (diveSite->description)
@ -152,7 +152,7 @@ void LocationInformationWidget::updateLabels()
ui.diveSiteCoordinates->clear(); ui.diveSiteCoordinates->clear();
coordinatesSetWarning(false); coordinatesSetWarning(false);
ui.locationTags->setText(constructLocationTags(&diveSite->taxonomy, false)); ui.locationTags->setText(constructLocationTags(diveSite->taxonomy, false));
} }
void LocationInformationWidget::unitsChanged() void LocationInformationWidget::unitsChanged()
@ -181,8 +181,8 @@ void LocationInformationWidget::diveSiteChanged(struct dive_site *ds, int field)
ui.diveSiteNotes->setText(diveSite->notes); ui.diveSiteNotes->setText(diveSite->notes);
return; return;
case LocationInformationModel::TAXONOMY: case LocationInformationModel::TAXONOMY:
ui.diveSiteCountry->setText(taxonomy_get_country(&diveSite->taxonomy)); ui.diveSiteCountry->setText(QString::fromStdString(taxonomy_get_country(diveSite->taxonomy)));
ui.locationTags->setText(constructLocationTags(&diveSite->taxonomy, false)); ui.locationTags->setText(constructLocationTags(diveSite->taxonomy, false));
return; return;
case LocationInformationModel::LOCATION: case LocationInformationModel::LOCATION:
filter_model.setCoordinates(diveSite->location); filter_model.setCoordinates(diveSite->location);
@ -342,10 +342,8 @@ void LocationInformationWidget::reverseGeocode()
if (!ds || !has_location(&location)) if (!ds || !has_location(&location))
return; return;
taxonomy_data taxonomy = reverseGeoLookup(location.lat, location.lon); taxonomy_data taxonomy = reverseGeoLookup(location.lat, location.lon);
if (ds != diveSite) { if (ds != diveSite)
free_taxonomy(&taxonomy);
return; return;
}
// This call transfers ownership of the taxonomy memory into an EditDiveSiteTaxonomy object // This call transfers ownership of the taxonomy memory into an EditDiveSiteTaxonomy object
Command::editDiveSiteTaxonomy(ds, taxonomy); Command::editDiveSiteTaxonomy(ds, taxonomy);
} }

View file

@ -461,12 +461,12 @@ void LocationFilterDelegate::paint(QPainter *painter, const QStyleOptionViewItem
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (prefs.geocoding.category[i] == TC_NONE) if (prefs.geocoding.category[i] == TC_NONE)
continue; continue;
const char *value = taxonomy_get_value(&ds->taxonomy, prefs.geocoding.category[i]); std::string value = taxonomy_get_value(ds->taxonomy, prefs.geocoding.category[i]);
if (empty_string(value)) if (!value.empty())
continue; continue;
if(!bottomText.isEmpty()) if(!bottomText.isEmpty())
bottomText += " / "; bottomText += " / ";
bottomText += QString(value); bottomText += QString::fromStdString(value);
} }
if (bottomText.isEmpty()) if (bottomText.isEmpty())

View file

@ -178,7 +178,7 @@ void TabDiveNotes::updateDiveSite(struct dive *d)
struct dive_site *ds = d->dive_site; struct dive_site *ds = d->dive_site;
ui.location->setCurrentDiveSite(d); ui.location->setCurrentDiveSite(d);
if (ds) { if (ds) {
ui.locationTags->setText(constructLocationTags(&ds->taxonomy, true)); ui.locationTags->setText(constructLocationTags(ds->taxonomy, true));
if (ui.locationTags->text().isEmpty() && has_location(&ds->location)) if (ui.locationTags->text().isEmpty() && has_location(&ds->location))
ui.locationTags->setText(printGPSCoords(&ds->location)); ui.locationTags->setText(printGPSCoords(&ds->location));

View file

@ -908,7 +908,7 @@ void QMLManager::refreshDiveList()
// The following structure describes such a change caused by a dive edit. // The following structure describes such a change caused by a dive edit.
// Hopefully, we can remove this in due course by using finer-grained undo-commands. // Hopefully, we can remove this in due course by using finer-grained undo-commands.
struct DiveSiteChange { struct DiveSiteChange {
OwningDiveSitePtr createdDs; // not-null if we created a dive site. std::unique_ptr<dive_site> createdDs; // not-null if we created a dive site.
dive_site *editDs = nullptr; // not-null if we are supposed to edit an existing dive site. dive_site *editDs = nullptr; // not-null if we are supposed to edit an existing dive site.
location_t location = zero_location; // new value of the location if we edit an existing dive site. location_t location = zero_location; // new value of the location if we edit an existing dive site.
@ -923,7 +923,7 @@ static void setupDivesite(DiveSiteChange &res, struct dive *d, struct dive_site
res.editDs = ds; res.editDs = ds;
res.location = location; res.location = location;
} else { } else {
res.createdDs.reset(alloc_dive_site_with_name(locationtext)); res.createdDs = std::make_unique<dive_site>(locationtext);
res.createdDs->location = location; res.createdDs->location = location;
d->dive_site = res.createdDs.get(); d->dive_site = res.createdDs.get();
} }
@ -1072,7 +1072,7 @@ bool QMLManager::checkLocation(DiveSiteChange &res, struct dive *d, QString loca
if (oldLocation != location) { if (oldLocation != location) {
ds = get_dive_site_by_name(qPrintable(location), divelog.sites); ds = get_dive_site_by_name(qPrintable(location), divelog.sites);
if (!ds && !location.isEmpty()) { if (!ds && !location.isEmpty()) {
res.createdDs.reset(alloc_dive_site_with_name(qPrintable(location))); res.createdDs = std::make_unique<dive_site>(qPrintable(location));
res.changed = true; res.changed = true;
ds = res.createdDs.get(); ds = res.createdDs.get();
} }

View file

@ -63,7 +63,7 @@ QVariant DivesiteImportedModel::data(const QModelIndex &index, int role) const
case LOCATION: case LOCATION:
return printGPSCoords(&ds->location); return printGPSCoords(&ds->location);
case COUNTRY: case COUNTRY:
return taxonomy_get_country(&ds->taxonomy); return QString::fromStdString(taxonomy_get_country(ds->taxonomy));
case NEAREST: { case NEAREST: {
// 40075000 is circumference of the earth in meters // 40075000 is circumference of the earth in meters
struct dive_site *nearest_ds = struct dive_site *nearest_ds =

View file

@ -351,7 +351,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case PHOTOS: case PHOTOS:
break; break;
case COUNTRY: case COUNTRY:
return QString(get_dive_country(d)); return QString::fromStdString(get_dive_country(d));
case BUDDIES: case BUDDIES:
return QString(d->buddy); return QString(d->buddy);
case DIVEGUIDE: case DIVEGUIDE:
@ -1770,7 +1770,7 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case PHOTOS: case PHOTOS:
return lessThanHelper(countPhotos(d1) - countPhotos(d2), row_diff); return lessThanHelper(countPhotos(d1) - countPhotos(d2), row_diff);
case COUNTRY: case COUNTRY:
return lessThanHelper(strCmp(get_dive_country(d1), get_dive_country(d2)), row_diff); return lessThanHelper(strCmp(get_dive_country(d1).c_str(), get_dive_country(d2).c_str()), row_diff);
case BUDDIES: case BUDDIES:
return lessThanHelper(strCmp(d1->buddy, d2->buddy), row_diff); return lessThanHelper(strCmp(d1->buddy, d2->buddy), row_diff);
case DIVEGUIDE: case DIVEGUIDE: