From 36657c019be70be11430ce8e785dea3fb2e6a415 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:25:47 -0700 Subject: Geo taxonomy: create some data structures and helper functions This is designed to store taxonomy information for dive sites, including information where the data came from. Signed-off-by: Dirk Hohndel --- CMakeLists.txt | 1 + taxonomy.c | 36 ++++++++++++++++++++++++++++++++++++ taxonomy.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 taxonomy.c create mode 100644 taxonomy.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f84ffe78..2424376d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,6 +287,7 @@ set(SUBSURFACE_CORE_LIB_SRCS configuredivecomputer.cpp configuredivecomputerthreads.cpp divesitehelpers.cpp + taxonomy.c checkcloudconnection.cpp windowtitleupdate.cpp divelogexportlogic.cpp diff --git a/taxonomy.c b/taxonomy.c new file mode 100644 index 000000000..2c101962a --- /dev/null +++ b/taxonomy.c @@ -0,0 +1,36 @@ +#include "taxonomy.h" +#include "gettext.h" +#include + +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); + } +} diff --git a/taxonomy.h b/taxonomy.h new file mode 100644 index 000000000..fef6364e2 --- /dev/null +++ b/taxonomy.h @@ -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 -- cgit v1.2.3-70-g09d2 From 53b805131edeea839dc0af9a51b9e953fc4fcabf Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:28:15 -0700 Subject: Geo taxonomy: add the taxonomy information to dive sites Make the helper functions handle it as well Signed-off-by: Dirk Hohndel --- divesite.c | 15 +++++++++++++++ divesite.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/divesite.c b/divesite.c index 41d96de5d..cd8ee8a7d 100644 --- a/divesite.c +++ b/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->description = copy_string(orig->description); 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) @@ -182,4 +195,6 @@ void clear_dive_site(struct dive_site *ds) ds->latitude.udeg = 0; ds->longitude.udeg = 0; ds->uuid = 0; + ds->taxonomy.nr = 0; + free_taxonomy(ds->taxonomy.category); } diff --git a/divesite.h b/divesite.h index 71f3c0de7..306272e96 100644 --- a/divesite.h +++ b/divesite.h @@ -2,6 +2,7 @@ #define DIVESITE_H #include "units.h" +#include "taxonomy.h" #include #ifdef __cplusplus @@ -17,6 +18,7 @@ struct dive_site degrees_t latitude, longitude; char *description; char *notes; + struct taxonomy_data taxonomy; }; struct dive_site_table { -- cgit v1.2.3-70-g09d2 From 6e81677d89591099266c1d94e06afbf54dbb6358 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:29:32 -0700 Subject: Geo taxonomy: save and load the geo taxonomy data with git This also supports the cloud storage, of course. Signed-off-by: Dirk Hohndel --- load-git.c | 18 +++++++++++++++++- save-git.c | 8 ++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/load-git.c b/load-git.c index 0610cd0d8..7cfad325f 100644 --- a/load-git.c +++ b/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); } +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 */ 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[] = { #undef D #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) diff --git a/save-git.c b/save-git.c index a18ef8f84..ff82ca841 100644 --- a/save-git.c +++ b/save-git.c @@ -897,6 +897,14 @@ static void save_divesites(git_repository *repo, struct dir *tree) show_utf8(&b, "description ", ds->description, "\n"); show_utf8(&b, "notes ", ds->notes, "\n"); 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)); } } -- cgit v1.2.3-70-g09d2 From f7b7d4c2df7fb82421588c69b3aa34e702dcbfdb Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:30:33 -0700 Subject: Geo taxonomy: save and load the taxonomy data with XML If taxonomy data are available we are switching a dive site entry from single item with attributes to an item that has children. This is backwards compatible and older versions will simply ignore the children. Signed-off-by: Dirk Hohndel --- parse-xml.c | 24 +++++++++++++++++++----- save-xml.c | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/parse-xml.c b/parse-xml.c index 4b6901f7f..879e31fd2 100644 --- a/parse-xml.c +++ b/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); struct dive_site *ds = *ds_p; + if (ds->taxonomy.category == NULL) + ds->taxonomy.category = alloc_taxonomy(); if (MATCH("uuid", hex_value, &ds->uuid)) return; @@ -1442,6 +1444,15 @@ static void try_to_fill_dive_site(struct dive_site **ds_p, const char *name, cha return; if (MATCH("gps", gps_location, ds)) 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); } @@ -1517,14 +1528,17 @@ static void dive_site_end(void) if (!cur_dive_site) return; 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 = get_dive_site_by_uuid(tmp); - ds->uuid = cur_dive_site->uuid; - ds->notes = cur_dive_site->notes; - ds->description = cur_dive_site->description; + struct dive_site *ds = alloc_dive_site(); + if (cur_dive_site->taxonomy.nr == 0) { + free(cur_dive_site->taxonomy.category); + cur_dive_site->taxonomy.category = NULL; + } + copy_dive_site(cur_dive_site, ds); + if (verbose > 3) printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name); } + free_taxonomy(cur_dive_site->taxonomy.category); free(cur_dive_site); cur_dive_site = NULL; } diff --git a/save-xml.c b/save-xml.c index 988ede1bf..a81d4258d 100644 --- a/save-xml.c +++ b/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->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, "category); + put_format(b, " origin='%d'", t->origin); + show_utf8(b, t->value, " value='", "'/>\n", 1); + } + } + put_format(b, "\n"); + } else { + put_format(b, "/>\n"); + } } put_format(b, "\n\n"); for (trip = dive_trip_list; trip != NULL; trip = trip->next) -- cgit v1.2.3-70-g09d2 From a413141b334e89b0c9944bc403b8774f85427509 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:32:46 -0700 Subject: Geo taxonomy: adjust the preferences to the new data structures This allows us to pick which three categories of geo taxonomy will be shown in the UI. Signed-off-by: Dirk Hohndel --- pref.h | 5 ++--- qt-models/divelocationmodel.cpp | 4 +++- qt-ui/preferences.cpp | 25 ++++++++++++++++--------- subsurfacestartup.c | 4 +--- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/pref.h b/pref.h index 03b28a98c..0470d0e3b 100644 --- a/pref.h +++ b/pref.h @@ -6,6 +6,7 @@ extern "C" { #endif #include "units.h" +#include "taxonomy.h" /* can't use 'bool' for the boolean values - different size in C and C++ */ typedef struct @@ -28,9 +29,7 @@ typedef struct { bool enable_geocoding; bool parse_dive_without_gps; bool tag_existing_dives; - char *first_item; - char *second_item; - char *third_item; + enum taxonomy_category category[3]; } geocoding_prefs_t; struct preferences { diff --git a/qt-models/divelocationmodel.cpp b/qt-models/divelocationmodel.cpp index e34e20a5d..32bccd5e1 100644 --- a/qt-models/divelocationmodel.cpp +++ b/qt-models/divelocationmodel.cpp @@ -99,6 +99,8 @@ GeoReferencingOptionsModel *GeoReferencingOptionsModel::instance() { GeoReferencingOptionsModel::GeoReferencingOptionsModel(QObject *parent) : QStringListModel(parent) { 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); } diff --git a/qt-ui/preferences.cpp b/qt-ui/preferences.cpp index c93460f9a..25638c991 100644 --- a/qt-ui/preferences.cpp +++ b/qt-ui/preferences.cpp @@ -241,9 +241,9 @@ void PreferencesDialog::setUiFromPrefs() ui.enable_geocoding->setChecked( prefs.geocoding.enable_geocoding ); ui.parse_without_gps->setChecked(prefs.geocoding.parse_dive_without_gps); ui.tag_existing_dives->setChecked(prefs.geocoding.tag_existing_dives); - ui.first_item->setCurrentText(prefs.geocoding.first_item); - ui.second_item->setCurrentText(prefs.geocoding.second_item); - ui.third_item->setCurrentText(prefs.geocoding.third_item); + ui.first_item->setCurrentIndex(prefs.geocoding.category[0]); + ui.second_item->setCurrentIndex(prefs.geocoding.category[1]); + ui.third_item->setCurrentIndex(prefs.geocoding.category[2]); } void PreferencesDialog::restorePrefs() @@ -288,6 +288,13 @@ void PreferencesDialog::rememberPrefs() else \ 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) \ v = s.value(QString(name)); \ if (v.isValid()) \ @@ -455,9 +462,9 @@ void PreferencesDialog::syncSettings() s.setValue("enable_geocoding", ui.enable_geocoding->isChecked()); s.setValue("parse_dives_without_gps", ui.parse_without_gps->isChecked()); s.setValue("tag_existing_dives", ui.tag_existing_dives->isChecked()); - s.setValue("first_item", ui.first_item->currentText()); - s.setValue("second_item", ui.second_item->currentText()); - s.setValue("third_item", ui.third_item->currentText()); + s.setValue("cat0", ui.first_item->currentIndex()); + s.setValue("cat1", ui.second_item->currentIndex()); + s.setValue("cat2", ui.third_item->currentIndex()); s.endGroup(); loadSettings(); @@ -603,9 +610,9 @@ void PreferencesDialog::loadSettings() GET_BOOL("enable_geocoding", geocoding.enable_geocoding); GET_BOOL("parse_dives_without_gps", geocoding.parse_dive_without_gps); GET_BOOL("tag_existing_dives", geocoding.tag_existing_dives); - GET_TXT("first_item", geocoding.first_item); - GET_TXT("second_item", geocoding.second_item); - GET_TXT("third_item", geocoding.third_item); + GET_ENUM("cat0", taxonomy_category, geocoding.category[0]); + GET_ENUM("cat1", taxonomy_category, geocoding.category[1]); + GET_ENUM("cat2", taxonomy_category, geocoding.category[2]); s.endGroup(); } diff --git a/subsurfacestartup.c b/subsurfacestartup.c index f5b0e7b4b..3005e7e04 100644 --- a/subsurfacestartup.c +++ b/subsurfacestartup.c @@ -74,9 +74,7 @@ struct preferences default_prefs = { .enable_geocoding = false, .parse_dive_without_gps = false, .tag_existing_dives = false, - .first_item = NULL, - .second_item = NULL, - .third_item = NULL + .category = { 0 } } }; -- cgit v1.2.3-70-g09d2 From 3055f4ac2212fef67a6e191538fe615f48be7042 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:33:48 -0700 Subject: Geo taxonomy: show the chosen taxonomy entries in the notes pane This isn't perfect - I'd like to have them show behind the word Location instead as what we have now creates movement in the position of the fields on the screen which I think is distracting. Signed-off-by: Dirk Hohndel --- qt-ui/maintab.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index d60e22a79..b5981c977 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -496,9 +496,26 @@ void MainTab::updateDiveInfo(bool clear) if (!clear) { struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid); + qDebug() << "showing dive site uuid" << ds->uuid << ds; if (ds) { + // construct the location tags + QString locationTag; + if (ds->taxonomy.nr) { + QString connector = ""; + for (int i = 0; i < 3; i++) { + qDebug() << "looking for category" << prefs.geocoding.category[i]; + for (int j = 0; j < NR_CATEGORIES; j++) { + qDebug() << "seeing category" << ds->taxonomy.category[j].category; + if (ds->taxonomy.category[j].category == prefs.geocoding.category[i]) { + locationTag += connector + QString(ds->taxonomy.category[j].value); + connector = " / "; + break; + } + } + } + } 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) copy_dive_site(get_dive_site_by_uuid(displayed_dive.dive_site_uuid), &displayed_dive_site); } else { -- cgit v1.2.3-70-g09d2 From b42bae2ce8b665c45020f53ef8b494dffc086d38 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:36:21 -0700 Subject: Geo taxonomy: download the taxonomy data from geonames.org There are a number of web servies we could use. All have their drawbacks. This one is free with free data. It's daily limits are reasonably high. For many coordinates I tested the results were good, for others at least not terrible. We can always consider supporting multiple such services. But for now this seems like a reasonable choice. Signed-off-by: Dirk Hohndel --- divesitehelpers.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++--------- divesitehelpers.h | 1 + 2 files changed, 102 insertions(+), 20 deletions(-) diff --git a/divesitehelpers.cpp b/divesitehelpers.cpp index 62b48ba94..4cc40f203 100644 --- a/divesitehelpers.cpp +++ b/divesitehelpers.cpp @@ -41,54 +41,135 @@ void ReverseGeoLookupThread::run() { QNetworkRequest request; 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("User-Agent", getUserAgent().toUtf8()); - QEventLoop loop; - QString apiCall("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3"); + connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + 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); - QTimer timer; timer.setSingleShot(true); - - QEventLoop loop; - connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - timer.start(500); // 30 secs. timeout + timer.start(5000); // 5 secs. timeout loop.exec(); if(timer.isActive()) { timer.stop(); - if(reply->error() > 0) + if(reply->error() > 0) { + report_error("got error accessing 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(reply->readAll(), &errorObject); - if (errorObject.error != QJsonParseError::NoError) + 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(); - QJsonObject address = obj.value("address").toObject(); - - struct dive_site *ds = get_dive_site_by_uuid(info.uuid); - ds->notes = add_to_string(ds->notes, "countrytag: %s", address.value("country").toString().toUtf8().data()); - + QVariant geoNamesObject = obj.value("geonames").toVariant(); + QVariantList geoNames = geoNamesObject.toList(); + if (geoNames.count() > 0) { + 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 { + 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; + qDebug() << "set category of slot" << ds->taxonomy.nr << "to OCEAN(1)"; + 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())); reply->abort(); } - clear_reply: +clear_reply: reply->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) { GeoLookupInfo info; info.lat = latitude; diff --git a/divesitehelpers.h b/divesitehelpers.h index dad60be36..a08069bc0 100644 --- a/divesitehelpers.h +++ b/divesitehelpers.h @@ -8,6 +8,7 @@ class ReverseGeoLookupThread : public QThread { Q_OBJECT public: static ReverseGeoLookupThread *instance(); + void lookup(struct dive_site *ds); void run() Q_DECL_OVERRIDE; private: -- cgit v1.2.3-70-g09d2 From 80f26912b070328806436fbd3d1d4a37a56e4bb6 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 15:38:08 -0700 Subject: Notes pane: move the location taxonomy to a better spot And display it smaller, marked as "tags". Signed-off-by: Dirk Hohndel --- qt-ui/maintab.cpp | 2 ++ qt-ui/maintab.ui | 37 ++++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index b5981c977..688927cb6 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -501,6 +501,7 @@ void MainTab::updateDiveInfo(bool clear) // construct the location tags QString locationTag; if (ds->taxonomy.nr) { + locationTag = "(tags: "; QString connector = ""; for (int i = 0; i < 3; i++) { qDebug() << "looking for category" << prefs.geocoding.category[i]; @@ -513,6 +514,7 @@ void MainTab::updateDiveInfo(bool clear) } } } + locationTag += ")"; } ui.location->setText(ds->name); ui.locationTags->setText(locationTag); diff --git a/qt-ui/maintab.ui b/qt-ui/maintab.ui index 7ac703076..c7801666f 100644 --- a/qt-ui/maintab.ui +++ b/qt-ui/maintab.ui @@ -171,21 +171,28 @@ 0 - - - Location - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - - - + + + + + Location + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + Qt::RichText + + + + -- cgit v1.2.3-70-g09d2 From c3e38b6da34561cae0f66c151527df55f99be9b0 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 16:07:21 -0700 Subject: Notes pane: once again fix the layout It seems nearly impossible to keep all these margins consistent. Signed-off-by: Dirk Hohndel --- qt-ui/maintab.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qt-ui/maintab.ui b/qt-ui/maintab.ui index c7801666f..3623cf8db 100644 --- a/qt-ui/maintab.ui +++ b/qt-ui/maintab.ui @@ -167,6 +167,12 @@ + + 5 + + + 5 + 0 -- cgit v1.2.3-70-g09d2 From 92722adeba68cde39d9388c629d99ed747af385e Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 16:38:22 -0700 Subject: Notes pane: don't show taxonomy info for trip location Signed-off-by: Dirk Hohndel --- qt-ui/maintab.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index 688927cb6..109c816c2 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -555,6 +555,7 @@ void MainTab::updateDiveInfo(bool clear) ui.watertemp->setVisible(false); // rename the remaining fields and fill data from selected trip ui.LocationLabel->setText(tr("Trip location")); + ui.locationTags->clear(); ui.location->setText(currentTrip->location); ui.NotesLabel->setText(tr("Trip notes")); ui.notes->setText(currentTrip->notes); -- cgit v1.2.3-70-g09d2 From baf68868f5af3f3339504bceca0ca0d6676f8eee Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 16:38:43 -0700 Subject: Notes pane: add geo code button This still needs to be hooked up. Signed-off-by: Dirk Hohndel --- icons/geocode.svg | 1010 +++++++++++++++++++++++++++++++++++++++++++++++++++++ qt-ui/maintab.ui | 23 +- subsurface.qrc | 1 + 3 files changed, 1028 insertions(+), 6 deletions(-) create mode 100644 icons/geocode.svg diff --git a/icons/geocode.svg b/icons/geocode.svg new file mode 100644 index 000000000..517e8788f --- /dev/null +++ b/icons/geocode.svg @@ -0,0 +1,1010 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + internet + tools + applications + category + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qt-ui/maintab.ui b/qt-ui/maintab.ui index 3623cf8db..3318bf788 100644 --- a/qt-ui/maintab.ui +++ b/qt-ui/maintab.ui @@ -219,6 +219,17 @@ + + + + ... + + + + :/geocode:/geocode + + + @@ -552,8 +563,8 @@ 0 0 - 449 - 743 + 100 + 30 @@ -647,8 +658,8 @@ 0 0 - 449 - 743 + 286 + 300 @@ -988,8 +999,8 @@ 0 0 - 449 - 743 + 297 + 177 diff --git a/subsurface.qrc b/subsurface.qrc index a28c86ad6..349d9d7b2 100644 --- a/subsurface.qrc +++ b/subsurface.qrc @@ -78,5 +78,6 @@ icons/process-stop.svg icons/edit-circled.svg icons/Emblem-earth.svg + icons/geocode.svg -- cgit v1.2.3-70-g09d2 From d966fd2606e4ac0054eafd5af1171fc2a5c495b4 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Jul 2015 12:37:50 -0700 Subject: Trigger reverse geo lookup by pressing the button This may not be the best UI, but for now it works. Signed-off-by: Dirk Hohndel --- qt-ui/maintab.cpp | 10 +++++++++- qt-ui/maintab.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index 109c816c2..26f221883 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -59,6 +59,7 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), closeMessage(); connect(ui.addDiveSite, SIGNAL(clicked()), this, SLOT(showDiveSiteSimpleEdit())); + connect(ui.geocodeButton, SIGNAL(clicked()), this, SLOT(reverseGeocode())); QAction *action = new QAction(tr("Apply changes"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(acceptChanges())); @@ -496,7 +497,7 @@ void MainTab::updateDiveInfo(bool clear) if (!clear) { struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid); - qDebug() << "showing dive site uuid" << ds->uuid << ds; + ui.geocodeButton->setVisible(ds && dive_site_has_gps_location(ds)); if (ds) { // construct the location tags QString locationTag; @@ -1550,3 +1551,10 @@ void MainTab::showAndTriggerEditSelective(struct dive_components what) weightModel->changed = true; } } + +void MainTab::reverseGeocode() +{ + ReverseGeoLookupThread *geoLookup = ReverseGeoLookupThread::instance(); + geoLookup->lookup(&displayed_dive_site); + MainWindow::instance()->information()->updateDiveInfo(); +} diff --git a/qt-ui/maintab.h b/qt-ui/maintab.h index 844710954..eac1521cc 100644 --- a/qt-ui/maintab.h +++ b/qt-ui/maintab.h @@ -97,6 +97,7 @@ slots: void disableGeoLookupEdition(); void setCurrentLocationIndex(); void showDiveSiteSimpleEdit(); + void reverseGeocode(); private: Ui::MainTab ui; WeightModel *weightModel; -- cgit v1.2.3-70-g09d2 From 0a0a6f07d5dbb2c24184d22c3c2cedf89ffdc7ac Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Thu, 2 Jul 2015 06:59:08 -0700 Subject: Remove a few more debug messages Yes, I could go back and try to fix the earlier commits. This is easier. Signed-off-by: Dirk Hohndel --- divesitehelpers.cpp | 1 - qt-ui/maintab.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/divesitehelpers.cpp b/divesitehelpers.cpp index 4cc40f203..d635969da 100644 --- a/divesitehelpers.cpp +++ b/divesitehelpers.cpp @@ -138,7 +138,6 @@ void ReverseGeoLookupThread::run() { if (ds->taxonomy.category == NULL) ds->taxonomy.category = alloc_taxonomy(); ds->taxonomy.category[ds->taxonomy.nr].category = OCEAN; - qDebug() << "set category of slot" << ds->taxonomy.nr << "to OCEAN(1)"; 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++; diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index 26f221883..dd6ce72b0 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -505,9 +505,7 @@ void MainTab::updateDiveInfo(bool clear) locationTag = "(tags: "; QString connector = ""; for (int i = 0; i < 3; i++) { - qDebug() << "looking for category" << prefs.geocoding.category[i]; for (int j = 0; j < NR_CATEGORIES; j++) { - qDebug() << "seeing category" << ds->taxonomy.category[j].category; if (ds->taxonomy.category[j].category == prefs.geocoding.category[i]) { locationTag += connector + QString(ds->taxonomy.category[j].value); connector = " / "; -- cgit v1.2.3-70-g09d2