Add unit-aware cylinder size string parserc

Whittling down on the string parsing that doesn't check user-specified
units.  Still need to handle temperatures (and will do percentages to
match the pattern too), but this is getting us closer to always honoring
user-specified units.

With this you can say that you have a "10l" cylinder at "3000psi", and
it will do the right thing (it's basically a 72 cuft cylinder in
imperial measurements).

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Linus Torvalds 2014-01-09 10:34:25 +08:00 committed by Dirk Hohndel
parent 39fb3b2c13
commit a79ddde1b9
2 changed files with 41 additions and 22 deletions

1
dive.h
View file

@ -802,6 +802,7 @@ extern double strtod_flags(const char *str, const char **ptr, unsigned int flags
extern weight_t string_to_weight(const char *str); extern weight_t string_to_weight(const char *str);
extern depth_t string_to_depth(const char *str); extern depth_t string_to_depth(const char *str);
extern pressure_t string_to_pressure(const char *str); extern pressure_t string_to_pressure(const char *str);
extern volume_t string_to_volume(const char *str, pressure_t workp);
#include "pref.h" #include "pref.h"

View file

@ -206,30 +206,16 @@ bool CylindersModel::setData(const QModelIndex& index, const QVariant& value, in
} }
break; break;
case SIZE: case SIZE:
if (CHANGED(toDouble, "cuft", "l")) { if (CHANGED(data, "", "")) {
// if units are CUFT then this value is meaningless until we have working pressure
if (vString.toDouble() != 0.0) {
TankInfoModel *tanks = TankInfoModel::instance(); TankInfoModel *tanks = TankInfoModel::instance();
QModelIndexList matches = tanks->match(tanks->index(0,0), Qt::DisplayRole, cyl->type.description); QModelIndexList matches = tanks->match(tanks->index(0,0), Qt::DisplayRole, cyl->type.description);
int mbar = cyl->type.workingpressure.mbar;
int mliter;
if (mbar && prefs.units.volume == prefs.units.CUFT) { cyl->type.size = string_to_volume(vString.toUtf8().data(), cyl->type.workingpressure);
double liters = cuft_to_l(vString.toDouble());
liters /= bar_to_atm(mbar / 1000.0);
mliter = rint(liters * 1000);
} else {
mliter = rint(vString.toDouble() * 1000);
}
if (cyl->type.size.mliter != mliter) {
mark_divelist_changed(TRUE); mark_divelist_changed(TRUE);
cyl->type.size.mliter = mliter;
if (!matches.isEmpty()) if (!matches.isEmpty())
tanks->setData(tanks->index(matches.first().row(), TankInfoModel::ML), cyl->type.size.mliter); tanks->setData(tanks->index(matches.first().row(), TankInfoModel::ML), cyl->type.size.mliter);
}
changed = true; changed = true;
} }
}
break; break;
case WORKINGPRESS: case WORKINGPRESS:
if (CHANGED(data, "", "")) { if (CHANGED(data, "", "")) {
@ -513,6 +499,38 @@ psi:
return pressure; return pressure;
} }
/* Imperial cylinder volumes need working pressure to be meaningful */
volume_t string_to_volume(const char *str, pressure_t workp)
{
const char *end;
double value = strtod_flags(str, &end, 0);
QString rest = QString(end).trimmed();
QString local_l = CylindersModel::tr("l");
QString local_cuft = CylindersModel::tr("cuft");
volume_t volume;
if (rest.startsWith("l") || rest.startsWith(local_l))
goto l;
if (rest.startsWith("cuft") || rest.startsWith(local_cuft))
goto cuft;
/*
* If we don't have explicit units, and there is no working
* pressure, we're going to assume "liter" even in imperial
* measurements.
*/
if (!workp.mbar)
goto l;
if (prefs.units.volume == prefs.units.LITER)
goto l;
cuft:
if (workp.mbar)
value /= bar_to_atm(workp.mbar / 1000.0);
value = cuft_to_l(value);
l:
volume.mliter = rint(value * 1000);
return volume;
}
bool WeightModel::setData(const QModelIndex& index, const QVariant& value, int role) bool WeightModel::setData(const QModelIndex& index, const QVariant& value, int role)
{ {
QString vString = value.toString(); QString vString = value.toString();