core: remove filterconstraint C boilerplate code

Since all code can now directly access C++ structures these
accessor functions were not necessary.

Split out the table from the filterconstraint source file
and include it directly into the divelog.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-06-08 18:54:23 +02:00 committed by bstoeger
parent 2bdcdab391
commit 91968ac579
20 changed files with 212 additions and 250 deletions

View file

@ -55,6 +55,7 @@ SOURCES += subsurface-mobile-main.cpp \
core/eventtype.cpp \
core/filterconstraint.cpp \
core/filterpreset.cpp \
core/filterpresettable.cpp \
core/divelist.cpp \
core/divelog.cpp \
core/gas-model.cpp \
@ -228,6 +229,7 @@ HEADERS += \
core/divefilter.h \
core/filterconstraint.h \
core/filterpreset.h \
core/filterpresettable.h \
core/divelist.h \
core/divelog.h \
core/divelogexportlogic.h \

View file

@ -492,11 +492,11 @@ ImportDives::ImportDives(struct divelog *log, int flags, const QString &source)
// When encountering filter presets with equal names, check whether they are
// the same. If they are, ignore them.
for (const filter_preset &preset: *log->filter_presets) {
for (const filter_preset &preset: log->filter_presets) {
std::string name = preset.name;
auto it = std::find_if(divelog.filter_presets->begin(), divelog.filter_presets->end(),
auto it = std::find_if(divelog.filter_presets.begin(), divelog.filter_presets.end(),
[&name](const filter_preset &preset) { return preset.name == name; });
if (it != divelog.filter_presets->end() && it->data == preset.data)
if (it != divelog.filter_presets.end() && it->data == preset.data)
continue;
filterPresetsToAdd.emplace_back(preset.name, preset.data);
}
@ -530,7 +530,7 @@ void ImportDives::redoit()
// Add new filter presets
for (auto &it: filterPresetsToAdd) {
filterPresetsToRemove.push_back(filter_preset_add(it.first, it.second));
filterPresetsToRemove.push_back(divelog.filter_presets.add(it.first, it.second));
emit diveListNotifier.filterPresetAdded(filterPresetsToRemove.back());
}
filterPresetsToAdd.clear();
@ -559,9 +559,10 @@ void ImportDives::undoit()
// Remove filter presets. Do this in reverse order.
for (auto it = filterPresetsToRemove.rbegin(); it != filterPresetsToRemove.rend(); ++it) {
int index = *it;
std::string oldName = filter_preset_name(index);
FilterData oldData = filter_preset_get(index);
filter_preset_delete(index);
const filter_preset &preset = divelog.filter_presets[index];
std::string oldName = preset.name;
FilterData oldData = preset.data;
divelog.filter_presets.remove(index);
emit diveListNotifier.filterPresetRemoved(index);
filterPresetsToAdd.emplace_back(oldName, oldData);
}

View file

@ -1,23 +1,26 @@
// SPDX-License-Identifier: GPL-2.0
#include "command_filter.h"
#include "core/divelog.h"
#include "core/filterpreset.h"
#include "core/filterpresettable.h"
#include "core/subsurface-qt/divelistnotifier.h"
namespace Command {
static int createFilterPreset(const std::string &name, const FilterData &data)
{
int index = filter_preset_add(name, data);
int index = divelog.filter_presets.add(name, data);
emit diveListNotifier.filterPresetAdded(index);
return index;
}
static std::pair<std::string, FilterData> removeFilterPreset(int index)
{
std::string oldName = filter_preset_name(index);
FilterData oldData = filter_preset_get(index);
filter_preset_delete(index);
const filter_preset &preset = divelog.filter_presets[index];
std::string oldName = preset.name;
FilterData oldData = preset.data;
divelog.filter_presets.remove(index);
emit diveListNotifier.filterPresetRemoved(index);
return { oldName, oldData };
}
@ -46,7 +49,8 @@ void CreateFilterPreset::undo()
RemoveFilterPreset::RemoveFilterPreset(int indexIn) : index(indexIn)
{
setText(Command::Base::tr("Delete filter preset %1").arg(QString(filter_preset_name(index).c_str())));
const std::string &name = divelog.filter_presets[index].name;
setText(Command::Base::tr("Delete filter preset %1").arg(QString::fromStdString(name)));
}
bool RemoveFilterPreset::workToBeDone()
@ -68,7 +72,8 @@ void RemoveFilterPreset::undo()
EditFilterPreset::EditFilterPreset(int indexIn, const FilterData &dataIn) :
index(indexIn), data(dataIn)
{
setText(Command::Base::tr("Edit filter preset %1").arg(QString(filter_preset_name(index).c_str())));
const std::string &name = divelog.filter_presets[index].name;
setText(Command::Base::tr("Edit filter preset %1").arg(QString::fromStdString(name)));
}
bool EditFilterPreset::workToBeDone()
@ -78,9 +83,8 @@ bool EditFilterPreset::workToBeDone()
void EditFilterPreset::redo()
{
FilterData oldData = filter_preset_get(index);
filter_preset_set(index, data);
data = std::move(oldData);
filter_preset &preset = divelog.filter_presets[index];
std::swap(data, preset.data);
}
void EditFilterPreset::undo()

View file

@ -95,6 +95,8 @@ set(SUBSURFACE_CORE_LIB_SRCS
filterconstraint.h
filterpreset.cpp
filterpreset.h
filterpresettable.cpp
filterpresettable.h
format.cpp
format.h
fulltext.cpp

View file

@ -6,16 +6,12 @@
#include "dive.h"
#include "errorhelper.h"
#include "filterpreset.h"
#include "filterpresettable.h"
#include "trip.h"
struct divelog divelog;
divelog::divelog() :
filter_presets(std::make_unique<filter_preset_table>()),
autogroup(false)
{
}
divelog::divelog() = default;
divelog::~divelog() = default;
divelog::divelog(divelog &&) = default;
struct divelog &divelog::operator=(divelog &&) = default;
@ -68,7 +64,7 @@ void divelog::clear()
sites.clear();
trips.clear();
devices.clear();
filter_presets->clear();
filter_presets.clear();
}
/* check if we have a trip right before / after this dive */

View file

@ -1,26 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
// A structure that contains all the data we store in a divelog files
// A structure that contains all the data we store in divelog files
#ifndef DIVELOG_H
#define DIVELOG_H
#include "divelist.h"
#include "divesitetable.h"
#include "filterpresettable.h"
#include "triptable.h"
#include <memory>
#include <vector>
struct trip_table;
struct device;
struct filter_preset_table;
struct divelog {
dive_table dives;
trip_table trips;
dive_site_table sites;
std::vector<device> devices;
std::unique_ptr<filter_preset_table> filter_presets;
bool autogroup;
filter_preset_table filter_presets;
bool autogroup = false;
divelog();
~divelog();

View file

@ -134,33 +134,33 @@ static const range_mode_description *get_range_mode_description(enum filter_cons
return nullptr;
}
static enum filter_constraint_type filter_constraint_type_from_string(const char *s)
static enum filter_constraint_type filter_constraint_type_from_string(const std::string &s)
{
for (const auto &desc: type_descriptions) {
if (same_string(desc.token, s))
if (desc.token == s)
return desc.type;
}
report_error("unknown filter constraint type: %s", s);
report_error("unknown filter constraint type: %s", s.c_str());
return FILTER_CONSTRAINT_DATE;
}
static enum filter_constraint_string_mode filter_constraint_string_mode_from_string(const char *s)
static enum filter_constraint_string_mode filter_constraint_string_mode_from_string(const std::string &s)
{
for (const auto &desc: string_mode_descriptions) {
if (same_string(desc.token, s))
if (desc.token == s)
return desc.mode;
}
report_error("unknown filter constraint string mode: %s", s);
report_error("unknown filter constraint string mode: %s", s.c_str());
return FILTER_CONSTRAINT_EXACT;
}
static enum filter_constraint_range_mode filter_constraint_range_mode_from_string(const char *s)
static enum filter_constraint_range_mode filter_constraint_range_mode_from_string(const std::string &s)
{
for (const auto &desc: range_mode_descriptions) {
if (same_string(desc.token, s))
if (desc.token == s)
return desc.mode;
}
report_error("unknown filter constraint range mode: %s", s);
report_error("unknown filter constraint range mode: %s", s.c_str());
return FILTER_CONSTRAINT_EQUAL;
}
@ -551,14 +551,14 @@ filter_constraint::filter_constraint(const filter_constraint &c) :
data.numerical_range = c.data.numerical_range;
}
filter_constraint::filter_constraint(const char *type_in, const char *string_mode_in,
const char *range_mode_in, bool negate_in, const char *s_in) :
filter_constraint::filter_constraint(const std::string &type_in, const std::string &string_mode_in,
const std::string &range_mode_in, bool negate_in, const std::string &s_in) :
type(filter_constraint_type_from_string(type_in)),
string_mode(FILTER_CONSTRAINT_STARTS_WITH),
range_mode(FILTER_CONSTRAINT_GREATER),
negate(negate_in)
{
QString s(s_in);
QString s = QString::fromStdString(s_in);
if (filter_constraint_has_string_mode(type))
string_mode = filter_constraint_string_mode_from_string(string_mode_in);
if (filter_constraint_has_range_mode(type))
@ -622,22 +622,22 @@ filter_constraint::~filter_constraint()
delete data.string_list;
}
std::string filter_constraint_data_to_string(const filter_constraint *c)
std::string filter_constraint_data_to_string(const filter_constraint &c)
{
if (filter_constraint_is_timestamp(c->type)) {
std::string from_s = format_datetime(c->data.timestamp_range.from);
std::string to_s = format_datetime(c->data.timestamp_range.to);
if (filter_constraint_is_timestamp(c.type)) {
std::string from_s = format_datetime(c.data.timestamp_range.from);
std::string to_s = format_datetime(c.data.timestamp_range.to);
return from_s + ',' + to_s;
} else if (filter_constraint_is_string(c->type)) {
} else if (filter_constraint_is_string(c.type)) {
// TODO: this obviously breaks if the strings contain ",".
// That is currently not supported by the UI, but one day we might
// have to escape the strings.
return c->data.string_list->join(",").toStdString();
} else if (filter_constraint_is_multiple_choice(c->type)) {
return std::to_string(c->data.multiple_choice);
return c.data.string_list->join(",").toStdString();
} else if (filter_constraint_is_multiple_choice(c.type)) {
return std::to_string(c.data.multiple_choice);
} else {
return std::to_string(c->data.numerical_range.from) + ',' +
std::to_string(c->data.numerical_range.to);
return std::to_string(c.data.numerical_range.from) + ',' +
std::to_string(c.data.numerical_range.to);
}
}

View file

@ -78,8 +78,8 @@ struct filter_constraint {
} data;
// For C++, define constructors, assignment operators and destructor to make our lives easier.
filter_constraint(filter_constraint_type type);
filter_constraint(const char *type, const char *string_mode,
const char *range_mode, bool negate, const char *data); // from parser data
filter_constraint(const std::string &type, const std::string &string_mode,
const std::string &range_mode, bool negate, const std::string &data); // from parser data
filter_constraint(const filter_constraint &);
filter_constraint &operator=(const filter_constraint &);
~filter_constraint();
@ -137,6 +137,6 @@ void filter_constraint_set_timestamp_from(filter_constraint &c, timestamp_t from
void filter_constraint_set_timestamp_to(filter_constraint &c, timestamp_t to); // convert according to current units (metric or imperial)
void filter_constraint_set_multiple_choice(filter_constraint &c, uint64_t);
bool filter_constraint_match_dive(const filter_constraint &c, const struct dive *d);
std::string filter_constraint_data_to_string(const struct filter_constraint *constraint); // caller takes ownership of returned string
std::string filter_constraint_data_to_string(const struct filter_constraint &constraint); // caller takes ownership of returned string
#endif

View file

@ -4,24 +4,14 @@
#include "qthelper.h"
#include "subsurface-string.h"
static filter_preset_table &global_table()
std::string filter_preset::fulltext_query() const
{
return *divelog.filter_presets;
return data.fullText.originalQuery.toStdString();
}
int filter_presets_count()
const char *filter_preset::fulltext_mode() const
{
return (int)global_table().size();
}
extern std::string filter_preset_fulltext_query(int preset)
{
return global_table()[preset].data.fullText.originalQuery.toStdString();
}
const char *filter_preset_fulltext_mode(int preset)
{
switch (global_table()[preset].data.fulltextStringMode) {
switch (data.fulltextStringMode) {
default:
case StringFilterMode::SUBSTRING:
return "substring";
@ -32,98 +22,19 @@ const char *filter_preset_fulltext_mode(int preset)
}
}
void filter_preset_set_fulltext(struct filter_preset *preset, const char *fulltext, const char *fulltext_string_mode)
void filter_preset::set_fulltext(const std::string fulltext, const std::string &fulltext_string_mode)
{
if (same_string(fulltext_string_mode, "substring"))
preset->data.fulltextStringMode = StringFilterMode::SUBSTRING;
else if (same_string(fulltext_string_mode, "startswith"))
preset->data.fulltextStringMode = StringFilterMode::STARTSWITH;
else // if (same_string(fulltext_string_mode, "exact"))
preset->data.fulltextStringMode = StringFilterMode::EXACT;
preset->data.fullText = fulltext;
if (fulltext_string_mode == "substring")
data.fulltextStringMode = StringFilterMode::SUBSTRING;
else if (fulltext_string_mode == "startswith")
data.fulltextStringMode = StringFilterMode::STARTSWITH;
else // if (fulltext_string_mode == "exact"))
data.fulltextStringMode = StringFilterMode::EXACT;
data.fullText = QString::fromStdString(std::move(fulltext));
}
int filter_preset_constraint_count(int preset)
void filter_preset::add_constraint(const std::string &type, const std::string &string_mode,
const std::string &range_mode, bool negate, const std::string &constraint_data)
{
return (int)global_table()[preset].data.constraints.size();
}
const filter_constraint *filter_preset_constraint(int preset, int constraint)
{
return &global_table()[preset].data.constraints[constraint];
}
void filter_preset_set_name(struct filter_preset *preset, const char *name)
{
preset->name = name;
}
static int filter_preset_add_to_table(const std::string name, const FilterData &d, struct filter_preset_table &table)
{
// std::lower_bound does a binary search - the vector must be sorted.
filter_preset newEntry { name, d };
auto it = std::lower_bound(table.begin(), table.end(), newEntry,
[](const filter_preset &p1, const filter_preset &p2)
{ return p1.name < p2.name; });
it = table.insert(it, newEntry);
return it - table.begin();
}
// Take care that the name doesn't already exist by adding numbers
static std::string get_unique_preset_name(const std::string &orig, const struct filter_preset_table &table)
{
std::string res = orig;
int count = 2;
while (std::find_if(table.begin(), table.end(),
[&res](const filter_preset &preset)
{ return preset.name == res; }) != table.end()) {
res = orig + "#" + std::to_string(count);
++count;
}
return res;
}
void add_filter_preset_to_table(const struct filter_preset *preset, struct filter_preset_table *table)
{
std::string name = get_unique_preset_name(preset->name, *table);
filter_preset_add_to_table(name, preset->data, *table);
}
void filter_preset_add_constraint(struct filter_preset *preset, const char *type, const char *string_mode,
const char *range_mode, bool negate, const char *data)
{
preset->data.constraints.emplace_back(type, string_mode, range_mode, negate, data);
}
int filter_preset_id(const std::string &name)
{
auto it = std::find_if(global_table().begin(), global_table().end(),
[&name] (filter_preset &p) { return p.name == name; });
return it != global_table().end() ? it - global_table().begin() : -1;
}
std::string filter_preset_name(int preset)
{
return global_table()[preset].name;
}
void filter_preset_set(int preset, const FilterData &data)
{
global_table()[preset].data = data;
}
FilterData filter_preset_get(int preset)
{
return global_table()[preset].data;
}
int filter_preset_add(const std::string &nameIn, const FilterData &d)
{
std::string name = get_unique_preset_name(nameIn, global_table());
return filter_preset_add_to_table(name, d, global_table());
}
void filter_preset_delete(int preset)
{
global_table().erase(global_table().begin() + preset);
data.constraints.emplace_back(type, string_mode, range_mode, negate, constraint_data);
}

View file

@ -1,15 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
// A list of filter settings with names. Every name is unique, which
// means that saving to an old name will overwrite the old preset.
//
// Even though the filter data itself is a C++/Qt class to simplify
// string manipulation and memory management, the data is accessible
// via pure C functions so that it can be written to the log (git or xml).
#ifndef FILTER_PRESETS_H
#define FILTER_PRESETS_H
#include "divefilter.h"
#include <vector>
#include <string>
struct dive;
@ -19,32 +12,12 @@ struct FilterData;
struct filter_preset {
std::string name;
FilterData data;
};
// Subclassing standard library containers is generally
// not recommended. However, this makes interaction with
// C-code easier and since we don't add any member functions,
// this is not a problem.
struct filter_preset_table : public std::vector<filter_preset>
{
std::string fulltext_query() const; // Fulltext query of filter preset.
const char *fulltext_mode() const; // String mode of fulltext query. Ownership is *not* passed to caller.
void set_fulltext(const std::string fulltext, const std::string &fulltext_string_mode); // First argument is consumed.
void add_constraint(const std::string &type, const std::string &string_mode,
const std::string &range_mode, bool negate, const std::string &data); // called by the parser, therefore data passed as strings.
};
// The C IO code accesses the filter presets via integer indices.
extern int filter_presets_count();
extern const char *filter_preset_fulltext_mode(int preset); // string mode of fulltext query. ownership is *not* passed to caller.
extern int filter_preset_constraint_count(int preset); // number of constraints in the filter preset.
extern const struct filter_constraint *filter_preset_constraint(int preset, int constraint); // get constraint. ownership is *not* passed to caller.
extern void filter_preset_set_name(struct filter_preset *preset, const char *name);
extern void filter_preset_set_fulltext(struct filter_preset *preset, const char *fulltext, const char *fulltext_string_mode);
extern void add_filter_preset_to_table(const struct filter_preset *preset, struct filter_preset_table *table);
extern void filter_preset_add_constraint(struct filter_preset *preset, const char *type, const char *string_mode,
const char *range_mode, bool negate, const char *data); // called by the parser, therefore data passed as strings.
int filter_preset_id(const std::string &s); // for now, we assume that names are unique. returns -1 if no preset with that name.
void filter_preset_set(int preset, const FilterData &d); // this will override a preset if the name already exists.
FilterData filter_preset_get(int preset);
int filter_preset_add(const std::string &name, const FilterData &d); // returns point of insertion
void filter_preset_delete(int preset);
std::string filter_preset_name(int preset); // name of filter preset - caller must free the result.
std::string filter_preset_fulltext_query(int preset); // fulltext query of filter preset - caller must free the result.
#endif

View file

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
#include "filterpresettable.h"
#include "filterpreset.h"
#include <algorithm>
int filter_preset_table::preset_id(const std::string &name) const
{
auto it = std::find_if(begin(), end(), [&name] (const filter_preset &p) { return p.name == name; });
return it != end() ? it - begin() : -1;
}
// Take care that the name doesn't already exist by adding numbers
static std::string get_unique_preset_name(const std::string &orig, const struct filter_preset_table &table)
{
std::string res = orig;
int count = 2;
while (std::find_if(table.begin(), table.end(),
[&res](const filter_preset &preset)
{ return preset.name == res; }) != table.end()) {
res = orig + "#" + std::to_string(count);
++count;
}
return res;
}
static int filter_preset_add_to_table(const std::string name, const FilterData &d, struct filter_preset_table &table)
{
// std::lower_bound does a binary search - the vector must be sorted.
filter_preset newEntry { name, d };
auto it = std::lower_bound(table.begin(), table.end(), newEntry,
[](const filter_preset &p1, const filter_preset &p2)
{ return p1.name < p2.name; });
it = table.insert(it, newEntry);
return it - table.begin();
}
void filter_preset_table::add(const filter_preset &preset)
{
std::string name = get_unique_preset_name(preset.name, *this);
filter_preset_add_to_table(name, preset.data, *this);
}
int filter_preset_table::add(const std::string &nameIn, const FilterData &d)
{
std::string name = get_unique_preset_name(nameIn, *this);
return filter_preset_add_to_table(name, d, *this);
}
void filter_preset_table::remove(int preset)
{
erase(begin() + preset);
}

25
core/filterpresettable.h Normal file
View file

@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
// A list of filter settings with names. Every name is unique, which
// means that saving to an old name will overwrite the old preset.
#ifndef FILTER_PRESETSTABLE_H
#define FILTER_PRESETSTABLE_H
#include <string>
#include <vector>
struct filter_preset;
struct FilterData;
// Subclassing standard library containers is generally
// not recommended. However, this makes interaction with
// C-code easier and since we don't add any member functions,
// this is not a problem.
struct filter_preset_table : public std::vector<filter_preset>
{
void add(const filter_preset &preset);
int add(const std::string &name, const FilterData &d); // returns point of insertion
void remove(int iox);
int preset_id(const std::string &s) const; // for now, we assume that names are unique. returns -1 if no preset with that name
};
#endif

View file

@ -1183,10 +1183,10 @@ static void parse_filter_preset_constraint(char *line, struct git_parser_state *
line = parse_keyvalue_entry(parse_filter_preset_constraint_keyvalue, state, line, state);
}
filter_preset_add_constraint(state->active_filter.get(), state->filter_constraint_type.c_str(),
state->filter_constraint_string_mode.c_str(),
state->filter_constraint_range_mode.c_str(),
state->filter_constraint_negate, state->filter_constraint_data.c_str());
state->active_filter->add_constraint(state->filter_constraint_type,
state->filter_constraint_string_mode,
state->filter_constraint_range_mode,
state->filter_constraint_negate, state->filter_constraint_data);
state->filter_constraint_type.clear();
state->filter_constraint_string_mode.clear();
state->filter_constraint_range_mode.clear();
@ -1220,14 +1220,14 @@ static void parse_filter_preset_fulltext(char *line, struct git_parser_state *st
line = parse_keyvalue_entry(parse_filter_preset_fulltext_keyvalue, state, line, state);
}
filter_preset_set_fulltext(state->active_filter.get(), state->fulltext_query.c_str(), state->fulltext_mode.c_str());
state->active_filter.get()->set_fulltext(std::move(state->fulltext_query), state->fulltext_mode);
state->fulltext_mode.clear();
state->fulltext_query.clear();
}
static void parse_filter_preset_name(char *, struct git_parser_state *state)
{
filter_preset_set_name(state->active_filter.get(), get_first_converted_string_c(state));
state->active_filter->name = get_first_converted_string(state);
}
/* These need to be sorted! */
@ -1774,7 +1774,7 @@ static int parse_filter_preset(struct git_parser_state *state, const git_tree_en
git_blob_free(blob);
add_filter_preset_to_table(state->active_filter.get(), state->log->filter_presets.get());
state->log->filter_presets.add(*state->active_filter);
state->active_filter.reset();
return 0;

View file

@ -1440,11 +1440,8 @@ static void try_to_fill_filter(struct filter_preset *filter, const char *name, c
{
start_match("filterpreset", name, buf);
std::string s;
if (MATCH("name", utf8_string_std, &s)) {
filter_preset_set_name(filter, s.c_str());
if (MATCH("name", utf8_string_std, &filter->name))
return;
}
nonmatch("filterpreset", name, buf);
}

View file

@ -202,7 +202,7 @@ void filter_preset_start(struct parser_state *state)
void filter_preset_end(struct parser_state *state)
{
add_filter_preset_to_table(state->cur_filter.get(), state->log->filter_presets.get());
state->log->filter_presets.add(*state->cur_filter);
state->cur_filter.reset();
}
@ -217,7 +217,7 @@ void fulltext_end(struct parser_state *state)
{
if (!state->in_fulltext)
return;
filter_preset_set_fulltext(state->cur_filter.get(), state->fulltext.c_str(), state->fulltext_string_mode.c_str());
state->cur_filter->set_fulltext(std::move(state->fulltext), state->fulltext_string_mode);
state->fulltext.clear();
state->fulltext_string_mode.clear();
state->in_fulltext = false;
@ -234,8 +234,8 @@ void filter_constraint_end(struct parser_state *state)
{
if (!state->in_filter_constraint)
return;
filter_preset_add_constraint(state->cur_filter.get(), state->filter_constraint_type.c_str(), state->filter_constraint_string_mode.c_str(),
state->filter_constraint_range_mode.c_str(), state->filter_constraint_negate, state->filter_constraint.c_str());
state->cur_filter->add_constraint(state->filter_constraint_type, state->filter_constraint_string_mode,
state->filter_constraint_range_mode, state->filter_constraint_negate, state->filter_constraint);
state->filter_constraint_type.clear();
state->filter_constraint_string_mode.clear();

View file

@ -33,6 +33,7 @@
#include "version.h"
#include "picture.h"
#include "qthelper.h"
#include "range.h"
#include "gettext.h"
#include "tag.h"
#include "subsurface-time.h"
@ -914,21 +915,20 @@ static void save_divesites(git_repository *repo, struct dir *tree)
* Whether stringmode or rangemode exist depends on the type of the constraint.
* Any constraint can be negated.
*/
static void format_one_filter_constraint(int preset_id, int constraint_id, struct membuffer *b)
static void format_one_filter_constraint(const filter_constraint &constraint, struct membuffer *b)
{
const struct filter_constraint *constraint = filter_preset_constraint(preset_id, constraint_id);
const char *type = filter_constraint_type_to_string(constraint->type);
const char *type = filter_constraint_type_to_string(constraint.type);
show_utf8(b, "constraint type=", type, "");
if (filter_constraint_has_string_mode(constraint->type)) {
const char *mode = filter_constraint_string_mode_to_string(constraint->string_mode);
if (filter_constraint_has_string_mode(constraint.type)) {
const char *mode = filter_constraint_string_mode_to_string(constraint.string_mode);
show_utf8(b, " stringmode=", mode, "");
}
if (filter_constraint_has_range_mode(constraint->type)) {
const char *mode = filter_constraint_range_mode_to_string(constraint->range_mode);
if (filter_constraint_has_range_mode(constraint.type)) {
const char *mode = filter_constraint_range_mode_to_string(constraint.range_mode);
show_utf8(b, " rangemode=", mode, "");
}
if (constraint->negate)
if (constraint.negate)
put_format(b, " negate");
std::string data = filter_constraint_data_to_string(constraint);
show_utf8(b, " data=", data.c_str(), "\n");
@ -943,19 +943,18 @@ static void format_one_filter_constraint(int preset_id, int constraint_id, struc
* fulltext mode "fulltext mode" query "the query as entered by the user"
* The format of the "constraint" entry is described in the format_one_filter_constraint() function.
*/
static void format_one_filter_preset(int preset_id, struct membuffer *b)
static void format_one_filter_preset(const filter_preset &preset, struct membuffer *b)
{
std::string name = filter_preset_name(preset_id);
show_utf8(b, "name ", name.c_str(), "\n");
show_utf8(b, "name ", preset.name.c_str(), "\n");
std::string fulltext = filter_preset_fulltext_query(preset_id);
std::string fulltext = preset.fulltext_query();
if (!fulltext.empty()) {
show_utf8(b, "fulltext mode=", filter_preset_fulltext_mode(preset_id), "");
show_utf8(b, "fulltext mode=", preset.fulltext_mode(), "");
show_utf8(b, " query=", fulltext.c_str(), "\n");
}
for (int i = 0; i < filter_preset_constraint_count(preset_id); i++)
format_one_filter_constraint(preset_id, i, b);
for (auto &constraint: preset.data.constraints)
format_one_filter_constraint(constraint, b);
}
static void save_filter_presets(git_repository *repo, struct dir *tree)
@ -965,13 +964,13 @@ static void save_filter_presets(git_repository *repo, struct dir *tree)
put_format(&dirname, "02-Filterpresets");
filter_dir = new_directory(repo, tree, &dirname);
for (int i = 0; i < filter_presets_count(); i++)
for (auto [i, filter_preset]: enumerated_range(divelog.filter_presets))
{
membuffer preset_name;
membuffer preset_buffer;
put_format(&preset_name, "Preset-%03d", i);
format_one_filter_preset(i, &preset_buffer);
format_one_filter_preset(filter_preset, &preset_buffer);
blob_insert(repo, filter_dir, &preset_buffer, mb_cstring(&preset_name));
}

View file

@ -591,38 +591,34 @@ int save_dives(const char *filename)
static void save_filter_presets(struct membuffer *b)
{
int i;
if (filter_presets_count() <= 0)
if (divelog.filter_presets.empty())
return;
put_format(b, "<filterpresets>\n");
for (i = 0; i < filter_presets_count(); i++) {
std::string name = filter_preset_name(i);
for (auto &filter_preset: divelog.filter_presets) {
put_format(b, " <filterpreset");
show_utf8(b, name.c_str(), " name='", "'", 1);
show_utf8(b, filter_preset.name.c_str(), " name='", "'", 1);
put_format(b, ">\n");
std::string fulltext = filter_preset_fulltext_query(i);
std::string fulltext = filter_preset.fulltext_query();
if (!fulltext.empty()) {
const char *fulltext_mode = filter_preset_fulltext_mode(i);
const char *fulltext_mode = filter_preset.fulltext_mode();
show_utf8(b, fulltext_mode, " <fulltext mode='", "'>", 1);
show_utf8(b, fulltext.c_str(), "", "</fulltext>\n", 0);
}
for (int j = 0; j < filter_preset_constraint_count(i); j++) {
const struct filter_constraint *constraint = filter_preset_constraint(i, j);
const char *type = filter_constraint_type_to_string(constraint->type);
for (auto &constraint: filter_preset.data.constraints) {
const char *type = filter_constraint_type_to_string(constraint.type);
put_format(b, " <constraint");
show_utf8(b, type, " type='", "'", 1);
if (filter_constraint_has_string_mode(constraint->type)) {
const char *mode = filter_constraint_string_mode_to_string(constraint->string_mode);
if (filter_constraint_has_string_mode(constraint.type)) {
const char *mode = filter_constraint_string_mode_to_string(constraint.string_mode);
show_utf8(b, mode, " string_mode='", "'", 1);
}
if (filter_constraint_has_range_mode(constraint->type)) {
const char *mode = filter_constraint_range_mode_to_string(constraint->range_mode);
if (filter_constraint_has_range_mode(constraint.type)) {
const char *mode = filter_constraint_range_mode_to_string(constraint.range_mode);
show_utf8(b, mode, " range_mode='", "'", 1);
}
if (constraint->negate)
if (constraint.negate)
put_format(b, " negate='1'");
put_format(b, ">");
std::string data = filter_constraint_data_to_string(constraint);

View file

@ -97,7 +97,7 @@ void FilterWidget::selectPreset(int i)
void FilterWidget::loadPreset(int index)
{
ignoreSignal = true; // When reloading the filter UI, we get numerous constraintChanged signals. Ignore them.
FilterData filter = filter_preset_get(index);
FilterData filter = divelog.filter_presets[index].data;
setFilterData(filter);
ignoreSignal = false;
presetModified = false;
@ -227,7 +227,8 @@ void FilterWidget::updatePresetLabel()
int presetId = selectedPreset();
QString text;
if (presetId >= 0) {
text = QString(filter_preset_name(presetId).c_str());
const std::string &name = divelog.filter_presets[presetId].name;
text = QString::fromStdString(name);
if (presetModified)
text += " (" + tr("modified") + ")";
}
@ -240,13 +241,15 @@ void FilterWidget::on_addSetButton_clicked()
// Thus, if the user selects an item and modify the filter,
// they can simply overwrite the preset.
int presetId = selectedPreset();
QString selectedPreset = presetId >= 0 ? QString(filter_preset_name(presetId).c_str()) : QString();
QString selectedPreset = presetId >= 0 ?
QString::fromStdString(divelog.filter_presets[presetId].name) :
QString();
AddFilterPresetDialog dialog(selectedPreset, this);
QString name = dialog.doit();
if (name.isEmpty())
return;
int idx = filter_preset_id(name.toStdString());
int idx = divelog.filter_presets.preset_id(name.toStdString());
if (idx >= 0)
Command::editFilterPreset(idx, createFilterData());
else

View file

@ -374,10 +374,9 @@ AddFilterPresetDialog::AddFilterPresetDialog(const QString &defaultName, QWidget
// Create a completer so that the user can easily overwrite existing presets.
QStringList presets;
int count = filter_presets_count();
presets.reserve(count);
for (int i = 0; i < count; ++i)
presets.push_back(QString(filter_preset_name(i).c_str()));
presets.reserve(divelog.filter_presets.size());
for (auto &filter_preset: divelog.filter_presets)
presets.push_back(QString::fromStdString(filter_preset.name));
QCompleter *completer = new QCompleter(presets, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);
ui.name->setCompleter(completer);
@ -387,7 +386,7 @@ void AddFilterPresetDialog::nameChanged(const QString &text)
{
QString trimmed = text.trimmed();
bool isEmpty = trimmed.isEmpty();
bool exists = !isEmpty && filter_preset_id(trimmed.toStdString()) >= 0;
bool exists = !isEmpty && divelog.filter_presets.preset_id(trimmed.toStdString()) >= 0;
ui.duplicateWarning->setVisible(exists);
ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!isEmpty);
}

View file

@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
#include "filterpresetmodel.h"
#include "core/divelog.h"
#include "core/filterconstraint.h"
#include "core/filterpreset.h"
#include "core/filterpresettable.h"
#include "core/qthelper.h"
#include "core/subsurface-qt/divelistnotifier.h"
@ -26,13 +28,14 @@ FilterPresetModel *FilterPresetModel::instance()
QVariant FilterPresetModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= filter_presets_count())
if (index.row() < 0 || static_cast<size_t>(index.row()) >= divelog.filter_presets.size())
return QVariant();
const auto &filter_preset = divelog.filter_presets[index.row()];
switch (role) {
case Qt::DisplayRole:
if (index.column() == NAME)
return QString(filter_preset_name(index.row()).c_str());
return QString::fromStdString(filter_preset.name);
break;
case Qt::DecorationRole:
if (index.column() == REMOVE)
@ -52,7 +55,7 @@ QVariant FilterPresetModel::data(const QModelIndex &index, int role) const
int FilterPresetModel::rowCount(const QModelIndex &parent) const
{
return filter_presets_count();
return static_cast<int>(divelog.filter_presets.size());
}
void FilterPresetModel::reset()