From 627de38c01f6bcba56221ed3703bd08d1d215168 Mon Sep 17 00:00:00 2001 From: Tomaz Canabrava Date: Sun, 10 May 2015 12:44:35 -0300 Subject: [PATCH] Get the location information in a separate thread This makes Subsurface usable faster for those without a good internet connection when they are opening an older data file. While parsing, we are only feeding an vector of locations, after the parsing is done, we traverse the vector searching for the information on the web. I need to also add a way to stop if there`s no internet connection - but this will be another patch. Also, fixed two small memory leaks from the old imp. [Dirk Hohndel: cleaned up the whitespace mess] Signed-off-by: Tomaz Canabrava Signed-off-by: Dirk Hohndel --- divesitehelpers.cpp | 81 +++++++++++++++++++++++++++++++------------- divesitehelpers.h | 17 ++++++++++ parse-xml.c | 4 +-- qt-ui/mainwindow.cpp | 11 +++++- 4 files changed, 87 insertions(+), 26 deletions(-) create mode 100644 divesitehelpers.h diff --git a/divesitehelpers.cpp b/divesitehelpers.cpp index b29ca3faa..cc45851f3 100644 --- a/divesitehelpers.cpp +++ b/divesitehelpers.cpp @@ -1,6 +1,9 @@ // // infrastructure to deal with dive sites // + +#include "divesitehelpers.h" + #include "divesite.h" #include "helpers.h" #include "usersurvey.h" @@ -14,28 +17,60 @@ #include #include -extern "C" void reverseGeoLookup(degrees_t latitude, degrees_t longitude, uint32_t uuid) -{ - QNetworkRequest request; - QNetworkAccessManager *rgl = new QNetworkAccessManager(); - request.setUrl(QString("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3") - .arg(uiLanguage(NULL)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0)); - request.setRawHeader("Accept", "text/json"); - request.setRawHeader("User-Agent", getUserAgent().toUtf8()); - QNetworkReply *reply = rgl->get(request); - QEventLoop loop; - QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); - QJsonParseError errorObject; - QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &errorObject); - if (errorObject.error != QJsonParseError::NoError) { - qDebug() << errorObject.errorString(); - } else { - QJsonObject obj = jsonDoc.object(); - QJsonObject address = obj.value("address").toObject(); - qDebug() << "found country:" << address.value("country").toString(); - struct dive_site *ds = get_dive_site_by_uuid(uuid); - ds->notes = add_to_string(ds->notes, "countrytag: %s", address.value("country").toString().toUtf8().data()); - } +struct GeoLoockupInfo { + degrees_t lat; + degrees_t lon; + uint32_t uuid; +}; + +QVector geo_loockup_data; + +ReverseGeoLoockupThread* ReverseGeoLoockupThread::instance() { + static ReverseGeoLoockupThread* self = new ReverseGeoLoockupThread(); + return self; } +ReverseGeoLoockupThread::ReverseGeoLoockupThread(QObject *obj) : QThread(obj) +{ +} + +void ReverseGeoLoockupThread::run() { + if (geo_loockup_data.isEmpty()) + return; + + QNetworkRequest request; + QNetworkAccessManager *rgl = new QNetworkAccessManager(); + 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"); + Q_FOREACH (const GeoLoockupInfo& info, geo_loockup_data ) { + request.setUrl(apiCall.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0)); + QNetworkReply *reply = rgl->get(request); + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + QJsonParseError errorObject; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &errorObject); + if (errorObject.error != QJsonParseError::NoError) { + qDebug() << errorObject.errorString(); + } else { + QJsonObject obj = jsonDoc.object(); + QJsonObject address = obj.value("address").toObject(); + qDebug() << "found country:" << address.value("country").toString(); + 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()); + } + + reply->deleteLater(); + } + rgl->deleteLater(); +} + +extern "C" void add_geo_information_for_loockup(degrees_t latitude, degrees_t longitude, uint32_t uuid) { + GeoLoockupInfo info; + info.lat = latitude; + info.lon = longitude; + info.uuid = uuid; + + geo_loockup_data.append(info); +} diff --git a/divesitehelpers.h b/divesitehelpers.h new file mode 100644 index 000000000..68c195674 --- /dev/null +++ b/divesitehelpers.h @@ -0,0 +1,17 @@ +#ifndef DIVESITEHELPERS_H +#define DIVESITEHELPERS_H + +#include "units.h" +#include + +class ReverseGeoLoockupThread : public QThread { +Q_OBJECT +public: + static ReverseGeoLoockupThread *instance(); + void run() Q_DECL_OVERRIDE; + +private: + ReverseGeoLoockupThread(QObject *parent = 0); +}; + +#endif // DIVESITEHELPERS_H diff --git a/parse-xml.c b/parse-xml.c index 819d3a8ca..9f748cd9d 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -1167,7 +1167,7 @@ static void gps_location(char *buffer, struct dive_site *ds) /* this is in qthelper.cpp, so including the .h file is a pain */ extern const char *printGPSCoords(int lat, int lon); -extern void reverseGeoLookup(degrees_t, degrees_t, uint32_t); +extern void add_geo_information_for_loockup(degrees_t latitude, degrees_t longitude, uint32_t uuid); static void gps_in_dive(char *buffer, struct dive *dive) { @@ -1206,7 +1206,7 @@ static void gps_in_dive(char *buffer, struct dive *dive) } } if (ds && (!ds->notes || strstr(ds->notes, "countrytag:") == NULL)) - reverseGeoLookup(latitude, longitude, dive->dive_site_uuid); + add_geo_information_for_loockup(latitude, longitude, dive->dive_site_uuid); } static void add_dive_site(char *buffer, struct dive *dive) diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index 970c0f739..f8ab75a75 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -32,6 +32,7 @@ #include "divelogimportdialog.h" #include "divelogexportdialog.h" #include "usersurvey.h" +#include "divesitehelpers.h" #ifndef NO_USERMANUAL #include "usermanual.h" #endif @@ -199,6 +200,10 @@ MainWindow::MainWindow() : QMainWindow(), undoRedoActions.append(undoAction); undoRedoActions.append(redoAction); ui.menu_Edit->addActions(undoRedoActions); + + ReverseGeoLoockupThread *geoLoockup = ReverseGeoLoockupThread::instance(); + connect(geoLoockup, SIGNAL(start()),information(), SLOT(setDisabled())); + connect(geoLoockup, SIGNAL(finished()), information(), SLOT(setEnabled())); } MainWindow::~MainWindow() @@ -1292,7 +1297,7 @@ int MainWindow::file_save_as(void) QString filename; const char *default_filename = existing_filename; QFileDialog selection_dialog(this, tr("Save file as"), default_filename, - tr("Subsurface XML files (*.ssrf *.xml *.XML)")); + tr("Subsurface XML files (*.ssrf *.xml *.XML)")); /* if the exit/cancel button is pressed return */ if (!selection_dialog.exec()) @@ -1448,6 +1453,10 @@ void MainWindow::loadFiles(const QStringList fileNames) addRecentFile(fileNames); removeRecentFile(failedParses); + // searches for geo lookup information in a thread so it doesn`t + // freezes the ui. + ReverseGeoLoockupThread::instance()->start(); + refreshDisplay(); ui.actionAutoGroup->setChecked(autogroup); }