filter: add primitive filter presets

Add a rudimentary list of filter presets to the core. The list
is sorted by name. Access is provided via a C interface so that
the presets can be written to the git and XML logs. Internally,
the list is realized by a C++ vector for convenience (euphemism for
laziness).

Morover, a C++ interface is provided for the UI. Currently names of
the presets cannot be edited, since this would mean that the order
of the list changes. This may be implemented later if required.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2020-05-26 18:32:52 +02:00 committed by Dirk Hohndel
parent 634e26cbce
commit 937fdb500b
5 changed files with 223 additions and 0 deletions

View file

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

View file

@ -7,6 +7,7 @@
#include "device.h"
#include "divesite.h"
#include "dive.h"
#include "filterpreset.h"
#include "fulltext.h"
#include "planner.h"
#include "qthelper.h"
@ -1376,6 +1377,7 @@ void clear_dive_file_data()
clear_dive(&displayed_dive);
clear_device_nodes();
clear_events();
clear_filter_presets();
reset_min_datafile_version();
clear_git_id();

144
core/filterpreset.cpp Normal file
View file

@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0
#include "filterpreset.h"
#include "qthelper.h"
#include "subsurface-string.h"
std::vector<filter_preset> filter_preset_table;
extern "C" void clear_filter_presets(void)
{
filter_preset_table.clear();
}
extern "C" int filter_presets_count(void)
{
return (int)filter_preset_table.size();
}
extern "C" char *filter_preset_name(int preset)
{
return copy_qstring(filter_preset_name_qstring(preset));
}
extern "C" char *filter_preset_fulltext_query(int preset)
{
return copy_qstring(filter_preset_table[preset].data.fullText.originalQuery);
}
extern "C" const char *filter_preset_fulltext_mode(int preset)
{
switch (filter_preset_table[preset].data.fulltextStringMode) {
default:
case StringFilterMode::SUBSTRING:
return "substring";
case StringFilterMode::STARTSWITH:
return "startswith";
case StringFilterMode::EXACT:
return "exact";
}
}
extern "C" void filter_preset_set_fulltext(struct filter_preset *preset, const char *fulltext, const char *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;
}
extern "C" int filter_preset_constraint_count(int preset)
{
return (int)filter_preset_table[preset].data.constraints.size();
}
extern "C" const filter_constraint *filter_preset_constraint(int preset, int constraint)
{
return &filter_preset_table[preset].data.constraints[constraint];
}
extern "C" struct filter_preset *alloc_filter_preset()
{
return new filter_preset;
}
extern "C" void free_filter_preset(const struct filter_preset *preset)
{
delete preset;
}
extern "C" void filter_preset_set_name(struct filter_preset *preset, const char *name)
{
preset->name = name;
}
static int filter_preset_add_to_table(const QString &name, const FilterData &d, filter_preset_table_t &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 QString get_unique_preset_name(const QString &orig, const filter_preset_table_t &table)
{
QString 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 + "#" + QString::number(count);
++count;
}
return res;
}
extern "C" void add_filter_preset_to_table(const struct filter_preset *preset, filter_preset_table_t *table)
{
QString name = get_unique_preset_name(preset->name, *table);
filter_preset_add_to_table(name, preset->data, *table);
}
extern "C" 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 QString &name)
{
auto it = std::find_if(filter_preset_table.begin(), filter_preset_table.end(),
[&name] (filter_preset &p) { return p.name == name; });
return it != filter_preset_table.end() ? it - filter_preset_table.begin() : -1;
}
QString filter_preset_name_qstring(int preset)
{
return filter_preset_table[preset].name;
}
void filter_preset_set(int preset, const FilterData &data)
{
filter_preset_table[preset].data = data;
}
FilterData filter_preset_get(int preset)
{
return filter_preset_table[preset].data;
}
int filter_preset_add(const QString &name, const FilterData &d)
{
return filter_preset_add_to_table(name, d, filter_preset_table);
}
void filter_preset_delete(int preset)
{
filter_preset_table.erase(filter_preset_table.begin() + preset);
}

73
core/filterpreset.h Normal file
View file

@ -0,0 +1,73 @@
// 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
struct dive;
struct filter_constraint;
// So that we can pass filter preset table between C and C++ we define
// it as an opaque type in C. Thus we can easily create the table in C++
// without having to do our own memory management and pass pointers to
// void through C.
#ifdef __cplusplus
#include "divefilter.h"
#include <vector>
#include <QStringList>
struct filter_preset {
QString name;
FilterData data;
};
using filter_preset_table_t = std::vector<filter_preset>;
extern filter_preset_table_t filter_preset_table;
#else
struct filter_preset;
typedef void filter_preset_table_t;
#endif
#ifdef __cplusplus
extern "C" {
#endif
// The C IO code accesses the filter presets via integer indices.
extern void clear_filter_presets(void);
extern int filter_presets_count(void);
extern char *filter_preset_name(int preset); // name of filter preset - caller must free the result.
extern char *filter_preset_fulltext_query(int preset); // fulltext query of filter preset - caller must free the result.
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 struct filter_preset *alloc_filter_preset();
extern void free_filter_preset(const struct filter_preset *preset);
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, filter_preset_table_t *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.
#ifdef __cplusplus
}
#endif
// C++ only functions
#ifdef __cplusplus
struct FilterData;
int filter_preset_id(const QString &s); // for now, we assume that names are unique. returns -1 if no preset with that name.
QString filter_preset_name_qstring(int preset);
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 QString &name, const FilterData &d); // returns point of insertion
void filter_preset_delete(int preset);
#endif
#endif

View file

@ -55,6 +55,7 @@ SOURCES += ../../subsurface-mobile-main.cpp \
../../core/dive.c \
../../core/divefilter.cpp \
../../core/filterconstraint.cpp \
../../core/filterpreset.cpp \
../../core/divelist.c \
../../core/gas-model.c \
../../core/gaspressures.c \
@ -220,6 +221,7 @@ HEADERS += \
../../core/display.h \
../../core/divefilter.h \
../../core/filterconstraint.h \
../../core/filterpreset.h \
../../core/divelist.h \
../../core/divelogexportlogic.h \
../../core/divesitehelpers.h \