mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-28 05:00:20 +00:00
Merge branch 'taxonomy'
This commit is contained in:
commit
f554c2d16c
20 changed files with 1358 additions and 65 deletions
|
@ -306,6 +306,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||||
configuredivecomputer.cpp
|
configuredivecomputer.cpp
|
||||||
configuredivecomputerthreads.cpp
|
configuredivecomputerthreads.cpp
|
||||||
divesitehelpers.cpp
|
divesitehelpers.cpp
|
||||||
|
taxonomy.c
|
||||||
checkcloudconnection.cpp
|
checkcloudconnection.cpp
|
||||||
windowtitleupdate.cpp
|
windowtitleupdate.cpp
|
||||||
divelogexportlogic.cpp
|
divelogexportlogic.cpp
|
||||||
|
|
15
divesite.c
15
divesite.c
|
@ -169,6 +169,19 @@ void copy_dive_site(struct dive_site *orig, struct dive_site *copy)
|
||||||
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->uuid = orig->uuid;
|
copy->uuid = orig->uuid;
|
||||||
|
copy->taxonomy.nr = orig->taxonomy.nr;
|
||||||
|
if (orig->taxonomy.category == NULL) {
|
||||||
|
free(copy->taxonomy.category);
|
||||||
|
copy->taxonomy.category = NULL;
|
||||||
|
} else {
|
||||||
|
if (copy->taxonomy.category == NULL)
|
||||||
|
copy->taxonomy.category = alloc_taxonomy();
|
||||||
|
for (int i = 0; i < NR_CATEGORIES; i++) {
|
||||||
|
free((void *)copy->taxonomy.category[i].value);
|
||||||
|
copy->taxonomy.category[i] = orig->taxonomy.category[i];
|
||||||
|
copy->taxonomy.category[i].value = copy_string(orig->taxonomy.category[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_dive_site(struct dive_site *ds)
|
void clear_dive_site(struct dive_site *ds)
|
||||||
|
@ -182,4 +195,6 @@ void clear_dive_site(struct dive_site *ds)
|
||||||
ds->latitude.udeg = 0;
|
ds->latitude.udeg = 0;
|
||||||
ds->longitude.udeg = 0;
|
ds->longitude.udeg = 0;
|
||||||
ds->uuid = 0;
|
ds->uuid = 0;
|
||||||
|
ds->taxonomy.nr = 0;
|
||||||
|
free_taxonomy(ds->taxonomy.category);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define DIVESITE_H
|
#define DIVESITE_H
|
||||||
|
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
|
#include "taxonomy.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -17,6 +18,7 @@ struct dive_site
|
||||||
degrees_t latitude, longitude;
|
degrees_t latitude, longitude;
|
||||||
char *description;
|
char *description;
|
||||||
char *notes;
|
char *notes;
|
||||||
|
struct taxonomy_data taxonomy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dive_site_table {
|
struct dive_site_table {
|
||||||
|
|
|
@ -41,54 +41,134 @@ void ReverseGeoLookupThread::run() {
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
QNetworkAccessManager *rgl = new QNetworkAccessManager();
|
QNetworkAccessManager *rgl = new QNetworkAccessManager();
|
||||||
|
QEventLoop loop;
|
||||||
|
QString mapquestURL("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3");
|
||||||
|
QString geonamesURL("http://api.geonames.org/findNearbyPlaceNameJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh");
|
||||||
|
QString geonamesOceanURL("http://api.geonames.org/oceanJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh");
|
||||||
|
QString divelogsURL("https://www.divelogs.de/mapsearch_divespotnames.php?lat=%1&lng=%2&radius=50");
|
||||||
|
QTimer timer;
|
||||||
|
|
||||||
request.setRawHeader("Accept", "text/json");
|
request.setRawHeader("Accept", "text/json");
|
||||||
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
|
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
|
||||||
QEventLoop loop;
|
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||||
QString apiCall("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3");
|
|
||||||
Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) {
|
Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) {
|
||||||
request.setUrl(apiCall.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
|
struct dive_site *ds = get_dive_site_by_uuid(info.uuid);
|
||||||
|
|
||||||
|
// first check the findNearbyPlaces API from geonames - that should give us country, state, city
|
||||||
|
request.setUrl(geonamesURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
|
||||||
|
|
||||||
QNetworkReply *reply = rgl->get(request);
|
QNetworkReply *reply = rgl->get(request);
|
||||||
QTimer timer;
|
|
||||||
timer.setSingleShot(true);
|
timer.setSingleShot(true);
|
||||||
|
|
||||||
QEventLoop loop;
|
|
||||||
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
|
||||||
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
timer.start(500); // 30 secs. timeout
|
timer.start(5000); // 5 secs. timeout
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
if(timer.isActive()) {
|
if(timer.isActive()) {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
if(reply->error() > 0)
|
if(reply->error() > 0) {
|
||||||
|
report_error("got error accessing geonames.org: %s", reply->errorString());
|
||||||
goto clear_reply;
|
goto clear_reply;
|
||||||
|
}
|
||||||
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
if (v < 200 || v >= 300)
|
if (v < 200 || v >= 300)
|
||||||
goto clear_reply;
|
goto clear_reply;
|
||||||
|
QByteArray fullReply = reply->readAll();
|
||||||
QJsonParseError errorObject;
|
QJsonParseError errorObject;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &errorObject);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject);
|
||||||
if (errorObject.error != QJsonParseError::NoError)
|
if (errorObject.error != QJsonParseError::NoError) {
|
||||||
|
report_error("error parsing geonames.org response: %s", errorObject.errorString());
|
||||||
goto clear_reply;
|
goto clear_reply;
|
||||||
|
}
|
||||||
QJsonObject obj = jsonDoc.object();
|
QJsonObject obj = jsonDoc.object();
|
||||||
QJsonObject address = obj.value("address").toObject();
|
QVariant geoNamesObject = obj.value("geonames").toVariant();
|
||||||
|
QVariantList geoNames = geoNamesObject.toList();
|
||||||
struct dive_site *ds = get_dive_site_by_uuid(info.uuid);
|
if (geoNames.count() > 0) {
|
||||||
ds->notes = add_to_string(ds->notes, "countrytag: %s", address.value("country").toString().toUtf8().data());
|
QVariantMap firstData = geoNames.at(0).toMap();
|
||||||
|
int ri = 0;
|
||||||
|
if (ds->taxonomy.category == NULL)
|
||||||
|
ds->taxonomy.category = alloc_taxonomy();
|
||||||
|
// get all the data - OCEAN is special, so start at COUNTRY
|
||||||
|
for (int j = COUNTRY; j < NR_CATEGORIES; j++) {
|
||||||
|
if (firstData[taxonomy_api_names[j]].isValid()) {
|
||||||
|
ds->taxonomy.category[ri].category = j;
|
||||||
|
ds->taxonomy.category[ri].origin = taxonomy::GEOCODED;
|
||||||
|
free((void*)ds->taxonomy.category[ri].value);
|
||||||
|
ds->taxonomy.category[ri].value = copy_string(qPrintable(firstData[taxonomy_api_names[j]].toString()));
|
||||||
|
ri++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ds->taxonomy.nr = ri;
|
||||||
|
mark_divelist_changed(true);
|
||||||
|
} else {
|
||||||
|
report_error("geonames.org did not provide reverse lookup information");
|
||||||
|
qDebug() << "no reverse geo lookup; geonames returned\n" << fullReply;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
report_error("timeout accessing geonames.org");
|
||||||
|
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
|
reply->abort();
|
||||||
|
}
|
||||||
|
// next check the oceans API to figure out the body of water
|
||||||
|
request.setUrl(geonamesOceanURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
|
||||||
|
reply = rgl->get(request);
|
||||||
|
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
|
timer.start(5000); // 5 secs. timeout
|
||||||
|
loop.exec();
|
||||||
|
if(timer.isActive()) {
|
||||||
|
timer.stop();
|
||||||
|
if(reply->error() > 0) {
|
||||||
|
report_error("got error accessing oceans API of geonames.org: %s", reply->errorString());
|
||||||
|
goto clear_reply;
|
||||||
|
}
|
||||||
|
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
if (v < 200 || v >= 300)
|
||||||
|
goto clear_reply;
|
||||||
|
QByteArray fullReply = reply->readAll();
|
||||||
|
QJsonParseError errorObject;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject);
|
||||||
|
if (errorObject.error != QJsonParseError::NoError) {
|
||||||
|
report_error("error parsing geonames.org response: %s", errorObject.errorString());
|
||||||
|
goto clear_reply;
|
||||||
|
}
|
||||||
|
QJsonObject obj = jsonDoc.object();
|
||||||
|
QVariant oceanObject = obj.value("ocean").toVariant();
|
||||||
|
QVariantMap oceanName = oceanObject.toMap();
|
||||||
|
if (oceanName["name"].isValid()) {
|
||||||
|
if (ds->taxonomy.category == NULL)
|
||||||
|
ds->taxonomy.category = alloc_taxonomy();
|
||||||
|
ds->taxonomy.category[ds->taxonomy.nr].category = OCEAN;
|
||||||
|
ds->taxonomy.category[ds->taxonomy.nr].origin = taxonomy::GEOCODED;
|
||||||
|
ds->taxonomy.category[ds->taxonomy.nr].value = copy_string(qPrintable(oceanName["name"].toString()));
|
||||||
|
ds->taxonomy.nr++;
|
||||||
|
mark_divelist_changed(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
report_error("timeout accessing geonames.org");
|
||||||
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
reply->abort();
|
reply->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_reply:
|
clear_reply:
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
rgl->deleteLater();
|
rgl->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReverseGeoLookupThread::lookup(dive_site *ds)
|
||||||
|
{
|
||||||
|
if (!ds)
|
||||||
|
return;
|
||||||
|
GeoLookupInfo info;
|
||||||
|
info.lat = ds->latitude;
|
||||||
|
info.lon = ds->longitude;
|
||||||
|
info.uuid = ds->uuid;
|
||||||
|
|
||||||
|
geo_lookup_data.clear();
|
||||||
|
geo_lookup_data.append(info);
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void add_geo_information_for_lookup(degrees_t latitude, degrees_t longitude, uint32_t uuid) {
|
extern "C" void add_geo_information_for_lookup(degrees_t latitude, degrees_t longitude, uint32_t uuid) {
|
||||||
GeoLookupInfo info;
|
GeoLookupInfo info;
|
||||||
info.lat = latitude;
|
info.lat = latitude;
|
||||||
|
|
|
@ -8,6 +8,7 @@ class ReverseGeoLookupThread : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static ReverseGeoLookupThread *instance();
|
static ReverseGeoLookupThread *instance();
|
||||||
|
void lookup(struct dive_site *ds);
|
||||||
void run() Q_DECL_OVERRIDE;
|
void run() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
1010
icons/geocode.svg
Normal file
1010
icons/geocode.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 38 KiB |
18
load-git.c
18
load-git.c
|
@ -300,6 +300,22 @@ static void parse_site_gps(char *line, struct membuffer *str, void *_ds)
|
||||||
ds->longitude = parse_degrees(line, &line);
|
ds->longitude = parse_degrees(line, &line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_site_geo(char *line, struct membuffer *str, void *_ds)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "line |%s| str |%s|\n", line, mb_cstring(str));
|
||||||
|
struct dive_site *ds = _ds;
|
||||||
|
if (ds->taxonomy.category == NULL)
|
||||||
|
ds->taxonomy.category = alloc_taxonomy();
|
||||||
|
int nr = ds->taxonomy.nr;
|
||||||
|
if (nr < NR_CATEGORIES) {
|
||||||
|
struct taxonomy *t = &ds->taxonomy.category[nr];
|
||||||
|
t->value = strdup(mb_cstring(str));
|
||||||
|
sscanf(line, "cat %d origin %d \"", &t->category, &t->origin);
|
||||||
|
fprintf(stderr, "found category %d origin %d value |%s|\n", t->category, t->origin, t->value);
|
||||||
|
ds->taxonomy.nr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse key=val parts of samples and cylinders etc */
|
/* Parse key=val parts of samples and cylinders etc */
|
||||||
static char *parse_keyvalue_entry(void (*fn)(void *, const char *, const char *), void *fndata, char *line)
|
static char *parse_keyvalue_entry(void (*fn)(void *, const char *, const char *), void *fndata, char *line)
|
||||||
{
|
{
|
||||||
|
@ -906,7 +922,7 @@ static void dive_parser(char *line, struct membuffer *str, void *_dive)
|
||||||
struct keyword_action site_action[] = {
|
struct keyword_action site_action[] = {
|
||||||
#undef D
|
#undef D
|
||||||
#define D(x) { #x, parse_site_ ## x }
|
#define D(x) { #x, parse_site_ ## x }
|
||||||
D(description), D(gps), D(name), D(notes)
|
D(description), D(geo), D(gps), D(name), D(notes)
|
||||||
};
|
};
|
||||||
|
|
||||||
static void site_parser(char *line, struct membuffer *str, void *_ds)
|
static void site_parser(char *line, struct membuffer *str, void *_ds)
|
||||||
|
|
24
parse-xml.c
24
parse-xml.c
|
@ -1431,6 +1431,8 @@ static void try_to_fill_dive_site(struct dive_site **ds_p, const char *name, cha
|
||||||
start_match("divesite", name, buf);
|
start_match("divesite", name, buf);
|
||||||
|
|
||||||
struct dive_site *ds = *ds_p;
|
struct dive_site *ds = *ds_p;
|
||||||
|
if (ds->taxonomy.category == NULL)
|
||||||
|
ds->taxonomy.category = alloc_taxonomy();
|
||||||
|
|
||||||
if (MATCH("uuid", hex_value, &ds->uuid))
|
if (MATCH("uuid", hex_value, &ds->uuid))
|
||||||
return;
|
return;
|
||||||
|
@ -1442,6 +1444,15 @@ static void try_to_fill_dive_site(struct dive_site **ds_p, const char *name, cha
|
||||||
return;
|
return;
|
||||||
if (MATCH("gps", gps_location, ds))
|
if (MATCH("gps", gps_location, ds))
|
||||||
return;
|
return;
|
||||||
|
if (MATCH("cat.geo", get_index, (int *)&ds->taxonomy.category[ds->taxonomy.nr].category))
|
||||||
|
return;
|
||||||
|
if (MATCH("origin.geo", get_index, (int *)&ds->taxonomy.category[ds->taxonomy.nr].origin))
|
||||||
|
return;
|
||||||
|
if (MATCH("value.geo", utf8_string, &ds->taxonomy.category[ds->taxonomy.nr].value)) {
|
||||||
|
if (ds->taxonomy.nr < NR_CATEGORIES)
|
||||||
|
ds->taxonomy.nr++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nonmatch("divesite", name, buf);
|
nonmatch("divesite", name, buf);
|
||||||
}
|
}
|
||||||
|
@ -1517,14 +1528,17 @@ static void dive_site_end(void)
|
||||||
if (!cur_dive_site)
|
if (!cur_dive_site)
|
||||||
return;
|
return;
|
||||||
if (cur_dive_site->uuid) {
|
if (cur_dive_site->uuid) {
|
||||||
uint32_t tmp = create_dive_site_with_gps(cur_dive_site->name, cur_dive_site->latitude, cur_dive_site->longitude);
|
struct dive_site *ds = alloc_dive_site();
|
||||||
struct dive_site *ds = get_dive_site_by_uuid(tmp);
|
if (cur_dive_site->taxonomy.nr == 0) {
|
||||||
ds->uuid = cur_dive_site->uuid;
|
free(cur_dive_site->taxonomy.category);
|
||||||
ds->notes = cur_dive_site->notes;
|
cur_dive_site->taxonomy.category = NULL;
|
||||||
ds->description = cur_dive_site->description;
|
}
|
||||||
|
copy_dive_site(cur_dive_site, ds);
|
||||||
|
|
||||||
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_taxonomy(cur_dive_site->taxonomy.category);
|
||||||
free(cur_dive_site);
|
free(cur_dive_site);
|
||||||
cur_dive_site = NULL;
|
cur_dive_site = NULL;
|
||||||
}
|
}
|
||||||
|
|
5
pref.h
5
pref.h
|
@ -6,6 +6,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
|
#include "taxonomy.h"
|
||||||
|
|
||||||
/* can't use 'bool' for the boolean values - different size in C and C++ */
|
/* can't use 'bool' for the boolean values - different size in C and C++ */
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -28,9 +29,7 @@ typedef struct {
|
||||||
bool enable_geocoding;
|
bool enable_geocoding;
|
||||||
bool parse_dive_without_gps;
|
bool parse_dive_without_gps;
|
||||||
bool tag_existing_dives;
|
bool tag_existing_dives;
|
||||||
char *first_item;
|
enum taxonomy_category category[3];
|
||||||
char *second_item;
|
|
||||||
char *third_item;
|
|
||||||
} geocoding_prefs_t;
|
} geocoding_prefs_t;
|
||||||
|
|
||||||
struct preferences {
|
struct preferences {
|
||||||
|
|
|
@ -116,6 +116,8 @@ GeoReferencingOptionsModel *GeoReferencingOptionsModel::instance() {
|
||||||
GeoReferencingOptionsModel::GeoReferencingOptionsModel(QObject *parent) : QStringListModel(parent)
|
GeoReferencingOptionsModel::GeoReferencingOptionsModel(QObject *parent) : QStringListModel(parent)
|
||||||
{
|
{
|
||||||
QStringList list;
|
QStringList list;
|
||||||
list << "Country" << "State" << "District" << "Town" << "Suburb" << "Body of Water" << "Site Name";
|
int i;
|
||||||
|
for (i = 0; i < NR_CATEGORIES; i++)
|
||||||
|
list << taxonomy_category_names[i];
|
||||||
setStringList(list);
|
setStringList(list);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
|
||||||
|
|
||||||
ui.location->setCompleter(completer);
|
ui.location->setCompleter(completer);
|
||||||
connect(ui.addDiveSite, SIGNAL(clicked()), this, SLOT(showDiveSiteSimpleEdit()));
|
connect(ui.addDiveSite, SIGNAL(clicked()), this, SLOT(showDiveSiteSimpleEdit()));
|
||||||
|
connect(ui.geocodeButton, SIGNAL(clicked()), this, SLOT(reverseGeocode()));
|
||||||
|
|
||||||
QAction *action = new QAction(tr("Apply changes"), this);
|
QAction *action = new QAction(tr("Apply changes"), this);
|
||||||
connect(action, SIGNAL(triggered(bool)), this, SLOT(acceptChanges()));
|
connect(action, SIGNAL(triggered(bool)), this, SLOT(acceptChanges()));
|
||||||
|
@ -506,9 +507,26 @@ void MainTab::updateDiveInfo(bool clear)
|
||||||
|
|
||||||
if (!clear) {
|
if (!clear) {
|
||||||
struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid);
|
struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid);
|
||||||
|
ui.geocodeButton->setVisible(ds && dive_site_has_gps_location(ds));
|
||||||
if (ds) {
|
if (ds) {
|
||||||
|
// construct the location tags
|
||||||
|
QString locationTag;
|
||||||
|
if (ds->taxonomy.nr) {
|
||||||
|
locationTag = "<small><small>(tags: ";
|
||||||
|
QString connector = "";
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < NR_CATEGORIES; j++) {
|
||||||
|
if (ds->taxonomy.category[j].category == prefs.geocoding.category[i]) {
|
||||||
|
locationTag += connector + QString(ds->taxonomy.category[j].value);
|
||||||
|
connector = " / ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locationTag += ")</small></small>";
|
||||||
|
}
|
||||||
ui.location->setText(ds->name);
|
ui.location->setText(ds->name);
|
||||||
ui.locationTags->setText(ds->description); // TODO: This should be three tags following davide's explanation.
|
ui.locationTags->setText(locationTag);
|
||||||
if (displayed_dive.dive_site_uuid)
|
if (displayed_dive.dive_site_uuid)
|
||||||
copy_dive_site(get_dive_site_by_uuid(displayed_dive.dive_site_uuid), &displayed_dive_site);
|
copy_dive_site(get_dive_site_by_uuid(displayed_dive.dive_site_uuid), &displayed_dive_site);
|
||||||
} else {
|
} else {
|
||||||
|
@ -546,6 +564,7 @@ void MainTab::updateDiveInfo(bool clear)
|
||||||
ui.watertemp->setVisible(false);
|
ui.watertemp->setVisible(false);
|
||||||
// rename the remaining fields and fill data from selected trip
|
// rename the remaining fields and fill data from selected trip
|
||||||
ui.LocationLabel->setText(tr("Trip location"));
|
ui.LocationLabel->setText(tr("Trip location"));
|
||||||
|
ui.locationTags->clear();
|
||||||
ui.location->setText(currentTrip->location);
|
ui.location->setText(currentTrip->location);
|
||||||
ui.NotesLabel->setText(tr("Trip notes"));
|
ui.NotesLabel->setText(tr("Trip notes"));
|
||||||
ui.notes->setText(currentTrip->notes);
|
ui.notes->setText(currentTrip->notes);
|
||||||
|
@ -1538,3 +1557,10 @@ void MainTab::showAndTriggerEditSelective(struct dive_components what)
|
||||||
weightModel->changed = true;
|
weightModel->changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainTab::reverseGeocode()
|
||||||
|
{
|
||||||
|
ReverseGeoLookupThread *geoLookup = ReverseGeoLookupThread::instance();
|
||||||
|
geoLookup->lookup(&displayed_dive_site);
|
||||||
|
MainWindow::instance()->information()->updateDiveInfo();
|
||||||
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ slots:
|
||||||
void disableGeoLookupEdition();
|
void disableGeoLookupEdition();
|
||||||
void setCurrentLocationIndex();
|
void setCurrentLocationIndex();
|
||||||
void showDiveSiteSimpleEdit();
|
void showDiveSiteSimpleEdit();
|
||||||
|
void reverseGeocode();
|
||||||
private:
|
private:
|
||||||
Ui::MainTab ui;
|
Ui::MainTab ui;
|
||||||
WeightModel *weightModel;
|
WeightModel *weightModel;
|
||||||
|
|
|
@ -167,25 +167,38 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="LocationLabel">
|
<layout class="QHBoxLayout" name="LocationLayout" stretch="0,1">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Location</string>
|
<widget class="QLabel" name="LocationLabel">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="alignment">
|
<string>Location</string>
|
||||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
</property>
|
||||||
</property>
|
<property name="alignment">
|
||||||
</widget>
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QLabel" name="locationTags">
|
</item>
|
||||||
<property name="text">
|
<item>
|
||||||
<string/>
|
<widget class="QLabel" name="locationTags">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
@ -206,6 +219,17 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="geocodeButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../subsurface.qrc">
|
||||||
|
<normaloff>:/geocode</normaloff>:/geocode</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QtWaitingSpinner" name="waitingSpinner" native="true"/>
|
<widget class="QtWaitingSpinner" name="waitingSpinner" native="true"/>
|
||||||
</item>
|
</item>
|
||||||
|
@ -539,8 +563,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>449</width>
|
<width>100</width>
|
||||||
<height>743</height>
|
<height>30</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="equipmentTabScrollAreaLayout">
|
<layout class="QGridLayout" name="equipmentTabScrollAreaLayout">
|
||||||
|
@ -634,8 +658,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>449</width>
|
<width>286</width>
|
||||||
<height>743</height>
|
<height>300</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="diveInfoScrollAreaLayout">
|
<layout class="QGridLayout" name="diveInfoScrollAreaLayout">
|
||||||
|
@ -975,8 +999,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>449</width>
|
<width>297</width>
|
||||||
<height>743</height>
|
<height>177</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
|
|
@ -241,9 +241,9 @@ void PreferencesDialog::setUiFromPrefs()
|
||||||
ui.enable_geocoding->setChecked( prefs.geocoding.enable_geocoding );
|
ui.enable_geocoding->setChecked( prefs.geocoding.enable_geocoding );
|
||||||
ui.parse_without_gps->setChecked(prefs.geocoding.parse_dive_without_gps);
|
ui.parse_without_gps->setChecked(prefs.geocoding.parse_dive_without_gps);
|
||||||
ui.tag_existing_dives->setChecked(prefs.geocoding.tag_existing_dives);
|
ui.tag_existing_dives->setChecked(prefs.geocoding.tag_existing_dives);
|
||||||
ui.first_item->setCurrentText(prefs.geocoding.first_item);
|
ui.first_item->setCurrentIndex(prefs.geocoding.category[0]);
|
||||||
ui.second_item->setCurrentText(prefs.geocoding.second_item);
|
ui.second_item->setCurrentIndex(prefs.geocoding.category[1]);
|
||||||
ui.third_item->setCurrentText(prefs.geocoding.third_item);
|
ui.third_item->setCurrentIndex(prefs.geocoding.category[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::restorePrefs()
|
void PreferencesDialog::restorePrefs()
|
||||||
|
@ -288,6 +288,13 @@ void PreferencesDialog::rememberPrefs()
|
||||||
else \
|
else \
|
||||||
prefs.field = default_prefs.field
|
prefs.field = default_prefs.field
|
||||||
|
|
||||||
|
#define GET_ENUM(name, type, field) \
|
||||||
|
v = s.value(QString(name)); \
|
||||||
|
if (v.isValid()) \
|
||||||
|
prefs.field = (enum type)v.toInt(); \
|
||||||
|
else \
|
||||||
|
prefs.field = default_prefs.field
|
||||||
|
|
||||||
#define GET_INT_DEF(name, field, defval) \
|
#define GET_INT_DEF(name, field, defval) \
|
||||||
v = s.value(QString(name)); \
|
v = s.value(QString(name)); \
|
||||||
if (v.isValid()) \
|
if (v.isValid()) \
|
||||||
|
@ -455,9 +462,9 @@ void PreferencesDialog::syncSettings()
|
||||||
s.setValue("enable_geocoding", ui.enable_geocoding->isChecked());
|
s.setValue("enable_geocoding", ui.enable_geocoding->isChecked());
|
||||||
s.setValue("parse_dives_without_gps", ui.parse_without_gps->isChecked());
|
s.setValue("parse_dives_without_gps", ui.parse_without_gps->isChecked());
|
||||||
s.setValue("tag_existing_dives", ui.tag_existing_dives->isChecked());
|
s.setValue("tag_existing_dives", ui.tag_existing_dives->isChecked());
|
||||||
s.setValue("first_item", ui.first_item->currentText());
|
s.setValue("cat0", ui.first_item->currentIndex());
|
||||||
s.setValue("second_item", ui.second_item->currentText());
|
s.setValue("cat1", ui.second_item->currentIndex());
|
||||||
s.setValue("third_item", ui.third_item->currentText());
|
s.setValue("cat2", ui.third_item->currentIndex());
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
@ -603,9 +610,9 @@ void PreferencesDialog::loadSettings()
|
||||||
GET_BOOL("enable_geocoding", geocoding.enable_geocoding);
|
GET_BOOL("enable_geocoding", geocoding.enable_geocoding);
|
||||||
GET_BOOL("parse_dives_without_gps", geocoding.parse_dive_without_gps);
|
GET_BOOL("parse_dives_without_gps", geocoding.parse_dive_without_gps);
|
||||||
GET_BOOL("tag_existing_dives", geocoding.tag_existing_dives);
|
GET_BOOL("tag_existing_dives", geocoding.tag_existing_dives);
|
||||||
GET_TXT("first_item", geocoding.first_item);
|
GET_ENUM("cat0", taxonomy_category, geocoding.category[0]);
|
||||||
GET_TXT("second_item", geocoding.second_item);
|
GET_ENUM("cat1", taxonomy_category, geocoding.category[1]);
|
||||||
GET_TXT("third_item", geocoding.third_item);
|
GET_ENUM("cat2", taxonomy_category, geocoding.category[2]);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -897,6 +897,14 @@ 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");
|
||||||
show_gps(&b, ds->latitude, ds->longitude);
|
show_gps(&b, ds->latitude, ds->longitude);
|
||||||
|
if (prefs.geocoding.enable_geocoding)
|
||||||
|
for (int j = 0; j < ds->taxonomy.nr; j++) {
|
||||||
|
struct taxonomy *t = &ds->taxonomy.category[j];
|
||||||
|
if (t->category != NONE) {
|
||||||
|
put_format(&b, "geo cat %d origin %d ", t->category, t->origin);
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
save-xml.c
15
save-xml.c
|
@ -539,7 +539,20 @@ void save_dives_buffer(struct membuffer *b, const bool select_only)
|
||||||
}
|
}
|
||||||
show_utf8(b, ds->description, " description='", "'", 1);
|
show_utf8(b, ds->description, " description='", "'", 1);
|
||||||
show_utf8(b, ds->notes, " notes='", "'", 1);
|
show_utf8(b, ds->notes, " notes='", "'", 1);
|
||||||
put_format(b, "/>\n");
|
if (prefs.geocoding.enable_geocoding && ds->taxonomy.nr) {
|
||||||
|
put_format(b, ">\n");
|
||||||
|
for (int j = 0; j < ds->taxonomy.nr; j++) {
|
||||||
|
struct taxonomy *t = &ds->taxonomy.category[j];
|
||||||
|
if (t->category != NONE) {
|
||||||
|
put_format(b, "<geo cat='%d'", t->category);
|
||||||
|
put_format(b, " origin='%d'", t->origin);
|
||||||
|
show_utf8(b, t->value, " value='", "'/>\n", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put_format(b, "</site>\n");
|
||||||
|
} else {
|
||||||
|
put_format(b, "/>\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
put_format(b, "</divesites>\n<dives>\n");
|
put_format(b, "</divesites>\n<dives>\n");
|
||||||
for (trip = dive_trip_list; trip != NULL; trip = trip->next)
|
for (trip = dive_trip_list; trip != NULL; trip = trip->next)
|
||||||
|
|
|
@ -78,5 +78,6 @@
|
||||||
<file alias="filter-close">icons/process-stop.svg</file>
|
<file alias="filter-close">icons/process-stop.svg</file>
|
||||||
<file alias="edit">icons/edit-circled.svg</file>
|
<file alias="edit">icons/edit-circled.svg</file>
|
||||||
<file alias="satellite">icons/Emblem-earth.svg</file>
|
<file alias="satellite">icons/Emblem-earth.svg</file>
|
||||||
|
<file alias="geocode">icons/geocode.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -74,9 +74,7 @@ struct preferences default_prefs = {
|
||||||
.enable_geocoding = false,
|
.enable_geocoding = false,
|
||||||
.parse_dive_without_gps = false,
|
.parse_dive_without_gps = false,
|
||||||
.tag_existing_dives = false,
|
.tag_existing_dives = false,
|
||||||
.first_item = NULL,
|
.category = { 0 }
|
||||||
.second_item = NULL,
|
|
||||||
.third_item = NULL
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
36
taxonomy.c
Normal file
36
taxonomy.c
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "taxonomy.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
char *taxonomy_category_names[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", "City")
|
||||||
|
};
|
||||||
|
|
||||||
|
// these are the names for geoname.org
|
||||||
|
char *taxonomy_api_names[NR_CATEGORIES] = {
|
||||||
|
"none",
|
||||||
|
"name",
|
||||||
|
"countryName",
|
||||||
|
"adminName1",
|
||||||
|
"adminName2",
|
||||||
|
"toponymName"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct taxonomy *alloc_taxonomy()
|
||||||
|
{
|
||||||
|
return calloc(NR_CATEGORIES, sizeof(struct taxonomy));
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_taxonomy(struct taxonomy *t)
|
||||||
|
{
|
||||||
|
if (t) {
|
||||||
|
for (int i = 0; i < NR_CATEGORIES; i++)
|
||||||
|
free((void *)t[i].value);
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
}
|
39
taxonomy.h
Normal file
39
taxonomy.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef TAXONOMY_H
|
||||||
|
#define TAXONOMY_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum taxonomy_category {
|
||||||
|
NONE,
|
||||||
|
OCEAN,
|
||||||
|
COUNTRY,
|
||||||
|
ADMIN_L1,
|
||||||
|
ADMIN_L2,
|
||||||
|
LOCALNAME,
|
||||||
|
NR_CATEGORIES
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *taxonomy_category_names[NR_CATEGORIES];
|
||||||
|
extern char *taxonomy_api_names[NR_CATEGORIES];
|
||||||
|
|
||||||
|
struct taxonomy {
|
||||||
|
int 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 */
|
||||||
|
enum { GEOCODED, PARSED, MANUAL } origin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* the data block contains 3 taxonomy structures - unused ones have a tag value of NONE */
|
||||||
|
struct taxonomy_data {
|
||||||
|
int nr;
|
||||||
|
struct taxonomy *category;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct taxonomy *alloc_taxonomy();
|
||||||
|
void free_taxonomy(struct taxonomy *t);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // TAXONOMY_H
|
Loading…
Reference in a new issue