void DiveLogExportDialog::exportHTMLstatistics(const QString &filename)
{
	QFile file(filename);
	file.open(QIODevice::WriteOnly | QIODevice::Text);
	QTextStream out(&file);
	int i = 0;
	out << "divestat=[";
	while (stats_yearly != NULL && stats_yearly[i].period) {
		out << "{";
		out << "\"YEAR\":\"" << stats_yearly[i].period << "\",";
		out << "\"DIVES\":\"" << stats_yearly[i].selection_size << "\",";
		out << "\"TOTAL_TIME\":\"" << get_time_string(stats_yearly[i].total_time.seconds, 0) << "\",";
		out << "\"AVERAGE_TIME\":\"" << get_minutes(stats_yearly[i].total_time.seconds / stats_yearly[i].selection_size) << "\",";
		out << "\"SHORTEST_TIME\":\"" << get_minutes(stats_yearly[i].shortest_time.seconds) << "\",";
		out << "\"LONGEST_TIME\":\"" << get_minutes(stats_yearly[i].longest_time.seconds) << "\",";
		out << "\"AVG_DEPTH\":\"" << get_depth_string(stats_yearly[i].avg_depth) << "\",";
		out << "\"MIN_DEPTH\":\"" << get_depth_string(stats_yearly[i].min_depth) << "\",";
		out << "\"MAX_DEPTH\":\"" << get_depth_string(stats_yearly[i].max_depth) << "\",";
		out << "\"AVG_SAC\":\"" << get_volume_string(stats_yearly[i].avg_sac) << "\",";
		out << "\"MIN_SAC\":\"" << get_volume_string(stats_yearly[i].min_sac) << "\",";
		out << "\"MAX_SAC\":\"" << get_volume_string(stats_yearly[i].max_sac) << "\",";
		out << "\"AVG_TEMP\":\"" << QString::number(stats_yearly[i].combined_temp / stats_yearly[i].combined_count, 'f', 1) << "\",";
		out << "\"MIN_TEMP\":\"" << get_temp_units(stats_yearly[i].min_temp, NULL) << "\",";
		out << "\"MAX_TEMP\":\"" << get_temp_units(stats_yearly[i].max_temp, NULL) << "\",";
		out << "},";
		i++;
	}
	out << "]";
	file.close();
}
static void exportHTMLstatistics(const QString filename, struct htmlExportSetting &hes)
{
	QFile file(filename);
	file.open(QIODevice::WriteOnly | QIODevice::Text);
	QTextStream out(&file);
	stats_summary_auto_free stats;

	stats_t total_stats;

	calculate_stats_summary(&stats, hes.selectedOnly);
	total_stats.selection_size = 0;
	total_stats.total_time.seconds = 0;

	int i = 0;
	out << "divestat=[";
	if (hes.yearlyStatistics) {
		while (stats.stats_yearly != NULL && stats.stats_yearly[i].period) {
			out << "{";
			out << "\"YEAR\":\"" << stats.stats_yearly[i].period << "\",";
			out << "\"DIVES\":\"" << stats.stats_yearly[i].selection_size << "\",";
			out << "\"TOTAL_TIME\":\"" << get_dive_duration_string(stats.stats_yearly[i].total_time.seconds,
											gettextFromC::tr("h"), gettextFromC::tr("min"), gettextFromC::tr("sec"), " ") << "\",";
			out << "\"AVERAGE_TIME\":\"" << get_minutes(stats.stats_yearly[i].total_time.seconds / stats.stats_yearly[i].selection_size) << "\",";
			out << "\"SHORTEST_TIME\":\"" << get_minutes(stats.stats_yearly[i].shortest_time.seconds) << "\",";
			out << "\"LONGEST_TIME\":\"" << get_minutes(stats.stats_yearly[i].longest_time.seconds) << "\",";
			out << "\"AVG_DEPTH\":\"" << get_depth_string(stats.stats_yearly[i].avg_depth) << "\",";
			out << "\"MIN_DEPTH\":\"" << get_depth_string(stats.stats_yearly[i].min_depth) << "\",";
			out << "\"MAX_DEPTH\":\"" << get_depth_string(stats.stats_yearly[i].max_depth) << "\",";
			out << "\"AVG_SAC\":\"" << get_volume_string(stats.stats_yearly[i].avg_sac) << "\",";
			out << "\"MIN_SAC\":\"" << get_volume_string(stats.stats_yearly[i].min_sac) << "\",";
			out << "\"MAX_SAC\":\"" << get_volume_string(stats.stats_yearly[i].max_sac) << "\",";
			if (stats.stats_yearly[i].combined_count) {
				temperature_t avg_temp;
				avg_temp.mkelvin = stats.stats_yearly[i].combined_temp.mkelvin / stats.stats_yearly[i].combined_count;
				out << "\"AVG_TEMP\":\"" << get_temperature_string(avg_temp) << "\",";
			} else {
				out << "\"AVG_TEMP\":\"0.0\",";
			}
			out << "\"MIN_TEMP\":\"" << (stats.stats_yearly[i].min_temp.mkelvin == 0 ? 0 : get_temperature_string(stats.stats_yearly[i].min_temp)) << "\",";
			out << "\"MAX_TEMP\":\"" << (stats.stats_yearly[i].max_temp.mkelvin == 0 ? 0 : get_temperature_string(stats.stats_yearly[i].max_temp)) << "\",";
			out << "},";
			total_stats.selection_size += stats.stats_yearly[i].selection_size;
			total_stats.total_time.seconds += stats.stats_yearly[i].total_time.seconds;
			i++;
		}
		exportHTMLstatisticsTotal(out, &total_stats);
	}
	out << "]";
	file.close();

}
Beispiel #3
0
QVariant YearStatisticsItem::data(int column, int role) const
{
	double value;
	QVariant ret;

	if (role == Qt::FontRole) {
		QFont font = defaultModelFont();
		font.setBold(stats_interval.is_year);
		return font;
	} else if (role != Qt::DisplayRole) {
		return ret;
	}
	switch(column) {
	case YEAR:
		if (stats_interval.is_trip) {
			ret = stats_interval.location;
		} else {
			ret =  stats_interval.period;
		}
		break;
	case DIVES:		ret =  stats_interval.selection_size; break;
	case TOTAL_TIME:	ret = get_time_string(stats_interval.total_time.seconds, 0); break;
	case AVERAGE_TIME:	ret = get_minutes(stats_interval.total_time.seconds / stats_interval.selection_size); break;
	case SHORTEST_TIME:	ret = get_minutes(stats_interval.shortest_time.seconds); break;
	case LONGEST_TIME:	ret = get_minutes(stats_interval.longest_time.seconds); break;
	case AVG_DEPTH:		ret = get_depth_string(stats_interval.avg_depth); break;
	case MIN_DEPTH:		ret = get_depth_string(stats_interval.min_depth); break;
	case MAX_DEPTH:		ret = get_depth_string(stats_interval.max_depth); break;
	case AVG_SAC:		ret = get_volume_string(stats_interval.avg_sac); break;
	case MIN_SAC:		ret = get_volume_string(stats_interval.min_sac); break;
	case MAX_SAC:		ret = get_volume_string(stats_interval.max_sac); break;
	case AVG_TEMP:
		if (stats_interval.combined_temp && stats_interval.combined_count) {
			ret = QString::number(stats_interval.combined_temp / stats_interval.combined_count, 'f', 1);
		}
		break;
	case MIN_TEMP:
		value = get_temp_units(stats_interval.min_temp, NULL);
		if (value > -100.0)
			ret =  QString::number(value, 'f', 1);
		break;
	case MAX_TEMP:
		value = get_temp_units(stats_interval.max_temp, NULL);
		if (value > -100.0)
			ret =  QString::number(value, 'f', 1);
		break;
	}
	return ret;
}
MobileDive::MobileDive(dive *d)
{
	m_thisDive = d;
	setDiveNumber(QString::number(d->number));
	setDiveId(QString::number(d->id));

	dive_trip *trip = d->divetrip;

	if(trip) {
		//trip is valid
		setTrip(trip->location);
	}

	setDate(get_dive_date_string(d->when));
	setDepth(get_depth_string(d->maxdepth));
	setDuration(get_dive_duration_string(d->duration.seconds, "h:","min"));

	setupDiveTempDetails();

	weight_t tw = { total_weight(d) };
	setWeight(weight_string(tw.grams));

	setSuit(QString(d->suit));
	setCylinder(QString(d->cylinder[0].type.description));
	setSac(QString::number(d->sac));
	setLocation(get_dive_location(d));
	setNotes(d->notes);
	setBuddy(d->buddy);
	setDivemaster(d->divemaster);
}
void DiveProfileItem::plot_depth_sample(struct plot_data *entry, QFlags<Qt::AlignmentFlag> flags, const QColor &color)
{
	DiveTextItem *item = new DiveTextItem(this);
	item->setPos(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->depth));
	item->setText(get_depth_string(entry->depth, true));
	item->setAlignment(flags);
	item->setBrush(color);
	texts.append(item);
}
void DiveMeanDepthItem::createTextItem() {
	plot_data *entry = dataModel->data().entry;
	int sec = entry[dataModel->rowCount()-1].sec;
	qDeleteAll(texts);
	texts.clear();
	DiveTextItem *text = new DiveTextItem(this);
	text->setAlignment(Qt::AlignRight | Qt::AlignTop);
	text->setBrush(getColor(TEMP_TEXT));
	text->setPos(QPointF(hAxis->posAtValue(sec) + 1, vAxis->posAtValue(lastRunningSum)));
	text->setScale(0.8); // need to call this BEFORE setText()
	text->setText(get_depth_string(lrint(lastRunningSum), true));
	texts.append(text);
}
QVariant DiveImportedModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();

	if (index.row() + firstIndex > lastIndex)
		return QVariant();

	struct dive *d = get_dive_from_table(index.row() + firstIndex, diveTable);
	if (!d)
		return QVariant();

	// widgets access the model via index.column(), qml via role.
	int column = index.column();
	if (role >= DateTime) {
		column = role - DateTime;
		role = Qt::DisplayRole;
	}

	if (role == Qt::DisplayRole) {
		switch (column) {
		case 0:
			return QVariant(get_short_dive_date_string(d->when));
		case 1:
			return QVariant(get_dive_duration_string(d->duration.seconds, tr("h"), tr("min")));
		case 2:
			return QVariant(get_depth_string(d->maxdepth.mm, true, false));
		case 3:
			return checkStates[index.row()];
		}
	}
	if (role == Qt::CheckStateRole) {
		if (index.column() == 0)
			return checkStates[index.row()] ? Qt::Checked : Qt::Unchecked;
	}
	return QVariant();
}
void MeanDepthLine::setMeanDepth(int value)
{
	leftText->setText(get_depth_string(value, true, true));
	rightText->setText(get_depth_string(value, true, true));
	meanDepth = value;
}
QString DiveItem::displayDepthWithUnit() const
{
	struct dive *dive = get_dive_by_uniq_id(diveId);
	return get_depth_string(dive->maxdepth, true);
}
void Dive::put_depth()
{
	m_depth = get_depth_string(dive->dc.maxdepth.mm, true, true);
}
void TabDiveStatistics::updateData()
{
	clear();
	ui->depthLimits->setMaximum(get_depth_string(stats_selection.max_depth, true));
	if (amount_selected > 1)
		ui->depthLimits->setMinimum(get_depth_string(stats_selection.min_depth, true));
	else
		ui->depthLimits->setMinimum("");
	// the overall average depth is really confusing when listed between the
	// deepest and shallowest dive - let's just not set it
	// ui->depthLimits->setAverage(get_depth_string(stats_selection.avg_depth, true));

	// Also hide the avgIco, so its clear that its not there.
	ui->depthLimits->overrideAvgToolTipText("");
	ui->depthLimits->setAvgVisibility(false);

	if (stats_selection.max_sac.mliter && (stats_selection.max_sac.mliter != stats_selection.avg_sac.mliter))
		ui->sacLimits->setMaximum(get_volume_string(stats_selection.max_sac, true).append(tr("/min")));
	else
		ui->sacLimits->setMaximum("");
	if (stats_selection.min_sac.mliter && (stats_selection.min_sac.mliter != stats_selection.avg_sac.mliter))
		ui->sacLimits->setMinimum(get_volume_string(stats_selection.min_sac, true).append(tr("/min")));
	else
		ui->sacLimits->setMinimum("");
	if (stats_selection.avg_sac.mliter)
		ui->sacLimits->setAverage(get_volume_string(stats_selection.avg_sac, true).append(tr("/min")));
	else
		ui->sacLimits->setAverage("");

	temperature_t temp;
	temp.mkelvin = stats_selection.max_temp;
	ui->tempLimits->setMaximum(get_temperature_string(temp, true));
	temp.mkelvin = stats_selection.min_temp;
	ui->tempLimits->setMinimum(get_temperature_string(temp, true));
	if (stats_selection.combined_temp && stats_selection.combined_count) {
		const char *unit;
		get_temp_units(0, &unit);
		ui->tempLimits->setAverage(QString("%1%2").arg(stats_selection.combined_temp / stats_selection.combined_count, 0, 'f', 1).arg(unit));
	}


	ui->divesAllText->setText(QString::number(stats_selection.selection_size));
	ui->totalTimeAllText->setText(get_dive_duration_string(stats_selection.total_time.seconds, tr("h"), tr("min"), tr("sec"),
		" ", displayed_dive.dc.divemode == FREEDIVE));
	
	int seconds = stats_selection.total_time.seconds;
	if (stats_selection.selection_size)
		seconds /= stats_selection.selection_size;
	ui->timeLimits->setAverage(get_dive_duration_string(seconds, tr("h"), tr("min"), tr("sec"),
			" ", displayed_dive.dc.divemode == FREEDIVE));
	if (amount_selected > 1) {
		ui->timeLimits->setMaximum(get_dive_duration_string(stats_selection.longest_time.seconds, tr("h"), tr("min"), tr("sec"),
			" ", displayed_dive.dc.divemode == FREEDIVE));
		ui->timeLimits->setMinimum(get_dive_duration_string(stats_selection.shortest_time.seconds, tr("h"), tr("min"), tr("sec"),
			" ", displayed_dive.dc.divemode == FREEDIVE));
	} else {
		ui->timeLimits->setMaximum("");
		ui->timeLimits->setMinimum("");
	}

	QVector<QPair<QString, int> > gasUsed;
	QString gasUsedString;
	volume_t vol;
	selectedDivesGasUsed(gasUsed);
	for (int j = 0; j < 20; j++) {
		if (gasUsed.isEmpty())
			break;
		QPair<QString, int> gasPair = gasUsed.last();
		gasUsed.pop_back();
		vol.mliter = gasPair.second;
		gasUsedString.append(gasPair.first).append(": ").append(get_volume_string(vol, true)).append("\n");
	}
	if (!gasUsed.isEmpty())
		gasUsedString.append("...");
	volume_t o2_tot = {}, he_tot = {};
	selected_dives_gas_parts(&o2_tot, &he_tot);

	/* No need to show the gas mixing information if diving
		* with pure air, and only display the he / O2 part when
		* it is used.
		*/
	if (he_tot.mliter || o2_tot.mliter) {
		gasUsedString.append(tr("These gases could be\nmixed from Air and using:\n"));
		if (he_tot.mliter) {
			gasUsedString.append(tr("He"));
			gasUsedString.append(QString(": %1").arg(get_volume_string(he_tot, true)));
		}
		if (he_tot.mliter && o2_tot.mliter)
			gasUsedString.append(" ").append(tr("and")).append(" ");
		if (o2_tot.mliter) {
			gasUsedString.append(tr("O₂"));
			gasUsedString.append(QString(": %2\n").arg(get_volume_string(o2_tot, true)));
		}
	}
	ui->gasConsumption->setText(gasUsedString);
}
Beispiel #12
0
QVariant CylindersModel::data(const QModelIndex &index, int role) const
{
	QVariant ret;

	if (!index.isValid() || index.row() >= MAX_CYLINDERS)
		return ret;

	cylinder_t *cyl = &displayed_dive.cylinder[index.row()];
	switch (role) {
	case Qt::BackgroundRole: {
		switch (index.column()) {
		// mark the cylinder start / end pressure in red if the values
		// seem implausible
		case START:
		case END:
			if ((cyl->start.mbar && !cyl->end.mbar) ||
			    (cyl->end.mbar && cyl->start.mbar <= cyl->end.mbar))
				ret = REDORANGE1_HIGH_TRANS;
			else
				ret = WHITE1;
			break;
		}
		break;
	}
	case Qt::FontRole: {
		QFont font = defaultModelFont();
		switch (index.column()) {
		case START:
			font.setItalic(!cyl->start.mbar);
			break;
		case END:
			font.setItalic(!cyl->end.mbar);
			break;
		}
		ret = font;
		break;
	}
	case Qt::TextAlignmentRole:
		ret = Qt::AlignCenter;
		break;
	case Qt::DisplayRole:
	case Qt::EditRole:
		switch (index.column()) {
		case TYPE:
			ret = QString(cyl->type.description);
			break;
		case SIZE:
			if (cyl->type.size.mliter)
				ret = get_volume_string(cyl->type.size, true, cyl->type.workingpressure.mbar);
			break;
		case WORKINGPRESS:
			if (cyl->type.workingpressure.mbar)
				ret = get_pressure_string(cyl->type.workingpressure, true);
			break;
		case START:
			if (cyl->start.mbar)
				ret = get_pressure_string(cyl->start, true);
			else if (cyl->sample_start.mbar)
				ret = get_pressure_string(cyl->sample_start, true);
			break;
		case END:
			if (cyl->end.mbar)
				ret = get_pressure_string(cyl->end, true);
			else if (cyl->sample_end.mbar)
				ret = get_pressure_string(cyl->sample_end, true);
			break;
		case O2:
			ret = percent_string(cyl->gasmix.o2);
			break;
		case HE:
			ret = percent_string(cyl->gasmix.he);
			break;
		case DEPTH:
			ret = get_depth_string(cyl->depth, true);
			break;
		}
		break;
	case Qt::DecorationRole:
		if (index.column() == REMOVE)
			ret = QIcon(":trash");
		break;

	case Qt::ToolTipRole:
		if (index.column() == REMOVE)
			ret = tr("Clicking here will remove this cylinder.");
		break;
	}

	return ret;
}
Beispiel #13
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);

}
Beispiel #14
0
QString get_depth_string(depth_t depth, bool showunit, bool showdecimal)
{
	return get_depth_string(depth.mm, showunit, showdecimal);
}