diff --git a/src/data/card.cpp b/src/data/card.cpp index 1fa92a02..bd2cbca9 100644 --- a/src/data/card.cpp +++ b/src/data/card.cpp @@ -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; } diff --git a/src/data/card.hpp b/src/data/card.hpp index 1d930feb..f1222757 100644 --- a/src/data/card.hpp +++ b/src/data/card.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include // 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 T& value(const String& name) { diff --git a/src/data/filter.cpp b/src/data/filter.cpp new file mode 100644 index 00000000..d187510a --- /dev/null +++ b/src/data/filter.cpp @@ -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 +#include + +// ----------------------------------------------------------------------------- : Quick filter + +vector parse_quicksearch_query(String const& query) { + // iterate over the components of the query + vector 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; +} \ No newline at end of file diff --git a/src/data/filter.hpp b/src/data/filter.hpp index 58addbb6..8e4f3fc7 100644 --- a/src/data/filter.hpp +++ b/src/data/filter.hpp @@ -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 parse_quicksearch_query(String const& query); + /// Does the given object match the quick search query? template -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 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 class QuickFilter : public Filter { - public: - using typename Filter::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 query; }; diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp index 4fd31ee4..95c20a42 100644 --- a/src/data/keyword.cpp +++ b/src/data/keyword.cpp @@ -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; } diff --git a/src/data/keyword.hpp b/src/data/keyword.hpp index 86db69c7..37324aef 100644 --- a/src/data/keyword.hpp +++ b/src/data/keyword.hpp @@ -12,6 +12,7 @@ #include