void LocationInformationWidget::setLocationId(uint32_t uuid)
{
	currentDs = get_dive_site_by_uuid(uuid);

	if (!currentDs) {
		currentDs = get_dive_site_by_uuid(create_dive_site(""));
		displayed_dive.dive_site_uuid = currentDs->uuid;
		ui.diveSiteName->clear();
		ui.diveSiteDescription->clear();
		ui.diveSiteNotes->clear();
		ui.diveSiteCoordinates->clear();
	}
	displayed_dive_site = *currentDs;
	if (displayed_dive_site.name)
		ui.diveSiteName->setText(displayed_dive_site.name);
	else
		ui.diveSiteName->clear();
	if (displayed_dive_site.description)
		ui.diveSiteDescription->setText(displayed_dive_site.description);
	else
		ui.diveSiteDescription->clear();
	if (displayed_dive_site.notes)
		ui.diveSiteNotes->setPlainText(displayed_dive_site.notes);
	else
		ui.diveSiteNotes->clear();
	if (displayed_dive_site.latitude.udeg || displayed_dive_site.longitude.udeg)
		ui.diveSiteCoordinates->setText(printGPSCoords(displayed_dive_site.latitude.udeg, displayed_dive_site.longitude.udeg));
	else
		ui.diveSiteCoordinates->clear();
}
Esempio n. 2
0
static void copy_gps_location(struct gpsTracker &gps, struct dive *d)
{
	struct dive_site *ds = get_dive_site_by_uuid(d->dive_site_uuid);
	if (!ds) {
		d->dive_site_uuid = create_dive_site(qPrintable(gps.name), gps.when);
		ds = get_dive_site_by_uuid(d->dive_site_uuid);
	}
	ds->latitude = gps.latitude;
	ds->longitude = gps.longitude;
}
static void get_uemis_divespot(const char *mountpath, int divespot_id, struct dive *dive)
{
	struct dive_site *nds = get_dive_site_by_uuid(dive->dive_site_uuid);
	if (nds && nds->name && strstr(nds->name,"from Uemis")) {
		if (load_uemis_divespot(mountpath, divespot_id)) {
			/* get the divesite based on the diveid, this should give us
			* the newly created site
			*/
			struct dive_site *ods = NULL;
			/* with the divesite name we got from parse_dive, that is called on load_uemis_divespot
			 * we search all existing divesites if we have one with the same name already. The function
			 * returns the first found which is luckily not the newly created.
			 */
			(void)get_dive_site_uuid_by_name(nds->name, &ods);
			if (ods) {
				/* if the uuid's are the same, the new site is a duplicat and can be deleted */
				if (nds->uuid != ods->uuid) {
					delete_dive_site(nds->uuid);
					dive->dive_site_uuid = ods->uuid;
				}
			}
		} else {
			/* if we cant load the dive site details, delete the site we
			* created in process_raw_buffer
			*/
			delete_dive_site(dive->dive_site_uuid);
		}
	}
}
Esempio n. 4
0
void save_one_dive_to_mb(struct membuffer *b, struct dive *dive)
{
	struct divecomputer *dc;

	put_string(b, "<dive");
	if (dive->number)
		put_format(b, " number='%d'", dive->number);
	if (dive->tripflag == NO_TRIP)
		put_format(b, " tripflag='NOTRIP'");
	if (dive->rating)
		put_format(b, " rating='%d'", dive->rating);
	if (dive->visibility)
		put_format(b, " visibility='%d'", dive->visibility);
	save_tags(b, dive->tag_list);
	if (dive->dive_site_uuid) {
		if (get_dive_site_by_uuid(dive->dive_site_uuid) != NULL)
			put_format(b, " divesiteid='%8x'", dive->dive_site_uuid);
		else if (verbose)
			fprintf(stderr, "removed reference to non-existant dive site with uuid %08x\n", dive->dive_site_uuid);
	}
	show_date(b, dive->when);
	put_format(b, " duration='%u:%02u min'>\n",
		   FRACTION(dive->dc.duration.seconds, 60));
	save_overview(b, dive);
	save_cylinder_info(b, dive);
	save_weightsystem_info(b, dive);
	save_dive_temperature(b, dive);
	/* Save the dive computer data */
	for_each_dc(dive, dc)
		save_dc(b, dive, dc);
	FOR_EACH_PICTURE(dive)
		save_picture(b, picture);
	put_format(b, "</dive>\n");
}
void LocationInformationWidget::acceptChanges()
{
	emit stopFilterDiveSite();
	char *uiString;
	struct dive_site *currentDs = get_dive_site_by_uuid(displayed_dive_site.uuid);
	currentDs->latitude = displayed_dive_site.latitude;
	currentDs->longitude = displayed_dive_site.longitude;
	uiString = ui.diveSiteName->text().toUtf8().data();
	if (!same_string(uiString, currentDs->name)) {
		free(currentDs->name);
		currentDs->name = copy_string(uiString);
	}
	uiString = ui.diveSiteDescription->text().toUtf8().data();
	if (!same_string(uiString, currentDs->description)) {
		free(currentDs->description);
		currentDs->description = copy_string(uiString);
	}
	uiString = ui.diveSiteNotes->document()->toPlainText().toUtf8().data();
	if (!same_string(uiString, currentDs->notes)) {
		free(currentDs->notes);
		currentDs->notes = copy_string(uiString);
	}
	if (dive_site_is_empty(currentDs)) {
		LocationInformationModel::instance()->removeRow(get_divesite_idx(currentDs));
		displayed_dive.dive_site_uuid = 0;
	}

	mark_divelist_changed(true);
	resetState();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
Esempio n. 6
0
void MapWidgetHelper::centerOnDiveSiteUUID(QVariant dive_site_uuid)
{
	const uint32_t uuid = qvariant_cast<uint32_t>(dive_site_uuid);
	struct dive_site *ds = get_dive_site_by_uuid(uuid);
	if (ds)
		centerOnDiveSite(ds);
}
void LocationInformationWidget::setCurrentDiveSiteByUuid(uint32_t uuid)
{
	currentDs = get_dive_site_by_uuid(uuid);
	if(!currentDs)
		return;

	displayed_dive_site = *currentDs;

	if (displayed_dive_site.name)
		ui.diveSiteName->setText(displayed_dive_site.name);
	else
		ui.diveSiteName->clear();
	if (displayed_dive_site.description)
		ui.diveSiteDescription->setText(displayed_dive_site.description);
	else
		ui.diveSiteDescription->clear();
	if (displayed_dive_site.notes)
		ui.diveSiteNotes->setPlainText(displayed_dive_site.notes);
	else
		ui.diveSiteNotes->clear();
	if (displayed_dive_site.latitude.udeg || displayed_dive_site.longitude.udeg)
		ui.diveSiteCoordinates->setText(printGPSCoords(displayed_dive_site.latitude.udeg, displayed_dive_site.longitude.udeg));
	else
		ui.diveSiteCoordinates->clear();

	if (current_mode == EDIT_DIVE_SITE)
		emit startFilterDiveSite(displayed_dive_site.uuid);
	emit startEditDiveSite(uuid);
}
Esempio n. 8
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();
	}
Esempio n. 9
0
QString constructLocationTags(uint32_t ds_uuid)
{
	QString locationTag;
	struct dive_site *ds = get_dive_site_by_uuid(ds_uuid);

	if (!ds || !ds->taxonomy.nr)
		return locationTag;

	locationTag = "<small><small>(tags: ";
	QString connector;
	for (int i = 0; i < 3; i++) {
		if (prefs.geocoding.category[i] == TC_NONE)
			continue;
		for (int j = 0; j < TC_NR_CATEGORIES; j++) {
			if (ds->taxonomy.category[j].category == prefs.geocoding.category[i]) {
				QString tag = ds->taxonomy.category[j].value;
				if (!tag.isEmpty()) {
					locationTag += connector + tag;
					connector = " / ";
				}
				break;
			}
		}
	}

	locationTag += ")</small></small>";
	return locationTag;
}
Esempio n. 10
0
QGeoCoordinate MapWidgetHelper::getCoordinatesForUUID(QVariant dive_site_uuid)
{
	const uint32_t uuid = qvariant_cast<uint32_t>(dive_site_uuid);
	struct dive_site *ds = get_dive_site_by_uuid(uuid);
	if (!ds || !dive_site_has_gps_location(ds))
		return QGeoCoordinate(0.0, 0.0);
	return QGeoCoordinate(ds->latitude.udeg * 0.000001, ds->longitude.udeg * 0.000001);
}
Esempio n. 11
0
void LocationFilterDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	QFont fontBigger = qApp->font();
	QFont fontSmaller = qApp->font();
	QFontMetrics fmBigger(fontBigger);
	QStyleOptionViewItemV4 opt = option;
	QStyledItemDelegate::initStyleOption(&opt, index);
	QBrush bg;
	QString diveSiteName = index.data().toString();

	struct dive_site *ds = get_dive_site_by_uuid(
		index.model()->data(index.model()->index(index.row(),0)).toInt()
	);
	if (!ds)
		return;

	QString bottomText;
	for (int i = 0; i < ds->taxonomy.nr; i++) {
		if(ds->taxonomy.category[i].category == TC_NONE)
			continue;
		if(!bottomText.isEmpty())
			bottomText += " ";
		bottomText += QString(ds->taxonomy.category[i].value) + " ";
	}

	if (bottomText.isEmpty()) {
		const char *gpsCoords = printGPSCoords(ds->latitude.udeg, ds->longitude.udeg);
		bottomText = QString(gpsCoords);
		free( (void*) gpsCoords);
	}

	fontBigger.setPointSize(fontBigger.pointSize() + 1);
	fontBigger.setBold(true);

	initStyleOption(&opt, index);
	opt.text = QString();
	qApp->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, NULL);

	painter->save();
	painter->setRenderHint(QPainter::Antialiasing);
	painter->setPen(QPen(Qt::NoPen));
	painter->setBrush(bg);
	painter->drawRect(option.rect);
	painter->restore();

	painter->save();
	painter->setBrush(option.palette.text());
	painter->setFont(fontBigger);
	painter->drawText(option.rect.x(),option.rect.y() + fmBigger.boundingRect("YH").height(), diveSiteName);
	painter->setFont(fontSmaller);
	painter->setBrush(option.palette.brightText());
	painter->drawText(option.rect.x(),option.rect.y() + fmBigger.boundingRect("YH").height() * 2, bottomText);
	painter->restore();
}
Esempio n. 12
0
/* try to create a uniqe ID - fingers crossed */
static uint32_t dive_site_getUniqId()
{
	uint32_t id = 0;

	while (id == 0 || get_dive_site_by_uuid(id)) {
		id = rand() & 0xff;
		id |= (rand() & 0xff) << 8;
		id |= (rand() & 0xff) << 16;
		id |= (rand() & 0xff) << 24;
	}

	return id;
}
Esempio n. 13
0
bool QMLManager::checkLocation(DiveObjectHelper *myDive, struct dive *d, QString location, QString gps)
{
	bool diveChanged = false;

	struct dive_site *ds = get_dive_site_by_uuid(d->dive_site_uuid);
	if (myDive->location() != location) {
		diveChanged = true;
		ds = get_dive_site_by_uuid(create_dive_site(qPrintable(location), d->when));
		d->dive_site_uuid = ds->uuid;
	}
	// now make sure that the GPS coordinates match - if the user changed the name but not
	// the GPS coordinates, this still does the right thing as the now new dive site will
	// have no coordinates, so the coordinates from the edit screen will get added
	if (myDive->gps() != gps) {
		double lat, lon;
		if (parseGpsText(gps, &lat, &lon)) {
			// there are valid GPS coordinates - just use them
			setupDivesite(d, ds, lat, lon, qPrintable(myDive->location()));
			diveChanged = true;
		} else if (gps == GPS_CURRENT_POS) {
			// user asked to use current pos
			QString gpsString = getCurrentPosition();
			if (gpsString != GPS_CURRENT_POS) {
				if (parseGpsText(qPrintable(gpsString), &lat, &lon)) {
					setupDivesite(d, ds, lat, lon, qPrintable(myDive->location()));
					diveChanged = true;
				}
			} else {
				appendTextToLog("couldn't get GPS location in time");
				qDebug() << "still don't have a position - will need to implement some sort of callback";
			}
		} else {
			// just something we can't parse, so tell the user
			appendTextToLog(QString("wasn't able to parse gps string '%1'").arg(gps));
		}
	}
	return diveChanged;
}
void LocationInformationWidget::resetState()
{
	if (displayed_dive.id) {
		struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid);
		if(ds) {
			displayed_dive_site = *ds;
		}
	}
	modified = false;
	resetPallete();
	MainWindow::instance()->dive_list()->setEnabled(true);
	MainWindow::instance()->setEnabledToolbar(true);
	ui.diveSiteMessage->setText(tr("Dive site management"));
}
Esempio n. 15
0
void LocationFilterDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	QFont fontBigger = qApp->font();
	QFont fontSmaller = qApp->font();
	QFontMetrics fmBigger(fontBigger);
	QStyleOptionViewItemV4 opt = option;
	QStyledItemDelegate::initStyleOption(&opt, index);
	QBrush bg;
	QString diveSiteName = index.data().toString();

	struct dive_site *ds = get_dive_site_by_uuid(
		index.model()->data(index.model()->index(index.row(),0)).toInt()
	);
	if (!ds)
		return;

	const char *gpsCoords = printGPSCoords(displayed_dive_site.latitude.udeg, displayed_dive_site.longitude.udeg);
	QString diveSiteCoords(gpsCoords);
	free( (void*) gpsCoords);

	fontBigger.setPointSize(fontBigger.pointSize() + 2);
	fontBigger.setBold(true);

	painter->save();
	painter->setRenderHint(QPainter::Antialiasing);
	if( ( option.state & QStyle::State_Selected ) || ( option.state & QStyle::State_MouseOver ) )
	    bg = option.palette.highlight();
	else
	    bg = option.palette.window();
	painter->setPen(QPen(Qt::NoPen));
	painter->setBrush(bg);
	painter->drawRect(option.rect);
	painter->restore();

	painter->save();
	painter->setBrush(option.palette.text());
	painter->setFont(fontBigger);
	painter->drawText(option.rect.x(),option.rect.y() + fmBigger.boundingRect("YH").height(), diveSiteName);
	painter->setFont(fontSmaller);
	painter->setBrush(option.palette.brightText());
	painter->drawText(option.rect.x(),option.rect.y() + fmBigger.boundingRect("YH").height() * 2, diveSiteCoords);
	painter->restore();
}
void LocationInformationWidget::rejectChanges()
{
	if (current_mode == CREATE_DIVE_SITE) {
		LocationInformationModel::instance()->removeRow(get_divesite_idx(currentDs));
		if (displayed_dive.dive_site_uuid) {
			displayed_dive_site = *get_dive_site_by_uuid(displayed_dive.dive_site_uuid);
		} else {
			displayed_dive_site.uuid = 0;
		}
	} else if ((currentDs && dive_site_is_empty(currentDs))) {
		LocationInformationModel::instance()->removeRow(get_divesite_idx(currentDs));
		displayed_dive_site.uuid = 0;
	}

	resetState();
	emit stopFilterDiveSite();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
Esempio n. 17
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());
	}
}
Esempio n. 18
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();
}
Esempio n. 19
0
// TODO: This looks like should be ported to C code. or a big part of it.
bool DivelogsDeWebServices::prepare_dives_for_divelogs(const QString &tempfile, const bool selected)
{
	static const char errPrefix[] = "divelog.de-upload:";
	if (!amount_selected) {
		report_error(tr("no dives were selected").toUtf8());
		return false;
	}

	xsltStylesheetPtr xslt = NULL;
	struct zip *zip;

	xslt = get_stylesheet("divelogs-export.xslt");
	if (!xslt) {
		qDebug() << errPrefix << "missing stylesheet";
		return false;
	}


	int error_code;
	zip = zip_open(QFile::encodeName(QDir::toNativeSeparators(tempfile)), ZIP_CREATE, &error_code);
	if (!zip) {
		char buffer[1024];
		zip_error_to_str(buffer, sizeof buffer, error_code, errno);
		report_error(tr("failed to create zip file for upload: %s").toUtf8(), buffer);
		return false;
	}

	/* walk the dive list in chronological order */
	int i;
	struct dive *dive;
	for_each_dive (i, dive) {
		FILE *f;
		char filename[PATH_MAX];
		int streamsize;
		const char *membuf;
		xmlDoc *transformed;
		struct zip_source *s;
		struct membuffer mb = { 0 };

		/*
		 * Get the i'th dive in XML format so we can process it.
		 * We need to save to a file before we can reload it back into memory...
		 */
		if (selected && !dive->selected)
			continue;
		/* make sure the buffer is empty and add the dive */
		mb.len = 0;

		struct dive_site *ds = get_dive_site_by_uuid(dive->dive_site_uuid);

		if (ds) {
			put_format(&mb, "<divelog><divesites><site uuid='%8x' name='", dive->dive_site_uuid);
			put_quoted(&mb, ds->name, 1, 0);
			put_format(&mb, "'");
			if (ds->latitude.udeg || ds->longitude.udeg) {
				put_degrees(&mb, ds->latitude, " gps='", " ");
				put_degrees(&mb, ds->longitude, "", "'");
			}
			put_format(&mb, "/>\n</divesites>\n");
		}

		save_one_dive_to_mb(&mb, dive);

		if (ds) {
			put_format(&mb, "</divelog>\n");
		}
		membuf = mb_cstring(&mb);
		streamsize = strlen(membuf);
		/*
		 * Parse the memory buffer into XML document and
		 * transform it to divelogs.de format, finally dumping
		 * the XML into a character buffer.
		 */
		xmlDoc *doc = xmlReadMemory(membuf, streamsize, "divelog", NULL, 0);
		if (!doc) {
			qWarning() << errPrefix << "could not parse back into memory the XML file we've just created!";
			report_error(tr("internal error").toUtf8());
			goto error_close_zip;
		}
		free((void *)membuf);

		transformed = xsltApplyStylesheet(xslt, doc, NULL);
		xmlDocDumpMemory(transformed, (xmlChar **)&membuf, &streamsize);
		xmlFreeDoc(doc);
		xmlFreeDoc(transformed);

		/*
		 * Save the XML document into a zip file.
		 */
		snprintf(filename, PATH_MAX, "%d.xml", i + 1);
		s = zip_source_buffer(zip, membuf, streamsize, 1);
		if (s) {
			int64_t ret = zip_add(zip, filename, s);
			if (ret == -1)
				qDebug() << errPrefix << "failed to include dive:" << i;
		}
	}
Esempio n. 20
0
void LocationFilterDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &origIdx) const
{
	QFont fontBigger = qApp->font();
	QFont fontSmaller = qApp->font();
	QFontMetrics fmBigger(fontBigger);
	QStyleOptionViewItemV4 opt = option;
	const QAbstractProxyModel *proxyModel = dynamic_cast<const QAbstractProxyModel*>(origIdx.model());
	QModelIndex index = proxyModel->mapToSource(origIdx);
	QStyledItemDelegate::initStyleOption(&opt, index);
	QString diveSiteName = index.data().toString();
	QString bottomText;
	QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
	struct dive_site *ds = get_dive_site_by_uuid(
		index.model()->data(index.model()->index(index.row(),0)).toInt()
	);
	//Special case: do not show name, but instead, show
	if (index.row() < 2) {
		diveSiteName = index.data().toString();
		bottomText = index.data(Qt::ToolTipRole).toString();
		goto print_part;
	}

	if (!ds)
		return;

	for (int i = 0; i < 3; i++) {
		if (prefs.geocoding.category[i] == TC_NONE)
			continue;
		int idx = taxonomy_index_for_category(&ds->taxonomy, prefs.geocoding.category[i]);
		if (idx == -1)
			continue;
		if(!bottomText.isEmpty())
			bottomText += " / ";
		bottomText += QString(ds->taxonomy.category[idx].value);
	}

	if (bottomText.isEmpty()) {
		const char *gpsCoords = printGPSCoords(ds->latitude.udeg, ds->longitude.udeg);
		bottomText = QString(gpsCoords);
		free( (void*) gpsCoords);
	}

	if (dive_site_has_gps_location(ds) && dive_site_has_gps_location(&displayed_dive_site)) {
		// so we are showing a completion and both the current dive site and the completion
		// have a GPS fix... so let's show the distance
		if (ds->latitude.udeg == displayed_dive_site.latitude.udeg &&
		    ds->longitude.udeg == displayed_dive_site.longitude.udeg) {
			bottomText += tr(" (same GPS fix)");
		} else {
			int distanceMeters = get_distance(ds->latitude, ds->longitude, displayed_dive_site.latitude, displayed_dive_site.longitude);
			QString distance = distance_string(distanceMeters);
			int nr = nr_of_dives_at_dive_site(ds->uuid, false);
			bottomText += tr(" (~%1 away").arg(distance);
			bottomText += tr(", %1 dive(s) here)").arg(nr);
		}
	}
	if (bottomText.isEmpty()) {
		if (dive_site_has_gps_location(&displayed_dive_site))
			bottomText = tr("(no existing GPS data, add GPS fix from this dive)");
		else
			bottomText = tr("(no GPS data)");
	}
	bottomText = tr("Pick site: ") + bottomText;

print_part:

	fontBigger.setPointSize(fontBigger.pointSize() + 1);
	fontBigger.setBold(true);
	QPen textPen = QPen(option.state & QStyle::State_Selected ? option.palette.highlightedText().color() : option.palette.text().color(), 1);

	initStyleOption(&opt, index);
	opt.text = QString();
	opt.icon = QIcon();
	painter->setClipRect(option.rect);

	painter->save();
	if (option.state & QStyle::State_Selected) {
		painter->setPen(QPen(opt.palette.highlight().color().darker()));
		painter->setBrush(opt.palette.highlight());
		const qreal pad = 1.0;
		const qreal pad2 = pad * 2.0;
		const qreal rounding = 5.0;
		painter->drawRoundedRect(option.rect.x() + pad,
			option.rect.y() + pad,
			option.rect.width() - pad2,
			option.rect.height() - pad2,
			rounding, rounding);
	}
	painter->setPen(textPen);
	painter->setFont(fontBigger);
	const qreal textPad = 5.0;
	painter->drawText(option.rect.x() + textPad, option.rect.y() + fmBigger.boundingRect("YH").height(), diveSiteName);
	double pointSize = fontSmaller.pointSizeF();
	fontSmaller.setPointSizeF(0.9 * pointSize);
	painter->setFont(fontSmaller);
	painter->drawText(option.rect.x() + textPad, option.rect.y() + fmBigger.boundingRect("YH").height() * 2, bottomText);
	painter->restore();

	if (!icon.isNull()) {
		painter->save();
		painter->drawPixmap(
			option.rect.x() + option.rect.width() - 24,
			option.rect.y() + option.rect.height() - 24, icon.pixmap(20,20));
		painter->restore();
	}
}
Esempio n. 21
0
// update the dive and return the notes field, stripped of the HTML junk
void QMLManager::commitChanges(QString diveId, QString date, QString location, QString gps, QString duration, QString depth,
			       QString airtemp, QString watertemp, QString suit, QString buddy, QString diveMaster, QString weight, QString notes,
			       QString startpressure, QString endpressure, QString gasmix)
{
#define DROP_EMPTY_PLACEHOLDER(_s) if ((_s) == QLatin1Literal("--")) (_s).clear()

	DROP_EMPTY_PLACEHOLDER(location);
	DROP_EMPTY_PLACEHOLDER(duration);
	DROP_EMPTY_PLACEHOLDER(depth);
	DROP_EMPTY_PLACEHOLDER(airtemp);
	DROP_EMPTY_PLACEHOLDER(watertemp);
	DROP_EMPTY_PLACEHOLDER(suit);
	DROP_EMPTY_PLACEHOLDER(buddy);
	DROP_EMPTY_PLACEHOLDER(diveMaster);
	DROP_EMPTY_PLACEHOLDER(weight);
	DROP_EMPTY_PLACEHOLDER(gasmix);
	DROP_EMPTY_PLACEHOLDER(startpressure);
	DROP_EMPTY_PLACEHOLDER(endpressure);
	DROP_EMPTY_PLACEHOLDER(notes);

#undef DROP_EMPTY_PLACEHOLDER

	struct dive *d = get_dive_by_uniq_id(diveId.toInt());
	// notes comes back as rich text - let's convert this into plain text
	QTextDocument doc;
	doc.setHtml(notes);
	notes = doc.toPlainText();

	if (!d) {
		qDebug() << "don't touch this... no dive";
		return;
	}
	bool diveChanged = false;
	bool needResort = false;

	invalidate_dive_cache(d);
	if (date != get_dive_date_string(d->when)) {
		diveChanged = needResort = true;
		QDateTime newDate;
		// what a pain - Qt will not parse dates if the day of the week is incorrect
		// so if the user changed the date but didn't update the day of the week (most likely behavior, actually),
		// we need to make sure we don't try to parse that
		QString format(QString(prefs.date_format) + QChar(' ') + prefs.time_format);
		if (format.contains(QLatin1String("ddd")) || format.contains(QLatin1String("dddd"))) {
			QString dateFormatToDrop = format.contains(QLatin1String("ddd")) ? QStringLiteral("ddd") : QStringLiteral("dddd");
			QDateTime ts;
			QLocale loc = getLocale();
			ts.setMSecsSinceEpoch(d->when * 1000L);
			QString drop = loc.toString(ts.toUTC(), dateFormatToDrop);
			format.replace(dateFormatToDrop, "");
			date.replace(drop, "");
		}
		newDate = QDateTime::fromString(date, format);
		if (!newDate.isValid()) {
			qDebug() << "unable to parse date" << date << "with the given format" << format;
			QRegularExpression isoDate("\\d+-\\d+-\\d+[^\\d]+\\d+:\\d+");
			if (date.contains(isoDate)) {
				newDate = QDateTime::fromString(date, "yyyy-M-d h:m:s");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date, "yy-M-d h:m:s");
				if (newDate.isValid())
					goto parsed;
			}
			QRegularExpression isoDateNoSecs("\\d+-\\d+-\\d+[^\\d]+\\d+");
			if (date.contains(isoDateNoSecs)) {
				newDate = QDateTime::fromString(date, "yyyy-M-d h:m");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date, "yy-M-d h:m");
				if (newDate.isValid())
					goto parsed;
			}
			QRegularExpression usDate("\\d+/\\d+/\\d+[^\\d]+\\d+:\\d+:\\d+");
			if (date.contains(usDate)) {
				newDate = QDateTime::fromString(date, "M/d/yyyy h:m:s");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date, "M/d/yy h:m:s");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date.toLower(), "M/d/yyyy h:m:sap");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date.toLower(), "M/d/yy h:m:sap");
				if (newDate.isValid())
					goto parsed;
			}
			QRegularExpression usDateNoSecs("\\d+/\\d+/\\d+[^\\d]+\\d+:\\d+");
			if (date.contains(usDateNoSecs)) {
				newDate = QDateTime::fromString(date, "M/d/yyyy h:m");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date, "M/d/yy h:m");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date.toLower(), "M/d/yyyy h:map");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date.toLower(), "M/d/yy h:map");
				if (newDate.isValid())
					goto parsed;
			}
			QRegularExpression leDate("\\d+\\.\\d+\\.\\d+[^\\d]+\\d+:\\d+:\\d+");
			if (date.contains(leDate)) {
				newDate = QDateTime::fromString(date, "d.M.yyyy h:m:s");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date, "d.M.yy h:m:s");
				if (newDate.isValid())
					goto parsed;
			}
			QRegularExpression leDateNoSecs("\\d+\\.\\d+\\.\\d+[^\\d]+\\d+:\\d+");
			if (date.contains(leDateNoSecs)) {
				newDate = QDateTime::fromString(date, "d.M.yyyy h:m");
				if (newDate.isValid())
					goto parsed;
				newDate = QDateTime::fromString(date, "d.M.yy h:m");
				if (newDate.isValid())
					goto parsed;
			}
		}
parsed:
		if (newDate.isValid()) {
			// stupid Qt... two digit years are always 19xx - WTF???
			// so if adding a hundred years gets you into something before a year from now...
			// add a hundred years.
			if (newDate.addYears(100) < QDateTime::currentDateTime().addYears(1))
				newDate = newDate.addYears(100);
			d->dc.when = d->when = newDate.toMSecsSinceEpoch() / 1000 + gettimezoneoffset(newDate.toMSecsSinceEpoch() / 1000);
		} else {
			qDebug() << "none of our parsing attempts worked for the date string";
		}
	}
	struct dive_site *ds = get_dive_site_by_uuid(d->dive_site_uuid);
	char *locationtext = NULL;
	if (ds)
		locationtext = ds->name;
	if (!same_string(locationtext, qPrintable(location))) {
		diveChanged = true;
		// this is not ideal - and it's missing the gps information
		// but for now let's just create a new dive site
		ds = get_dive_site_by_uuid(create_dive_site(qPrintable(location), d->when));
		d->dive_site_uuid = ds->uuid;
	}
	if (!gps.isEmpty()) {
		QString gpsString = getCurrentPosition();
		if (gpsString != QString("waiting for the next gps location")) {
			qDebug() << "from commitChanges call to getCurrentPosition returns" << gpsString;
			double lat, lon;
			if (parseGpsText(qPrintable(gpsString), &lat, &lon)) {
				struct dive_site *ds = get_dive_site_by_uuid(d->dive_site_uuid);
				if (ds) {
					ds->latitude.udeg = lat * 1000000;
					ds->longitude.udeg = lon * 1000000;
				} else {
					degrees_t latData, lonData;
					latData.udeg = lat;
					lonData.udeg = lon;
					d->dive_site_uuid = create_dive_site_with_gps("new site", latData, lonData, d->when);
				}
				qDebug() << "set up dive site with new GPS data";
			}
		} else {
			qDebug() << "still don't have a position - will need to implement some sort of callback";
		}
	}
	if (get_dive_duration_string(d->duration.seconds, tr("h:"), tr("min")) != duration) {
		diveChanged = true;
		int h = 0, m = 0, s = 0;
		QRegExp r1(QStringLiteral("(\\d*)\\s*%1[\\s,:]*(\\d*)\\s*%2[\\s,:]*(\\d*)\\s*%3").arg(tr("h")).arg(tr("min")).arg(tr("sec")), Qt::CaseInsensitive);
		QRegExp r2(QStringLiteral("(\\d*)\\s*%1[\\s,:]*(\\d*)\\s*%2").arg(tr("h")).arg(tr("min")), Qt::CaseInsensitive);
		QRegExp r3(QStringLiteral("(\\d*)\\s*%1").arg(tr("min")), Qt::CaseInsensitive);
		QRegExp r4(QStringLiteral("(\\d*):(\\d*):(\\d*)"));
		QRegExp r5(QStringLiteral("(\\d*):(\\d*)"));
		QRegExp r6(QStringLiteral("(\\d*)"));
		if (r1.indexIn(duration) >= 0) {
			h = r1.cap(1).toInt();
			m = r1.cap(2).toInt();
			s = r1.cap(3).toInt();
		} else if (r2.indexIn(duration) >= 0) {
			h = r2.cap(1).toInt();
			m = r2.cap(2).toInt();
		} else if (r3.indexIn(duration) >= 0) {
			m = r3.cap(1).toInt();
		} else if (r4.indexIn(duration) >= 0) {
			h = r4.cap(1).toInt();
			m = r4.cap(2).toInt();
			s = r4.cap(3).toInt();
		} else if (r5.indexIn(duration) >= 0) {
			h = r5.cap(1).toInt();
			m = r5.cap(2).toInt();
		} else if (r6.indexIn(duration) >= 0) {
			m = r6.cap(1).toInt();
		}
		d->dc.duration.seconds = d->duration.seconds = h * 3600 + m * 60 + s;
		if (same_string(d->dc.model, "manually added dive")) {
			free(d->dc.sample);
			d->dc.sample = 0;
			d->dc.samples = 0;
		} else {
			qDebug() << "changing the duration on a dive that wasn't manually added - Uh-oh";
		}

	}
	if (get_depth_string(d->maxdepth.mm, true, true) != depth) {
		int depthValue = parseLengthToMm(depth);
		// the QML code should stop negative depth, but massively huge depth can make
		// the profile extremely slow or even run out of memory and crash, so keep
		// the depth <= 500m
		if (0 <= depthValue && depthValue <= 500000) {
			diveChanged = true;
			d->maxdepth.mm = depthValue;
			if (same_string(d->dc.model, "manually added dive")) {
				d->dc.maxdepth.mm = d->maxdepth.mm;
				free(d->dc.sample);
				d->dc.sample = 0;
				d->dc.samples = 0;
			}
		}
	}
	if (get_temperature_string(d->airtemp, true) != airtemp) {
		diveChanged = true;
		d->airtemp.mkelvin = parseTemperatureToMkelvin(airtemp);
	}
	if (get_temperature_string(d->watertemp, true) != watertemp) {
		diveChanged = true;
		d->watertemp.mkelvin = parseTemperatureToMkelvin(watertemp);
	}
	// not sure what we'd do if there was more than one weight system
	// defined - for now just ignore that case
	if (weightsystem_none((void *)&d->weightsystem[1])) {
		if (get_weight_string(d->weightsystem[0].weight, true) != weight) {
			diveChanged = true;
			d->weightsystem[0].weight.grams = parseWeightToGrams(weight);
		}
	}
	// start and end pressures for first cylinder only
	if (get_pressure_string(d->cylinder[0].start, true) != startpressure || get_pressure_string(d->cylinder[0].end, true) != endpressure) {
		diveChanged = true;
		d->cylinder[0].start.mbar = parsePressureToMbar(startpressure);
		d->cylinder[0].end.mbar = parsePressureToMbar(endpressure);
		if (d->cylinder[0].end.mbar > d->cylinder[0].start.mbar)
			d->cylinder[0].end.mbar = d->cylinder[0].start.mbar;
	}
	// gasmix for first cylinder
	if (get_gas_string(d->cylinder[0].gasmix) != gasmix) {
		int o2 = parseGasMixO2(gasmix);
		int he = parseGasMixHE(gasmix);
		// the QML code SHOULD only accept valid gas mixes, but just to make sure
		if (o2 >= 0 && o2 <= 1000 &&
		    he >= 0 && he <= 1000 &&
		    o2 + he <= 1000) {
			diveChanged = true;
			d->cylinder[0].gasmix.o2.permille = o2;
			d->cylinder[0].gasmix.he.permille = he;
		}
	}
	if (!same_string(d->suit, qPrintable(suit))) {
		diveChanged = true;
		free(d->suit);
		d->suit = strdup(qPrintable(suit));
	}
	if (!same_string(d->buddy, qPrintable(buddy))) {
		diveChanged = true;
		free(d->buddy);
		d->buddy = strdup(qPrintable(buddy));
	}
	if (!same_string(d->divemaster, qPrintable(diveMaster))) {
		diveChanged = true;
		free(d->divemaster);
		d->divemaster = strdup(qPrintable(diveMaster));
	}
	if (!same_string(d->notes, qPrintable(notes))) {
		diveChanged = true;
		free(d->notes);
		d->notes = strdup(qPrintable(notes));
	}
	// now that we have it all figured out, let's see what we need
	// to update
	DiveListModel *dm = DiveListModel::instance();
	int oldModelIdx = dm->getDiveIdx(d->id);
	int oldIdx = get_idx_by_uniq_id(d->id);
	if (needResort) {
		// we know that the only thing that might happen in a resort is that
		// this one dive moves to a different spot in the dive list
		sort_table(&dive_table);
		int newIdx = get_idx_by_uniq_id(d->id);
		if (newIdx != oldIdx) {
			DiveObjectHelper *newDive = new DiveObjectHelper(d);
			DiveListModel::instance()->removeDive(oldModelIdx);
			DiveListModel::instance()->insertDive(oldModelIdx - (newIdx - oldIdx), newDive);
			diveChanged = false; // because we already modified things
		}
	}
	if (diveChanged) {
		if (d->maxdepth.mm == d->dc.maxdepth.mm &&
		    d->maxdepth.mm > 0 &&
		    same_string(d->dc.model, "manually added dive") &&
		    d->dc.samples == 0) {
			// so we have depth > 0, a manually added dive and no samples
			// let's create an actual profile so the desktop version can work it
			// first clear out the mean depth (or the fake_dc() function tries
			// to be too clever
			d->meandepth.mm = d->dc.meandepth.mm = 0;
			d->dc = *fake_dc(&d->dc, true);
		}
		DiveListModel::instance()->updateDive(oldModelIdx, d);
	}
	if (diveChanged || needResort)
		// we no longer save right away, but only the next time the app is not
		// in the foreground (or when explicitly requested)
		mark_divelist_changed(true);

}