diff --git a/CMakeLists.txt b/CMakeLists.txt index fca2b2282..9e5f9087a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -254,6 +254,7 @@ set(SUBSURFACE_MODELS_LIB_SRCS qt-models/filtermodels.cpp qt-models/tankinfomodel.cpp qt-models/weigthsysteminfomodel.cpp + qt-models/weightmodel.cpp qt-models/completionmodels.cpp ) source_group("Subsurface Models" FILES ${SUBSURFACE_MODELS}) diff --git a/qt-models/cleanertablemodel.h b/qt-models/cleanertablemodel.h index a492685a6..c47cf87f4 100644 --- a/qt-models/cleanertablemodel.h +++ b/qt-models/cleanertablemodel.h @@ -3,6 +3,10 @@ #include #include +#include + +/* Retrieve the trash icon pixmap, common to most table models */ +const QPixmap &trashIcon(); /* When using a QAbstractTableModel, consider using this instead * of the default implementation, as it's easyer to setup the columns diff --git a/qt-models/models.cpp b/qt-models/models.cpp index 5b0fc1a0f..cd62dfc67 100644 --- a/qt-models/models.cpp +++ b/qt-models/models.cpp @@ -36,289 +36,6 @@ const QPixmap &trashIcon() return trash; } -WeightModel::WeightModel(QObject *parent) : CleanerTableModel(parent), - changed(false), - rows(0) -{ - //enum Column {REMOVE, TYPE, WEIGHT}; - setHeaderDataStrings(QStringList() << tr("") << tr("Type") << tr("Weight")); -} - -weightsystem_t *WeightModel::weightSystemAt(const QModelIndex &index) -{ - return &displayed_dive.weightsystem[index.row()]; -} - -void WeightModel::remove(const QModelIndex &index) -{ - if (index.column() != REMOVE) { - return; - } - beginRemoveRows(QModelIndex(), index.row(), index.row()); // yah, know, ugly. - rows--; - remove_weightsystem(&displayed_dive, index.row()); - changed = true; - endRemoveRows(); -} - -void WeightModel::clear() -{ - if (rows > 0) { - beginRemoveRows(QModelIndex(), 0, rows - 1); - endRemoveRows(); - } -} - -QVariant WeightModel::data(const QModelIndex &index, int role) const -{ - QVariant ret; - if (!index.isValid() || index.row() >= MAX_WEIGHTSYSTEMS) - return ret; - - weightsystem_t *ws = &displayed_dive.weightsystem[index.row()]; - - switch (role) { - case Qt::FontRole: - ret = defaultModelFont(); - break; - case Qt::TextAlignmentRole: - ret = Qt::AlignCenter; - break; - case Qt::DisplayRole: - case Qt::EditRole: - switch (index.column()) { - case TYPE: - ret = gettextFromC::instance()->tr(ws->description); - break; - case WEIGHT: - ret = get_weight_string(ws->weight, true); - break; - } - break; - case Qt::DecorationRole: - if (index.column() == REMOVE) - ret = trashIcon(); - break; - case Qt::SizeHintRole: - if (index.column() == REMOVE) - ret = trashIcon().size(); - break; - case Qt::ToolTipRole: - if (index.column() == REMOVE) - ret = tr("Clicking here will remove this weight system."); - break; - } - return ret; -} - -// this is our magic 'pass data in' function that allows the delegate to get -// the data here without silly unit conversions; -// so we only implement the two columns we care about -void WeightModel::passInData(const QModelIndex &index, const QVariant &value) -{ - weightsystem_t *ws = &displayed_dive.weightsystem[index.row()]; - if (index.column() == WEIGHT) { - if (ws->weight.grams != value.toInt()) { - ws->weight.grams = value.toInt(); - dataChanged(index, index); - } - } -} -//TODO: Move to C -weight_t string_to_weight(const char *str) -{ - const char *end; - double value = strtod_flags(str, &end, 0); - QString rest = QString(end).trimmed(); - QString local_kg = QObject::tr("kg"); - QString local_lbs = QObject::tr("lbs"); - weight_t weight; - - if (rest.startsWith("kg") || rest.startsWith(local_kg)) - goto kg; - // using just "lb" instead of "lbs" is intentional - some people might enter the singular - if (rest.startsWith("lb") || rest.startsWith(local_lbs)) - goto lbs; - if (prefs.units.weight == prefs.units.LBS) - goto lbs; -kg: - weight.grams = rint(value * 1000); - return weight; -lbs: - weight.grams = lbs_to_grams(value); - return weight; -} - -//TODO: Move to C. -depth_t string_to_depth(const char *str) -{ - const char *end; - double value = strtod_flags(str, &end, 0); - QString rest = QString(end).trimmed(); - QString local_ft = QObject::tr("ft"); - QString local_m = QObject::tr("m"); - depth_t depth; - - if (rest.startsWith("m") || rest.startsWith(local_m)) - goto m; - if (rest.startsWith("ft") || rest.startsWith(local_ft)) - goto ft; - if (prefs.units.length == prefs.units.FEET) - goto ft; -m: - depth.mm = rint(value * 1000); - return depth; -ft: - depth.mm = feet_to_mm(value); - return depth; -} - -//TODO: Move to C. -pressure_t string_to_pressure(const char *str) -{ - const char *end; - double value = strtod_flags(str, &end, 0); - QString rest = QString(end).trimmed(); - QString local_psi = QObject::tr("psi"); - QString local_bar = QObject::tr("bar"); - pressure_t pressure; - - if (rest.startsWith("bar") || rest.startsWith(local_bar)) - goto bar; - if (rest.startsWith("psi") || rest.startsWith(local_psi)) - goto psi; - if (prefs.units.pressure == prefs.units.PSI) - goto psi; -bar: - pressure.mbar = rint(value * 1000); - return pressure; -psi: - pressure.mbar = psi_to_mbar(value); - return pressure; -} - -//TODO: Move to C. -/* 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 = QObject::tr("l"); - QString local_cuft = QObject::tr("cuft"); - volume_t volume; - - if (rest.startsWith("l") || rest.startsWith("ℓ") || 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; -} - -//TODO: Move to C. -fraction_t string_to_fraction(const char *str) -{ - const char *end; - double value = strtod_flags(str, &end, 0); - fraction_t fraction; - - fraction.permille = rint(value * 10); - return fraction; -} - -bool WeightModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - QString vString = value.toString(); - weightsystem_t *ws = &displayed_dive.weightsystem[index.row()]; - switch (index.column()) { - case TYPE: - if (!value.isNull()) { - //TODO: C-function weigth_system_set_description ? - if (!ws->description || gettextFromC::instance()->tr(ws->description) != vString) { - // loop over translations to see if one matches - int i = -1; - while (ws_info[++i].name) { - if (gettextFromC::instance()->tr(ws_info[i].name) == vString) { - ws->description = copy_string(ws_info[i].name); - break; - } - } - if (ws_info[i].name == NULL) // didn't find a match - ws->description = strdup(vString.toUtf8().constData()); - changed = true; - } - } - break; - case WEIGHT: - if (CHANGED()) { - ws->weight = string_to_weight(vString.toUtf8().data()); - // now update the ws_info - changed = true; - WSInfoModel *wsim = WSInfoModel::instance(); - QModelIndexList matches = wsim->match(wsim->index(0, 0), Qt::DisplayRole, gettextFromC::instance()->tr(ws->description)); - if (!matches.isEmpty()) - wsim->setData(wsim->index(matches.first().row(), WSInfoModel::GR), ws->weight.grams); - } - break; - } - dataChanged(index, index); - return true; -} - -Qt::ItemFlags WeightModel::flags(const QModelIndex &index) const -{ - if (index.column() == REMOVE) - return Qt::ItemIsEnabled; - return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; -} - -int WeightModel::rowCount(const QModelIndex &parent) const -{ - return rows; -} - -void WeightModel::add() -{ - if (rows >= MAX_WEIGHTSYSTEMS) - return; - - int row = rows; - beginInsertRows(QModelIndex(), row, row); - rows++; - changed = true; - endInsertRows(); -} - -void WeightModel::updateDive() -{ - clear(); - rows = 0; - for (int i = 0; i < MAX_WEIGHTSYSTEMS; i++) { - if (!weightsystem_none(&displayed_dive.weightsystem[i])) { - rows = i + 1; - } - } - if (rows > 0) { - beginInsertRows(QModelIndex(), 0, rows - 1); - endInsertRows(); - } -} - //################################################################################################# //# //# Tree Model - a Basic Tree Model so I don't need to kill myself repeating this for every model. diff --git a/qt-models/models.h b/qt-models/models.h index 70e34e65f..31fb2871e 100644 --- a/qt-models/models.h +++ b/qt-models/models.h @@ -21,41 +21,6 @@ #include "../divecomputer.h" #include "cleanertablemodel.h" -/* Retrieve the trash icon pixmap, common to most table models */ -const QPixmap &trashIcon(); - -/* Encapsulation of the Weight Model, that represents - * the current weights on a dive. */ -class WeightModel : public CleanerTableModel { - Q_OBJECT -public: - enum Column { - REMOVE, - TYPE, - WEIGHT - }; - - explicit WeightModel(QObject *parent = 0); - /*reimp*/ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - /*reimp*/ int rowCount(const QModelIndex &parent = QModelIndex()) const; - /*reimp*/ Qt::ItemFlags flags(const QModelIndex &index) const; - /*reimp*/ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - - void passInData(const QModelIndex &index, const QVariant &value); - void add(); - void clear(); - void updateDive(); - weightsystem_t *weightSystemAt(const QModelIndex &index); - bool changed; - -public -slots: - void remove(const QModelIndex &index); - -private: - int rows; -}; - /* extra data model for additional dive computer data */ class ExtraDataModel : public CleanerTableModel { Q_OBJECT diff --git a/qt-models/weightmodel.cpp b/qt-models/weightmodel.cpp new file mode 100644 index 000000000..88ebeff6b --- /dev/null +++ b/qt-models/weightmodel.cpp @@ -0,0 +1,174 @@ +#include "weightmodel.h" +#include "dive.h" +#include "gettextfromc.h" +#include "metrics.h" +#include "helpers.h" +#include "weigthsysteminfomodel.h" + +WeightModel::WeightModel(QObject *parent) : CleanerTableModel(parent), + changed(false), + rows(0) +{ + //enum Column {REMOVE, TYPE, WEIGHT}; + setHeaderDataStrings(QStringList() << tr("") << tr("Type") << tr("Weight")); +} + +weightsystem_t *WeightModel::weightSystemAt(const QModelIndex &index) +{ + return &displayed_dive.weightsystem[index.row()]; +} + +void WeightModel::remove(const QModelIndex &index) +{ + if (index.column() != REMOVE) { + return; + } + beginRemoveRows(QModelIndex(), index.row(), index.row()); // yah, know, ugly. + rows--; + remove_weightsystem(&displayed_dive, index.row()); + changed = true; + endRemoveRows(); +} + +void WeightModel::clear() +{ + if (rows > 0) { + beginRemoveRows(QModelIndex(), 0, rows - 1); + endRemoveRows(); + } +} + +QVariant WeightModel::data(const QModelIndex &index, int role) const +{ + QVariant ret; + if (!index.isValid() || index.row() >= MAX_WEIGHTSYSTEMS) + return ret; + + weightsystem_t *ws = &displayed_dive.weightsystem[index.row()]; + + switch (role) { + case Qt::FontRole: + ret = defaultModelFont(); + break; + case Qt::TextAlignmentRole: + ret = Qt::AlignCenter; + break; + case Qt::DisplayRole: + case Qt::EditRole: + switch (index.column()) { + case TYPE: + ret = gettextFromC::instance()->tr(ws->description); + break; + case WEIGHT: + ret = get_weight_string(ws->weight, true); + break; + } + break; + case Qt::DecorationRole: + if (index.column() == REMOVE) + ret = trashIcon(); + break; + case Qt::SizeHintRole: + if (index.column() == REMOVE) + ret = trashIcon().size(); + break; + case Qt::ToolTipRole: + if (index.column() == REMOVE) + ret = tr("Clicking here will remove this weight system."); + break; + } + return ret; +} + +// this is our magic 'pass data in' function that allows the delegate to get +// the data here without silly unit conversions; +// so we only implement the two columns we care about +void WeightModel::passInData(const QModelIndex &index, const QVariant &value) +{ + weightsystem_t *ws = &displayed_dive.weightsystem[index.row()]; + if (index.column() == WEIGHT) { + if (ws->weight.grams != value.toInt()) { + ws->weight.grams = value.toInt(); + dataChanged(index, index); + } + } +} + + +bool WeightModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + QString vString = value.toString(); + weightsystem_t *ws = &displayed_dive.weightsystem[index.row()]; + switch (index.column()) { + case TYPE: + if (!value.isNull()) { + //TODO: C-function weigth_system_set_description ? + if (!ws->description || gettextFromC::instance()->tr(ws->description) != vString) { + // loop over translations to see if one matches + int i = -1; + while (ws_info[++i].name) { + if (gettextFromC::instance()->tr(ws_info[i].name) == vString) { + ws->description = copy_string(ws_info[i].name); + break; + } + } + if (ws_info[i].name == NULL) // didn't find a match + ws->description = strdup(vString.toUtf8().constData()); + changed = true; + } + } + break; + case WEIGHT: + if (CHANGED()) { + ws->weight = string_to_weight(vString.toUtf8().data()); + // now update the ws_info + changed = true; + WSInfoModel *wsim = WSInfoModel::instance(); + QModelIndexList matches = wsim->match(wsim->index(0, 0), Qt::DisplayRole, gettextFromC::instance()->tr(ws->description)); + if (!matches.isEmpty()) + wsim->setData(wsim->index(matches.first().row(), WSInfoModel::GR), ws->weight.grams); + } + break; + } + dataChanged(index, index); + return true; +} + +Qt::ItemFlags WeightModel::flags(const QModelIndex &index) const +{ + if (index.column() == REMOVE) + return Qt::ItemIsEnabled; + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; +} + +int WeightModel::rowCount(const QModelIndex &parent) const +{ + return rows; +} + +void WeightModel::add() +{ + if (rows >= MAX_WEIGHTSYSTEMS) + return; + + int row = rows; + beginInsertRows(QModelIndex(), row, row); + rows++; + changed = true; + endInsertRows(); +} + +void WeightModel::updateDive() +{ + clear(); + rows = 0; + for (int i = 0; i < MAX_WEIGHTSYSTEMS; i++) { + if (!weightsystem_none(&displayed_dive.weightsystem[i])) { + rows = i + 1; + } + } + if (rows > 0) { + beginInsertRows(QModelIndex(), 0, rows - 1); + endInsertRows(); + } +} diff --git a/qt-models/weightmodel.h b/qt-models/weightmodel.h new file mode 100644 index 000000000..5ab67e592 --- /dev/null +++ b/qt-models/weightmodel.h @@ -0,0 +1,39 @@ +#ifndef WEIGHTMODEL_H +#define WEIGHTMODEL_H + +#include "cleanertablemodel.h" +#include "dive.h" + +/* Encapsulation of the Weight Model, that represents + * the current weights on a dive. */ +class WeightModel : public CleanerTableModel { + Q_OBJECT +public: + enum Column { + REMOVE, + TYPE, + WEIGHT + }; + + explicit WeightModel(QObject *parent = 0); + /*reimp*/ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + /*reimp*/ int rowCount(const QModelIndex &parent = QModelIndex()) const; + /*reimp*/ Qt::ItemFlags flags(const QModelIndex &index) const; + /*reimp*/ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + void passInData(const QModelIndex &index, const QVariant &value); + void add(); + void clear(); + void updateDive(); + weightsystem_t *weightSystemAt(const QModelIndex &index); + bool changed; + +public +slots: + void remove(const QModelIndex &index); + +private: + int rows; +}; + +#endif diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index 0159029e2..c0330fde4 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -18,6 +18,7 @@ #include "diveplanner.h" #include "divesitehelpers.h" #include "cylindermodel.h" +#include "weightmodel.h" #if defined(FBSUPPORT) #include "socialnetworks.h" diff --git a/qt-ui/modeldelegates.cpp b/qt-ui/modeldelegates.cpp index 783fcc225..84d2db1d5 100644 --- a/qt-ui/modeldelegates.cpp +++ b/qt-ui/modeldelegates.cpp @@ -8,7 +8,7 @@ #include "profile/profilewidget2.h" #include "tankinfomodel.h" #include "weigthsysteminfomodel.h" - +#include "weightmodel.h" #include #include #include diff --git a/qthelper.cpp b/qthelper.cpp index 16354e34b..baed6d29c 100644 --- a/qthelper.cpp +++ b/qthelper.cpp @@ -909,3 +909,114 @@ QString get_divepoint_gas_string(const divedatapoint &p) { return get_gas_string(p.gasmix); } + +weight_t string_to_weight(const char *str) +{ + const char *end; + double value = strtod_flags(str, &end, 0); + QString rest = QString(end).trimmed(); + QString local_kg = QObject::tr("kg"); + QString local_lbs = QObject::tr("lbs"); + weight_t weight; + + if (rest.startsWith("kg") || rest.startsWith(local_kg)) + goto kg; + // using just "lb" instead of "lbs" is intentional - some people might enter the singular + if (rest.startsWith("lb") || rest.startsWith(local_lbs)) + goto lbs; + if (prefs.units.weight == prefs.units.LBS) + goto lbs; +kg: + weight.grams = rint(value * 1000); + return weight; +lbs: + weight.grams = lbs_to_grams(value); + return weight; +} + +depth_t string_to_depth(const char *str) +{ + const char *end; + double value = strtod_flags(str, &end, 0); + QString rest = QString(end).trimmed(); + QString local_ft = QObject::tr("ft"); + QString local_m = QObject::tr("m"); + depth_t depth; + + if (rest.startsWith("m") || rest.startsWith(local_m)) + goto m; + if (rest.startsWith("ft") || rest.startsWith(local_ft)) + goto ft; + if (prefs.units.length == prefs.units.FEET) + goto ft; +m: + depth.mm = rint(value * 1000); + return depth; +ft: + depth.mm = feet_to_mm(value); + return depth; +} + +pressure_t string_to_pressure(const char *str) +{ + const char *end; + double value = strtod_flags(str, &end, 0); + QString rest = QString(end).trimmed(); + QString local_psi = QObject::tr("psi"); + QString local_bar = QObject::tr("bar"); + pressure_t pressure; + + if (rest.startsWith("bar") || rest.startsWith(local_bar)) + goto bar; + if (rest.startsWith("psi") || rest.startsWith(local_psi)) + goto psi; + if (prefs.units.pressure == prefs.units.PSI) + goto psi; +bar: + pressure.mbar = rint(value * 1000); + return pressure; +psi: + pressure.mbar = psi_to_mbar(value); + return pressure; +} + +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 = QObject::tr("l"); + QString local_cuft = QObject::tr("cuft"); + volume_t volume; + + if (rest.startsWith("l") || rest.startsWith("ℓ") || 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; +} + +fraction_t string_to_fraction(const char *str) +{ + const char *end; + double value = strtod_flags(str, &end, 0); + fraction_t fraction; + + fraction.permille = rint(value * 10); + return fraction; +} diff --git a/qthelper.h b/qthelper.h index 0b1e3b111..310133f36 100644 --- a/qthelper.h +++ b/qthelper.h @@ -27,4 +27,10 @@ void add_hash(const QString filename, QByteArray hash); QString localFilePath(const QString originalFilename); QString fileFromHash(char *hash); void learnHash(struct picture *picture, QByteArray hash); +weight_t string_to_weight(const char *str); +depth_t string_to_depth(const char *str); +pressure_t string_to_pressure(const char *str); +volume_t string_to_volume(const char *str, pressure_t workp); +fraction_t string_to_fraction(const char *str); + #endif // QTHELPER_H