diff options
-rw-r--r-- | core/filterconstraint.cpp | 14 | ||||
-rw-r--r-- | core/filterconstraint.h | 1 | ||||
-rw-r--r-- | packaging/ios/Subsurface-mobile.pro | 2 | ||||
-rw-r--r-- | qt-models/CMakeLists.txt | 2 | ||||
-rw-r--r-- | qt-models/filterconstraintmodel.cpp | 186 | ||||
-rw-r--r-- | qt-models/filterconstraintmodel.h | 58 |
6 files changed, 261 insertions, 2 deletions
diff --git a/core/filterconstraint.cpp b/core/filterconstraint.cpp index b0a8b43aa..4bddc7b53 100644 --- a/core/filterconstraint.cpp +++ b/core/filterconstraint.cpp @@ -19,7 +19,8 @@ enum filter_constraint_units { FILTER_CONSTRAINT_DURATION_UNIT, FILTER_CONSTRAINT_TEMPERATURE_UNIT, FILTER_CONSTRAINT_WEIGHT_UNIT, - FILTER_CONSTRAINT_VOLUMETRIC_FLOW_UNIT + FILTER_CONSTRAINT_VOLUMETRIC_FLOW_UNIT, + FILTER_CONSTRAINT_DENSITY_UNIT }; static struct type_description { @@ -52,6 +53,7 @@ static struct type_description { { FILTER_CONSTRAINT_WEIGHT, "weight", QT_TRANSLATE_NOOP("gettextFromC", "weight"), false, true, false, FILTER_CONSTRAINT_WEIGHT_UNIT, 1, false, false }, { FILTER_CONSTRAINT_WATER_TEMP, "water_temp", QT_TRANSLATE_NOOP("gettextFromC", "water temp."), false, true, false, FILTER_CONSTRAINT_TEMPERATURE_UNIT, 1, false, false }, { FILTER_CONSTRAINT_AIR_TEMP, "air_temp", QT_TRANSLATE_NOOP("gettextFromC", "air temp."), false, true, false, FILTER_CONSTRAINT_TEMPERATURE_UNIT, 1, false, false }, + { FILTER_CONSTRAINT_WATER_DENSITY, "water_density", QT_TRANSLATE_NOOP("gettextFromC", "water density"), false, true, false, FILTER_CONSTRAINT_DENSITY_UNIT, 1, false, false }, { FILTER_CONSTRAINT_SAC, "sac", QT_TRANSLATE_NOOP("gettextFromC", "SAC"), false, true, false, FILTER_CONSTRAINT_VOLUMETRIC_FLOW_UNIT, 1, false, false }, { FILTER_CONSTRAINT_LOGGED, "logged", QT_TRANSLATE_NOOP("gettextFromC", "logged"), false, false, false, FILTER_CONSTRAINT_NO_UNIT, 0, false, false }, @@ -279,6 +281,8 @@ QString filter_constraint_get_unit(enum filter_constraint_type type) return get_weight_unit(); case FILTER_CONSTRAINT_VOLUMETRIC_FLOW_UNIT: return get_volume_unit() + "/min"; + case FILTER_CONSTRAINT_DENSITY_UNIT: + return "g/ℓ"; } } @@ -301,6 +305,8 @@ static int display_to_base_unit(double f, enum filter_constraint_type type) return prefs.units.weight == units::KG ? lrint(f * 1000.0) : lbs_to_grams(f); case FILTER_CONSTRAINT_VOLUMETRIC_FLOW_UNIT: return prefs.units.volume == units::LITER ? lrint(f * 1000.0) : lrint(cuft_to_l(f) * 1000.0); + case FILTER_CONSTRAINT_DENSITY_UNIT: + return lrint(f * 10.0); // Yippie, only "sane" units for density (g/l) } } @@ -323,6 +329,8 @@ static double base_to_display_unit(int i, enum filter_constraint_type type) return prefs.units.weight == units::KG ? (double)i / 1000.0 : grams_to_lbs(i); case FILTER_CONSTRAINT_VOLUMETRIC_FLOW_UNIT: return prefs.units.volume == units::LITER ? (double)i / 1000.0 : ml_to_cuft(i); + case FILTER_CONSTRAINT_DENSITY_UNIT: + return (double)i / 10.0; // Yippie, only "sane" units for density (g/l) } } @@ -445,7 +453,7 @@ extern "C" bool filter_constraint_has_time_widget(filter_constraint_type type) extern "C" int filter_constraint_num_decimals(enum filter_constraint_type type) { const type_description *desc = get_type_description(type); - return desc && desc->decimal_places; + return desc ? desc->decimal_places : 1; } // String constraints are valid if there is at least one term. @@ -1028,6 +1036,8 @@ bool filter_constraint_match_dive(const filter_constraint &c, const struct dive return check_numerical_range(c, d->watertemp.mkelvin); case FILTER_CONSTRAINT_AIR_TEMP: return check_numerical_range(c, d->airtemp.mkelvin); + case FILTER_CONSTRAINT_WATER_DENSITY: + return check_numerical_range(c, d->user_salinity ? d->user_salinity : d->salinity); case FILTER_CONSTRAINT_SAC: return check_numerical_range_non_zero(c, d->sac); case FILTER_CONSTRAINT_LOGGED: diff --git a/core/filterconstraint.h b/core/filterconstraint.h index 0a9621a86..d6596d09d 100644 --- a/core/filterconstraint.h +++ b/core/filterconstraint.h @@ -32,6 +32,7 @@ enum filter_constraint_type { FILTER_CONSTRAINT_WEIGHT, FILTER_CONSTRAINT_WATER_TEMP, FILTER_CONSTRAINT_AIR_TEMP, + FILTER_CONSTRAINT_WATER_DENSITY, FILTER_CONSTRAINT_SAC, FILTER_CONSTRAINT_LOGGED, FILTER_CONSTRAINT_PLANNED, diff --git a/packaging/ios/Subsurface-mobile.pro b/packaging/ios/Subsurface-mobile.pro index 68fc0ac4c..fb915a56b 100644 --- a/packaging/ios/Subsurface-mobile.pro +++ b/packaging/ios/Subsurface-mobile.pro @@ -144,6 +144,7 @@ SOURCES += ../../subsurface-mobile-main.cpp \ ../../qt-models/tankinfomodel.cpp \ ../../qt-models/models.cpp \ ../../qt-models/weightsysteminfomodel.cpp \ + ../../qt-models/filterconstraintmodel.cpp \ ../../profile-widget/qmlprofile.cpp \ ../../profile-widget/divecartesianaxis.cpp \ ../../profile-widget/diveeventitem.cpp \ @@ -293,6 +294,7 @@ HEADERS += \ ../../qt-models/tankinfomodel.h \ ../../qt-models/models.h \ ../../qt-models/weightsysteminfomodel.h \ + ../../qt-models/filterconstraintmodel.h \ ../../profile-widget/qmlprofile.h \ ../../profile-widget/diveprofileitem.h \ ../../profile-widget/profilewidget2.h \ diff --git a/qt-models/CMakeLists.txt b/qt-models/CMakeLists.txt index 8d88e0712..280abbd41 100644 --- a/qt-models/CMakeLists.txt +++ b/qt-models/CMakeLists.txt @@ -19,6 +19,8 @@ set(SUBSURFACE_GENERIC_MODELS_LIB_SRCS diveplotdatamodel.h divetripmodel.cpp divetripmodel.h + filterconstraintmodel.cpp + filterconstraintmodel.h maplocationmodel.cpp maplocationmodel.h models.cpp diff --git a/qt-models/filterconstraintmodel.cpp b/qt-models/filterconstraintmodel.cpp new file mode 100644 index 000000000..8ccc23d81 --- /dev/null +++ b/qt-models/filterconstraintmodel.cpp @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "filterconstraintmodel.h" +#include "core/qthelper.h" // for timestamp conversions +#include <QTime> + +FilterConstraintModel::~FilterConstraintModel() +{ +} + +// QTime <-> seconds in integer conversion functions +static QTime secondsToTime(int seconds) +{ + return QTime::fromMSecsSinceStartOfDay(seconds * 1000); +} + +static int timeToSeconds(const QTime &t) +{ + return t.msecsSinceStartOfDay() / 1000; +} + +QVariant FilterConstraintModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= (int)constraints.size()) + return QVariant(); + + const filter_constraint &constraint = constraints[index.row()]; + + switch (role) { + case TYPE_ROLE: + return constraint.type; + case IS_STAR_WIDGET_ROLE: + return filter_constraint_is_star(constraint.type); + case HAS_DATE_WIDGET_ROLE: + return filter_constraint_has_date_widget(constraint.type); + case HAS_TIME_WIDGET_ROLE: + return filter_constraint_has_time_widget(constraint.type); + case NUM_DECIMALS_ROLE: + return filter_constraint_num_decimals(constraint.type); + case NEGATE_COMBO_ROLE: + return filter_constraint_negate_list_translated(); + case STRING_MODE_COMBO_ROLE: + return filter_constraint_has_string_mode(constraint.type) ? + filter_constraint_string_mode_list_translated() : QStringList(); + case RANGE_MODE_COMBO_ROLE: + return filter_constraint_has_range_mode(constraint.type) ? + filter_constraint_range_mode_list_translated() : QStringList(); + case MULTIPLE_CHOICE_LIST_ROLE: + return filter_contraint_multiple_choice_translated(constraint.type); + case STRING_MODE_ROLE: + return static_cast<int>(constraint.string_mode); + case RANGE_MODE_ROLE: + return static_cast<int>(constraint.range_mode); + case TYPE_DISPLAY_ROLE: + return filter_constraint_type_to_string_translated(constraint.type); + case NEGATE_DISPLAY_ROLE: + return filter_constraint_negate_to_string_translated(constraint.negate); + case STRING_MODE_DISPLAY_ROLE: + return filter_constraint_string_mode_to_string_translated(constraint.string_mode); + case RANGE_MODE_DISPLAY_ROLE: + return filter_constraint_range_mode_to_string_translated(constraint.range_mode); + case TYPE_INDEX_ROLE: + return filter_constraint_type_to_index(constraint.type); + case NEGATE_INDEX_ROLE: + return static_cast<int>(constraint.negate); + case STRING_MODE_INDEX_ROLE: + return filter_constraint_string_mode_to_index(constraint.string_mode); + case RANGE_MODE_INDEX_ROLE: + return filter_constraint_range_mode_to_index(constraint.range_mode); + case UNIT_ROLE: + return filter_constraint_get_unit(constraint.type); + case STRING_ROLE: + return filter_constraint_get_string(constraint); + case INTEGER_FROM_ROLE: + return filter_constraint_get_integer_from(constraint); + case INTEGER_TO_ROLE: + return filter_constraint_get_integer_to(constraint); + case FLOAT_FROM_ROLE: + return filter_constraint_get_float_from(constraint); // Converts from integers to metric or imperial units + case FLOAT_TO_ROLE: + return filter_constraint_get_float_to(constraint); // Converts from integers to metric or imperial units + case TIMESTAMP_FROM_ROLE: + return timestampToDateTime(filter_constraint_get_timestamp_from(constraint)); + case TIMESTAMP_TO_ROLE: + return timestampToDateTime(filter_constraint_get_timestamp_to(constraint)); + case TIME_FROM_ROLE: + return secondsToTime(filter_constraint_get_integer_from(constraint)); + case TIME_TO_ROLE: + return secondsToTime(filter_constraint_get_integer_from(constraint)); + case MULTIPLE_CHOICE_ROLE: + return (qulonglong)filter_constraint_get_multiple_choice(constraint); + } + return QVariant(); +} + +bool FilterConstraintModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || index.row() > (int)constraints.size()) + return false; + filter_constraint &constraint = constraints[index.row()]; + + switch (role) { + case NEGATE_INDEX_ROLE: + constraint.negate = value.value<bool>(); + break; + case STRING_ROLE: + filter_constraint_set_stringlist(constraint, value.value<QString>()); + break; + case STRING_MODE_INDEX_ROLE: + constraint.string_mode = filter_constraint_string_mode_from_index(value.value<int>()); + break; + case RANGE_MODE_INDEX_ROLE: + constraint.range_mode = filter_constraint_range_mode_from_index(value.value<int>()); + break; + case INTEGER_FROM_ROLE: + filter_constraint_set_integer_from(constraint, value.value<int>()); + break; + case INTEGER_TO_ROLE: + filter_constraint_set_integer_to(constraint, value.value<int>()); + break; + case FLOAT_FROM_ROLE: + filter_constraint_set_float_from(constraint, value.value<double>()); + break; + case FLOAT_TO_ROLE: + filter_constraint_set_float_to(constraint, value.value<double>()); + break; + case TIMESTAMP_FROM_ROLE: + filter_constraint_set_timestamp_from(constraint, dateTimeToTimestamp(value.value<QDateTime>())); + break; + case TIMESTAMP_TO_ROLE: + filter_constraint_set_timestamp_to(constraint, dateTimeToTimestamp(value.value<QDateTime>())); + break; + case TIME_FROM_ROLE: + filter_constraint_set_integer_from(constraint, timeToSeconds(value.value<QTime>())); + break; + case TIME_TO_ROLE: + filter_constraint_set_integer_to(constraint, timeToSeconds(value.value<QTime>())); + break; + case MULTIPLE_CHOICE_ROLE: + filter_constraint_set_multiple_choice(constraint, value.value<uint64_t>()); + break; + default: + return false; + } + emit dataChanged(index, index, QVector<int> { role }); + return true; +} + +int FilterConstraintModel::rowCount(const QModelIndex&) const +{ + return constraints.size(); +} + +void FilterConstraintModel::reload(const std::vector<filter_constraint> &constraintsIn) +{ + beginResetModel(); + constraints = constraintsIn; + endResetModel(); +} + +std::vector<filter_constraint> FilterConstraintModel::getConstraints() const +{ + std::vector<filter_constraint> res; + res.reserve(constraints.size()); + for (const filter_constraint &c: constraints) { + if (filter_constraint_is_valid(&c)) + res.push_back(c); + } + return res; +} + +void FilterConstraintModel::addConstraint(filter_constraint_type type) +{ + int count = (int)constraints.size(); + beginInsertRows(QModelIndex(), count, count); + constraints.emplace_back(type); + endInsertRows(); +} + +void FilterConstraintModel::deleteConstraint(int row) +{ + if (row < 0 || row >= (int)constraints.size()) + return; + beginRemoveRows(QModelIndex(), row, row); + constraints.erase(constraints.begin() + row); + endRemoveRows(); +} diff --git a/qt-models/filterconstraintmodel.h b/qt-models/filterconstraintmodel.h new file mode 100644 index 000000000..e7e70960d --- /dev/null +++ b/qt-models/filterconstraintmodel.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef FILTERCONSTRAINTMODEL_H +#define FILTERCONSTRAINTMODEL_H + +#include "core/filterconstraint.h" +#include <QAbstractTableModel> +#include <vector> + +class FilterConstraintModel : public QAbstractListModel { + Q_OBJECT +public: + enum Roles { + TYPE_ROLE = Qt::UserRole + 1, // enum filter_constraint_type cast to int + IS_STAR_WIDGET_ROLE, // represent as a star widget + HAS_DATE_WIDGET_ROLE, // has a date widget + HAS_TIME_WIDGET_ROLE, // has a time widget + NUM_DECIMALS_ROLE, // number of decimal places for numeric data + NEGATE_COMBO_ROLE, // combo box entries for negate + STRING_MODE_COMBO_ROLE, // combo box entries for string mode or empty list if no string mode + RANGE_MODE_COMBO_ROLE, // combo box entries for range mode or empty list if no range mode + MULTIPLE_CHOICE_LIST_ROLE, // list of translated multiple-choice items + STRING_MODE_ROLE, // enum filter_constraint_string_mode_role cast to int + RANGE_MODE_ROLE, // enum filter_constraint_range_mode cast to int + TYPE_DISPLAY_ROLE, // type for display (i.e. translated) + NEGATE_DISPLAY_ROLE, // negate flag for display (i.e. translated) + STRING_MODE_DISPLAY_ROLE, // string mode for display (i.e. translated) + RANGE_MODE_DISPLAY_ROLE, // range mode for display (i.e. translated) + NEGATE_INDEX_ROLE, // negate index in combo box + TYPE_INDEX_ROLE, // type index in combo box + STRING_MODE_INDEX_ROLE, // string mode index in combo box + RANGE_MODE_INDEX_ROLE, // range mode index in combo box + UNIT_ROLE, // unit, if any + STRING_ROLE, // string data + INTEGER_FROM_ROLE, + INTEGER_TO_ROLE, + FLOAT_FROM_ROLE, + FLOAT_TO_ROLE, + TIMESTAMP_FROM_ROLE, + TIMESTAMP_TO_ROLE, + TIME_FROM_ROLE, + TIME_TO_ROLE, + MULTIPLE_CHOICE_ROLE + }; +private: + QVariant data(const QModelIndex &index, int role) const override; + std::vector<filter_constraint> constraints; +public: + using QAbstractListModel::QAbstractListModel; + ~FilterConstraintModel(); + void reload(const std::vector<filter_constraint> &); + std::vector<filter_constraint> getConstraints() const; // filters out constraints with no user input + void addConstraint(filter_constraint_type type); + void deleteConstraint(int row); + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + int rowCount(const QModelIndex &parent) const override; +}; + +#endif |