diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 029f19356..e09a7a61d 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -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 \ diff --git a/commands/command_divelist.cpp b/commands/command_divelist.cpp index c4a2867f1..6bcb98209 100644 --- a/commands/command_divelist.cpp +++ b/commands/command_divelist.cpp @@ -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); } diff --git a/commands/command_filter.cpp b/commands/command_filter.cpp index 4c60eb947..da5ea45ba 100644 --- a/commands/command_filter.cpp +++ b/commands/command_filter.cpp @@ -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 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() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 60343fe98..f9c39f60d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -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 diff --git a/core/divelog.cpp b/core/divelog.cpp index 508da5310..5f4d73a52 100644 --- a/core/divelog.cpp +++ b/core/divelog.cpp @@ -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()), - 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 */ diff --git a/core/divelog.h b/core/divelog.h index 6a1de2677..b77ec1214 100644 --- a/core/divelog.h +++ b/core/divelog.h @@ -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 #include -struct trip_table; struct device; -struct filter_preset_table; struct divelog { dive_table dives; trip_table trips; dive_site_table sites; std::vector devices; - std::unique_ptr filter_presets; - bool autogroup; + filter_preset_table filter_presets; + bool autogroup = false; divelog(); ~divelog(); diff --git a/core/filterconstraint.cpp b/core/filterconstraint.cpp index 9f266f935..418a61b55 100644 --- a/core/filterconstraint.cpp +++ b/core/filterconstraint.cpp @@ -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); } } diff --git a/core/filterconstraint.h b/core/filterconstraint.h index e9c85ec0b..53c7f6287 100644 --- a/core/filterconstraint.h +++ b/core/filterconstraint.h @@ -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 diff --git a/core/filterpreset.cpp b/core/filterpreset.cpp index 2366e88e2..60f9ca8a7 100644 --- a/core/filterpreset.cpp +++ b/core/filterpreset.cpp @@ -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); } diff --git a/core/filterpreset.h b/core/filterpreset.h index 5485f5bde..14e22ebf3 100644 --- a/core/filterpreset.h +++ b/core/filterpreset.h @@ -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 #include 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 -{ + 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 diff --git a/core/filterpresettable.cpp b/core/filterpresettable.cpp new file mode 100644 index 000000000..0c5cf0c9c --- /dev/null +++ b/core/filterpresettable.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "filterpresettable.h" +#include "filterpreset.h" + +#include + +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); +} diff --git a/core/filterpresettable.h b/core/filterpresettable.h new file mode 100644 index 000000000..849c5a48a --- /dev/null +++ b/core/filterpresettable.h @@ -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 +#include + +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 +{ + 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 diff --git a/core/load-git.cpp b/core/load-git.cpp index 96a42778c..487402b14 100644 --- a/core/load-git.cpp +++ b/core/load-git.cpp @@ -1179,10 +1179,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(); @@ -1216,14 +1216,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! */ @@ -1770,7 +1770,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; diff --git a/core/parse-xml.cpp b/core/parse-xml.cpp index 995314a36..869599edb 100644 --- a/core/parse-xml.cpp +++ b/core/parse-xml.cpp @@ -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); } diff --git a/core/parse.cpp b/core/parse.cpp index 96352b709..a217b4b9d 100644 --- a/core/parse.cpp +++ b/core/parse.cpp @@ -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(); diff --git a/core/save-git.cpp b/core/save-git.cpp index 49c4e65d6..62dc58a66 100644 --- a/core/save-git.cpp +++ b/core/save-git.cpp @@ -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)); } diff --git a/core/save-xml.cpp b/core/save-xml.cpp index cefa53f5a..29011c175 100644 --- a/core/save-xml.cpp +++ b/core/save-xml.cpp @@ -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, "\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, " \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, " ", 1); show_utf8(b, fulltext.c_str(), "", "\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, " 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); diff --git a/desktop-widgets/filterwidget.cpp b/desktop-widgets/filterwidget.cpp index b4d3188cf..f6ae3c55f 100644 --- a/desktop-widgets/filterwidget.cpp +++ b/desktop-widgets/filterwidget.cpp @@ -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 diff --git a/desktop-widgets/simplewidgets.cpp b/desktop-widgets/simplewidgets.cpp index 31c46d314..16dae6a5e 100644 --- a/desktop-widgets/simplewidgets.cpp +++ b/desktop-widgets/simplewidgets.cpp @@ -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); } diff --git a/qt-models/filterpresetmodel.cpp b/qt-models/filterpresetmodel.cpp index 52276315e..a78be8d24 100644 --- a/qt-models/filterpresetmodel.cpp +++ b/qt-models/filterpresetmodel.cpp @@ -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(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(divelog.filter_presets.size()); } void FilterPresetModel::reset()