Allow "field:query" in the quick filter bar

This commit is contained in:
Twan van Laarhoven
2020-04-27 01:22:40 +02:00
parent 1a39b85b73
commit 7ef0b885bb
6 changed files with 76 additions and 46 deletions
+3 -3
View File
@@ -52,11 +52,11 @@ String Card::identification() const {
}
}
bool Card::contains(String const& query) const {
bool Card::contains(QuickFilterPart const& query) const {
FOR_EACH_CONST(v, data) {
if (find_i(v->toString(),query) != String::npos) return true;
if (query.match(v->fieldP->name, v->toString())) return true;
}
if (find_i(notes,query) != String::npos) return true;
if (query.match(_("notes"), notes)) return true;
return false;
}
+2 -3
View File
@@ -11,6 +11,7 @@
#include <util/prec.hpp>
#include <util/reflect.hpp>
#include <util/error.hpp>
#include <data/filter.hpp>
#include <data/field.hpp> // for Card::value
class Game;
@@ -61,9 +62,7 @@ class Card : public IntrusivePtrVirtualBase {
/** May return "" */
String identification() const;
/// Does any field contains the given query string?
bool contains(String const& query) const;
/// Does this card contain each of the words in the query string?
bool contains_words(String const& query) const;
bool contains(QuickFilterPart const& query) const;
/// Find a value in the data by name and type
template <typename T> T& value(const String& name) {
+42
View File
@@ -0,0 +1,42 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/filter.hpp>
// ----------------------------------------------------------------------------- : Quick filter
vector<QuickFilterPart> parse_quicksearch_query(String const& query) {
// iterate over the components of the query
vector<QuickFilterPart> parts;
QuickFilterPart part;
bool quoted = false;
for (wxUniChar c : query) {
if (isSpace(c) && !quoted) {
if (!part.query.empty()) {
parts.push_back(part);
part = {};
}
} else if (c == _('"')) {
// begin/end quoted string, match exactly
quoted = !quoted;
} else if (c == _(':') && part.type.empty()) {
part.type = part.query;
part.query.clear();
} else if (c == _('!') && part.query.empty() && part.type.empty()) {
// negate
part.need_match = false;
} else {
part.query += c;
}
}
if (!part.query.empty()) {
parts.push_back(part);
}
return parts;
}
+22 -34
View File
@@ -35,37 +35,26 @@ class Filter : public IntrusivePtrVirtualBase {
// ----------------------------------------------------------------------------- : Quick search
struct QuickFilterQuery {
String type;
String query;
bool match(String const& key, String const& x) const {
return (type.empty() || find_i(key,type) != String::npos) && find_i(x,query) != String::npos;
}
};
struct QuickFilterPart : QuickFilterQuery {
bool need_match = true;
};
/// Parse a quick filter string
vector<QuickFilterPart> parse_quicksearch_query(String const& query);
/// Does the given object match the quick search query?
template <typename T>
bool match_quicksearch_query(String const& query, T const& object) {
bool need_match = true;
// iterate over the components of the query
for (size_t i = 0 ; i < query.size() ; ) {
if (query.GetChar(i) == _(' ')) {
// skip spaces
i++;
} else if (query.GetChar(i) == _('-')) {
// negate the next query, i.e. match only if it is not on the card
need_match = !need_match;
i++;
} else {
size_t end, next;
if (query.GetChar(i) == _('"')) {
// quoted string, match exactly
i++;
end =query.find_first_of(_('"'),i);
next = min(end,query.size()) + 1;
} else {
// single word
next = end = query.find_first_of(_(' '),i);
}
bool match = object.contains(query.substr(i,end-i));
if (match != need_match) {
return false;
}
need_match = true; // next word is no longer negated
i = next;
}
bool match_quicksearch_query(vector<QuickFilterPart> const& query, T const& object) {
for (auto const& part : query) {
if (object.contains(part) != part.need_match) return false;
}
return true;
}
@@ -73,13 +62,12 @@ bool match_quicksearch_query(String const& query, T const& object) {
/// A filter function that searches for objects containing a string
template <typename T>
class QuickFilter : public Filter<T> {
public:
using typename Filter<T>::TP;
QuickFilter(String const& query) : query(query) {}
public:
QuickFilter(String const& query) : query(parse_quicksearch_query(query)) {}
virtual bool keep(T const& x) const {
return match_quicksearch_query(query, x);
}
private:
String query;
private:
vector<QuickFilterPart> query;
};
+5 -5
View File
@@ -73,11 +73,11 @@ void read_compat(Reader& handler, Keyword* k) {
}
}
bool Keyword::contains(String const& query) const {
if (find_i(keyword,query) != String::npos) return true;
if (find_i(rules,query) != String::npos) return true;
if (find_i(match,query) != String::npos) return true;
if (find_i(reminder.get(),query) != String::npos) return true;
bool Keyword::contains(QuickFilterPart const& query) const {
if (query.match(_("keyword"), keyword)) return true;
if (query.match(_("rules"), rules)) return true;
if (query.match(_("match"), match)) return true;
if (query.match(_("reminder"), reminder.get())) return true;
return false;
}
+2 -1
View File
@@ -12,6 +12,7 @@
#include <script/scriptable.hpp>
#include <util/dynamic_arg.hpp>
#include <util/regex.hpp>
#include <data/filter.hpp>
DECLARE_POINTER_TYPE(KeywordParam);
DECLARE_POINTER_TYPE(KeywordMode);
@@ -116,7 +117,7 @@ class Keyword : public IntrusivePtrVirtualBase {
void prepare(const vector<KeywordParamP>& param_types, bool force = false);
/// Does the keyword contain the given query word?
bool contains(String const& word) const;
bool contains(QuickFilterPart const& query) const;
DECLARE_REFLECTION();
};