示例#1
0
UserSurvey::UserSurvey(QWidget *parent) : QDialog(parent),
	ui(new Ui::UserSurvey)
{
	QString osArch, arch;
	ui->setupUi(this);
	QShortcut *closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);
	connect(closeKey, SIGNAL(activated()), this, SLOT(close()));
	QShortcut *quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
	connect(quitKey, SIGNAL(activated()), parent, SLOT(close()));

	// fill in the system data
	QString sysInfo = QString("Subsurface %1").arg(VERSION_STRING);
	os = QString("ssrfVers=%1").arg(VERSION_STRING);
	sysInfo.append(tr("\nOperating System: %1").arg(SubsurfaceSysInfo::prettyOsName()));
	os.append(QString("&prettyOsName=%1").arg(SubsurfaceSysInfo::prettyOsName()));
	arch = SubsurfaceSysInfo::cpuArchitecture();
	sysInfo.append(tr("\nCPU Architecture: %1").arg(arch));
	os.append(QString("&appCpuArch=%1").arg(arch));
	if (arch == "i386") {
		osArch = SubsurfaceSysInfo::osArch();
		if (!osArch.isEmpty()) {
			sysInfo.append(tr("\nOS CPU Architecture %1").arg(osArch));
			os.append(QString("&osCpuArch=%1").arg(osArch));
		}
	}
	sysInfo.append(tr("\nLanguage: %1").arg(uiLanguage(NULL)));
	os.append(QString("&uiLang=%1").arg(uiLanguage(NULL)));
	ui->system->setPlainText(sysInfo);
	manager = SubsurfaceWebServices::manager();
	connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(requestReceived(QNetworkReply *)));
}
示例#2
0
void ReverseGeoLookupThread::run() {
	if (geo_lookup_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 GeoLookupInfo& info, geo_lookup_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();
	}
示例#3
0
void init_qt_late()
{
	QApplication *application = qApp;
	// tell Qt to use system proxies
	// note: on Linux, "system" == "environment variables"
	QNetworkProxyFactory::setUseSystemConfiguration(true);

	// for Win32 and Qt5 we try to set the locale codec to UTF-8.
	// this makes QFile::encodeName() work.
#ifdef Q_OS_WIN
	QTextCodec::setCodecForLocale(QTextCodec::codecForMib(106));
#endif

	QCoreApplication::setOrganizationName("Subsurface");
	QCoreApplication::setOrganizationDomain("subsurface.hohndel.org");
	// enable user specific settings (based on command line argument)
	if (settings_suffix) {
		if (verbose)
			qDebug() << "using custom config for" << QString("Subsurface-%1").arg(settings_suffix);
		QCoreApplication::setApplicationName(QString("Subsurface-%1").arg(settings_suffix));
	} else {
		QCoreApplication::setApplicationName("Subsurface");
	}
	// find plugins installed in the application directory (without this SVGs don't work on Windows)
	SettingsObjectWrapper::instance()->load();

	QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
	QLocale loc;
	QString uiLang = uiLanguage(&loc);
	QLocale::setDefault(loc);

	qtTranslator = new QTranslator;
	QString translationLocation;
#if defined(Q_OS_ANDROID)
	translationLocation = QLatin1Literal("assets:/translations");
#elif defined(Q_OS_IOS)
	translationLocation = QLatin1Literal(":/translations/");
#else
	translationLocation = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
#endif
	if (qtTranslator->load(loc, "qt", "_", translationLocation)) {
		application->installTranslator(qtTranslator);
	} else {
		if (uiLang != "en_US" && uiLang != "en-US")
			qDebug() << "can't find Qt localization for locale" << uiLang << "searching in" << translationLocation;
	}
	ssrfTranslator = new QTranslator;
	if (ssrfTranslator->load(loc, "subsurface", "_") ||
	    ssrfTranslator->load(loc, "subsurface", "_", translationLocation) ||
	    ssrfTranslator->load(loc, "subsurface", "_", getSubsurfaceDataPath("translations")) ||
	    ssrfTranslator->load(loc, "subsurface", "_", getSubsurfaceDataPath("../translations"))) {
		application->installTranslator(ssrfTranslator);
	} else {
		qDebug() << "can't find Subsurface localization for locale" << uiLang;
	}
}
示例#4
0
// refresh the preferences when a different SumatraPDF process saves them
// or if they are edited by the user using a text editor
bool Reload()
{
    ScopedMem<WCHAR> path(GetSettingsPath());
    if (!file::Exists(path))
        return false;

    // make sure that the settings file is readable - else wait
    // a short while to prevent accidental dataloss
    int tryAgainCount = 5;
    HANDLE h = file::OpenReadOnly(path);
    while (INVALID_HANDLE_VALUE == h && tryAgainCount-- > 0) {
        Sleep(200);
        h = file::OpenReadOnly(path);
    }
    if (INVALID_HANDLE_VALUE == h) {
        // prefer not reloading to resetting all settings
        return false;
    }

    ScopedHandle hScope(h);

    FILETIME time = file::GetModificationTime(path);
    if (FileTimeEq(time, gGlobalPrefs->lastPrefUpdate))
        return true;

    ScopedMem<char> uiLanguage(str::Dup(gGlobalPrefs->uiLanguage));
    bool showToolbar = gGlobalPrefs->showToolbar;
    bool invertColors = gGlobalPrefs->fixedPageUI.invertColors;

    gFileHistory.UpdateStatesSource(NULL);
    CleanUp();

    bool ok = Load();
    CrashAlwaysIf(!ok || !gGlobalPrefs);

    gGlobalPrefs->fixedPageUI.invertColors = invertColors;

    // TODO: about window doesn't have to be at position 0
    if (gWindows.Count() > 0 && gWindows.At(0)->IsAboutWindow()) {
        gWindows.At(0)->DeleteInfotip();
        gWindows.At(0)->staticLinks.Reset();
        gWindows.At(0)->RedrawAll(true);
    }

    if (!str::Eq(uiLanguage, gGlobalPrefs->uiLanguage))
        SetCurrentLanguageAndRefreshUi(gGlobalPrefs->uiLanguage);

    if (gGlobalPrefs->showToolbar != showToolbar)
        ShowOrHideToolbarGlobally();

    UpdateDocumentColors();
    UpdateFavoritesTreeForAllWindows();

    return true;
}
示例#5
0
void init_ui(void)
{
	// tell Qt to use system proxies
	// note: on Linux, "system" == "environment variables"
	QNetworkProxyFactory::setUseSystemConfiguration(true);

#if QT_VERSION < 0x050000
	// ask QString in Qt 4 to interpret all char* as UTF-8,
	// like Qt 5 does.
	// 106 is "UTF-8", this is faster than lookup by name
	// [http://www.iana.org/assignments/character-sets/character-sets.xml]
	QTextCodec::setCodecForCStrings(QTextCodec::codecForMib(106));
	// and for reasons I can't understand, I need to do the same again for tr
	// even though that clearly uses C strings as well...
	QTextCodec::setCodecForTr(QTextCodec::codecForMib(106));
#ifdef Q_OS_WIN
	QFile::setDecodingFunction(decodeUtf8);
	QFile::setEncodingFunction(encodeUtf8);
#endif
#endif
	QCoreApplication::setOrganizationName("Subsurface");
	QCoreApplication::setOrganizationDomain("subsurface.hohndel.org");
	QCoreApplication::setApplicationName("Subsurface");
	// find plugins installed in the application directory (without this SVGs don't work on Windows)
	QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
	QLocale loc;
	QString uiLang = uiLanguage(&loc);
	QLocale::setDefault(loc);

	// we don't have translations for English - if we don't check for this
	// Qt will proceed to load the second language in preference order - not what we want
	// on Linux this tends to be en-US, but on the Mac it's just en
	if (!uiLang.startsWith("en") || uiLang.startsWith("en-GB")) {
		qtTranslator = new QTranslator;
		if (qtTranslator->load(loc, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
			application->installTranslator(qtTranslator);
		} else {
			qDebug() << "can't find Qt localization for locale" << uiLang << "searching in" << QLibraryInfo::location(QLibraryInfo::TranslationsPath);
		}
		ssrfTranslator = new QTranslator;
		if (ssrfTranslator->load(loc, "subsurface", "_") ||
		    ssrfTranslator->load(loc, "subsurface", "_", getSubsurfaceDataPath("translations")) ||
		    ssrfTranslator->load(loc, "subsurface", "_", getSubsurfaceDataPath("../translations"))) {
			application->installTranslator(ssrfTranslator);
		} else {
			qDebug() << "can't find Subsurface localization for locale" << uiLang;
		}
	}
	window = new MainWindow();
	if (existing_filename && existing_filename[0] != '\0')
		window->setTitle(MWTF_FILENAME);
	else
		window->setTitle(MWTF_DEFAULT);
}
示例#6
0
UserManual::UserManual(QWidget *parent) : QMainWindow(parent),
	ui(new Ui::UserManual)
{
	ui->setupUi(this);

	QShortcut *closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);
	connect(closeKey, SIGNAL(activated()), this, SLOT(close()));
	QShortcut *quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
	connect(quitKey, SIGNAL(activated()), parent, SLOT(close()));

	QAction *actionShowSearch = new QAction(this);
	actionShowSearch->setShortcut(Qt::CTRL + Qt::Key_F);
	actionShowSearch->setShortcutContext(Qt::WindowShortcut);
	addAction(actionShowSearch);

	QAction *actionHideSearch = new QAction(this);
	actionHideSearch->setShortcut(Qt::Key_Escape);
	actionHideSearch->setShortcutContext(Qt::WindowShortcut);
	addAction(actionHideSearch);

	setWindowTitle(tr("User Manual"));

	ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
	QString searchPath = getSubsurfaceDataPath("Documentation");
	if (searchPath.size()) {
		// look for localized versions of the manual first
		QString lang = uiLanguage(NULL);
		QString prefix = searchPath.append("/user-manual");
		QFile manual(prefix + "_" + lang + ".html");
		if (!manual.exists())
			manual.setFileName(prefix + "_" + lang.left(2) + ".html");
		if (!manual.exists())
			manual.setFileName(prefix + ".html");
		if (!manual.exists()) {
			ui->webView->setHtml(tr("Cannot find the Subsurface manual"));
		} else {
			QString urlString = QString("file:///") + manual.fileName();
			QUrl url(urlString, QUrl::TolerantMode);
			ui->webView->setUrl(url);
		}
	} else {
		ui->webView->setHtml(tr("Cannot find the Subsurface manual"));
	}
	ui->searchPanel->setParent(this);
	ui->searchPanel->hide();

	connect(actionShowSearch, SIGNAL(triggered(bool)), this, SLOT(showSearchPanel()));
	connect(actionHideSearch, SIGNAL(triggered(bool)), this, SLOT(hideSearchPanel()));
	connect(ui->webView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClickedSlot(QUrl)));
	connect(ui->searchEdit, SIGNAL(textChanged(QString)), this, SLOT(searchTextChanged(QString)));
	connect(ui->findNext, SIGNAL(clicked()), this, SLOT(searchNext()));
	connect(ui->findPrev, SIGNAL(clicked()), this, SLOT(searchPrev()));
}
示例#7
0
QString UserSurvey::getVersion()
{
	QString arch;
	// fill in the system data
	QString sysInfo = QString("Subsurface %1").arg(subsurface_version());
	sysInfo.append(tr("\nOperating system: %1").arg(SubsurfaceSysInfo::prettyOsName()));
	arch = SubsurfaceSysInfo::buildCpuArchitecture();
	sysInfo.append(tr("\nCPU architecture: %1").arg(arch));
	if (arch == "i386")
		sysInfo.append(tr("\nOS CPU architecture: %1").arg(SubsurfaceSysInfo::currentCpuArchitecture()));
	sysInfo.append(tr("\nLanguage: %1").arg(uiLanguage(NULL)));
	return sysInfo;
}
示例#8
0
QString UserSurvey::getUserAgent()
{
	QString arch;
	// fill in the system data - use ':' as separator
	// replace all other ':' with ' ' so that this is easy to parse
	QString userAgent = QString("Subsurface:%1:").arg(VERSION_STRING);
	userAgent.append(SubsurfaceSysInfo::prettyOsName().replace(':', ' ') + ":");
	arch = SubsurfaceSysInfo::cpuArchitecture().replace(':', ' ');
	userAgent.append(arch);
	if (arch == "i386")
		userAgent.append("/" + SubsurfaceSysInfo::osArch());
	userAgent.append(":" + uiLanguage(NULL));
	return userAgent;

}
示例#9
0
QString getUserAgent()
{
	QString arch;
	// fill in the system data - use ':' as separator
	// replace all other ':' with ' ' so that this is easy to parse
	QString userAgent = QString("Subsurface:%1:").arg(subsurface_version());
	userAgent.append(SubsurfaceSysInfo::prettyOsName().replace(':', ' ') + ":");
	arch = SubsurfaceSysInfo::buildCpuArchitecture().replace(':', ' ');
	userAgent.append(arch);
	if (arch == "i386")
		userAgent.append("/" + SubsurfaceSysInfo::currentCpuArchitecture());
	userAgent.append(":" + uiLanguage(NULL));
	return userAgent;

}
示例#10
0
UserSurvey::UserSurvey(QWidget *parent) : QDialog(parent),
	ui(new Ui::UserSurvey)
{
	ui->setupUi(this);
	ui->buttonBox->buttons().first()->setText(tr("Send"));
	this->adjustSize();
	QShortcut *closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);
	connect(closeKey, SIGNAL(activated()), this, SLOT(close()));
	QShortcut *quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
	connect(quitKey, SIGNAL(activated()), parent, SLOT(close()));

	os = QString("ssrfVers=%1").arg(VERSION_STRING);
	os.append(QString("&prettyOsName=%1").arg(SubsurfaceSysInfo::prettyOsName()));
	QString arch = SubsurfaceSysInfo::cpuArchitecture();
	os.append(QString("&appCpuArch=%1").arg(arch));
	if (arch == "i386") {
		QString osArch = SubsurfaceSysInfo::osArch();
		os.append(QString("&osCpuArch=%1").arg(osArch));
	}
	os.append(QString("&uiLang=%1").arg(uiLanguage(NULL)));
	ui->system->setPlainText(getVersion());
}
示例#11
0
void PreferencesLanguage::syncSettings()
{
	bool useSystemLang = prefs.locale.use_system_language;
	QString currentText = ui->languageDropdown->currentText();

	if (useSystemLang != ui->languageSystemDefault->isChecked() ||
		(!useSystemLang && currentText != prefs.locale.language)) {
		QMessageBox::warning(this, tr("Restart required"),
			tr("To correctly load a new language you must restart Subsurface."));
	}
	QAbstractItemModel *m = ui->languageDropdown->model();
	QModelIndexList languages = m->match(m->index(0, 0), Qt::DisplayRole, currentText);
	QString currentLocale;
	if (languages.count())
		currentLocale = m->data(languages.first(),Qt::UserRole).toString();


	auto lang = SettingsObjectWrapper::instance()->language_settings;
	lang->setLanguage(currentText);
	lang->setLangLocale(currentLocale);
	lang->setUseSystemLanguage(ui->languageSystemDefault->isChecked());
	lang->setTimeFormatOverride(!ui->timeFormatSystemDefault->isChecked());
	lang->setDateFormatOverride(!ui->dateFormatSystemDefault->isChecked());
	lang->setTimeFormat(ui->timeFormatEntry->text());
	lang->setDateFormat(ui->dateFormatEntry->text());
	lang->setDateFormatShort(ui->shortDateFormatEntry->text());
	uiLanguage(NULL);

	QRegExp tfillegalchars("[^hHmszaApPt\\s:;\\.,]");
	if (tfillegalchars.indexIn(ui->timeFormatEntry->text()) >= 0)
		QMessageBox::warning(this, tr("Literal characters"),
			tr("Non-special character(s) in time format.\nThese will be used as is. This might not be what you intended.\nSee http://doc.qt.io/qt-5/qdatetime.html#toString"));

	QRegExp dfillegalchars("[^dMy/\\s:;\\.,]");
	if (dfillegalchars.indexIn(ui->dateFormatEntry->text()) >= 0 ||
	    dfillegalchars.indexIn(ui->shortDateFormatEntry->text()) >= 0)
		QMessageBox::warning(this, tr("Literal characters"),
				     tr("Non-special character(s) in time format.\nThese will be used as is. This might not be what you intended.\nSee http://doc.qt.io/qt-5/qdatetime.html#toString"));
}
示例#12
0
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());
	}
}
int main(int argc, char **argv)
{
	int i;
	bool no_filenames = true;
	QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
	QApplication *application = new QApplication(argc, argv);
	(void)application;
	QStringList files;
	QStringList importedFiles;
	QStringList arguments = QCoreApplication::arguments();

	bool dedicated_console = arguments.length() > 1 &&
				 (arguments.at(1) == QString("--win32console"));
	subsurface_console_init(dedicated_console);

	for (i = 1; i < arguments.length(); i++) {
		QString a = arguments.at(i);
		if (a.at(0) == '-') {
			parse_argument(a.toLocal8Bit().data());
			continue;
		}
		if (imported) {
			importedFiles.push_back(a);
		} else {
			no_filenames = false;
			files.push_back(a);
		}
	}
#if !LIBGIT2_VER_MAJOR && LIBGIT2_VER_MINOR < 22
	git_threads_init();
#else
	git_libgit2_init();
#endif
	setup_system_prefs();
	if (uiLanguage(0).contains("-US"))
		default_prefs.units = IMPERIAL_units;
	prefs = default_prefs;
	fill_profile_color();
	parse_xml_init();
	taglist_init_global();
	init_ui();
	loadPreferences();
	// some hard coded settings
	prefs.animation_speed = 0; // we render the profile to pixmap, no animations

	// always show the divecomputer reported ceiling in red
	prefs.dcceiling = 1;
	prefs.redceiling = 1;

	init_proxy();
	if (no_filenames) {
		if (prefs.default_file_behavior == LOCAL_DEFAULT_FILE) {
			QString defaultFile(prefs.default_filename);
			if (!defaultFile.isEmpty())
				files.push_back(QString(prefs.default_filename));
		} else if (prefs.default_file_behavior == CLOUD_DEFAULT_FILE) {
			QString cloudURL;
			if (getCloudURL(cloudURL) == 0)
				files.push_back(cloudURL);
		}
	}

	if (!quit)
		run_ui();
	exit_ui();
	taglist_free(g_tag_list);
	parse_xml_exit();
	subsurface_console_exit();
	free_prefs();
	return 0;
}
示例#14
0
void ReverseGeoLookupThread::run() {
	if (geo_lookup_data.isEmpty())
		return;

	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());
	connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

	Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) {
		struct dive_site *ds = info.uuid ? get_dive_site_by_uuid(info.uuid) : &displayed_dive_site;

		// 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);
		timer.setSingleShot(true);
		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 geonames.org: %s", qPrintable(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", qPrintable(errorObject.errorString()));
				goto clear_reply;
			}
			QJsonObject obj = jsonDoc.object();
			QVariant geoNamesObject = obj.value("geonames").toVariant();
			QVariantList geoNames = geoNamesObject.toList();
			if (geoNames.count() > 0) {
				QVariantMap firstData = geoNames.at(0).toMap();
				int ri = 0, l3 = -1, lt = -1;
				if (ds->taxonomy.category == NULL) {
					ds->taxonomy.category = alloc_taxonomy();
				} else {
					// clear out the data (except for the ocean data)
					int ocean;
					if ((ocean = taxonomy_index_for_category(&ds->taxonomy, TC_OCEAN)) > 0) {
						ds->taxonomy.category[0] = ds->taxonomy.category[ocean];
						ds->taxonomy.nr = 1;
					} else {
						// ocean is -1 if there is no such entry, and we didn't copy above
						// if ocean is 0, so the following gets us the correct count
						ds->taxonomy.nr = ocean + 1;
					}
				}
				// get all the data - OCEAN is special, so start at COUNTRY
				for (int j = TC_COUNTRY; j < TC_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;
				l3 = taxonomy_index_for_category(&ds->taxonomy, TC_ADMIN_L3);
				lt = taxonomy_index_for_category(&ds->taxonomy, TC_LOCALNAME);
				if (l3 == -1 && lt != -1) {
					// 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,
					// then we copy the town into the city
					ds->taxonomy.category[ri].value = copy_string(ds->taxonomy.category[lt].value);
					ds->taxonomy.category[ri].origin = taxonomy::COPIED;
					ds->taxonomy.category[ri].category = TC_ADMIN_L3;
					ds->taxonomy.nr++;
				}
				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", qPrintable(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", qPrintable(errorObject.errorString()));
				goto clear_reply;
			}
			QJsonObject obj = jsonDoc.object();
			QVariant oceanObject = obj.value("ocean").toVariant();
			QVariantMap oceanName = oceanObject.toMap();
			if (oceanName["name"].isValid()) {
				int idx;
				if (ds->taxonomy.category == NULL)
					ds->taxonomy.category = alloc_taxonomy();
				idx = taxonomy_index_for_category(&ds->taxonomy, TC_OCEAN);
				if (idx == -1)
					idx = ds->taxonomy.nr;
				if (idx < TC_NR_CATEGORIES) {
					ds->taxonomy.category[idx].category = TC_OCEAN;
					ds->taxonomy.category[idx].origin = taxonomy::GEOCODED;
					ds->taxonomy.category[idx].value = copy_string(qPrintable(oceanName["name"].toString()));
					if (idx == ds->taxonomy.nr)
						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:
		reply->deleteLater();
	}
	rgl->deleteLater();
}