mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
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:
parent
2bdcdab391
commit
91968ac579
20 changed files with 212 additions and 250 deletions
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
53
core/filterpresettable.cpp
Normal file
53
core/filterpresettable.cpp
Normal 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
25
core/filterpresettable.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Add table
Reference in a new issue