mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-31 18:23:23 +00:00
filter: add filter constraint model
Add a model that keeps track of a list of filter constraint and makes them accessible from Qt. Sadly, this is mostly repetitive boiler-plate code, but this is due to Qt's model/view-API, which is a perfect example of how *not* to design a reasonable modern API. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
634152ae43
commit
af9d379a41
6 changed files with 261 additions and 2 deletions
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
186
qt-models/filterconstraintmodel.cpp
Normal file
186
qt-models/filterconstraintmodel.cpp
Normal file
|
@ -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();
|
||||
}
|
58
qt-models/filterconstraintmodel.h
Normal file
58
qt-models/filterconstraintmodel.h
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue