diff --git a/cockatrice/src/filters/deck_filter_string.cpp b/cockatrice/src/filters/deck_filter_string.cpp index b53093500..a2b7519a8 100644 --- a/cockatrice/src/filters/deck_filter_string.cpp +++ b/cockatrice/src/filters/deck_filter_string.cpp @@ -47,12 +47,7 @@ static std::once_flag init; // per-instance state. The card language that the nested [[card name]] search matches // against is passed through this thread-local context, which is live only while a // DeckFilterString is being parsed, and copied into the nested FilterString closures. -struct DeckSearchLanguageContext -{ - QString searchLanguage; - SearchLanguageMode searchLanguageMode = SearchLanguageMode::English; -}; -thread_local DeckSearchLanguageContext deckSearchLanguageContext; +thread_local CardSearchLanguage deckSearchLanguageContext; static void setupParserRules() { @@ -127,9 +122,7 @@ static void setupParserRules() // actual functionality search["DeckContentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - const QString searchLanguage = deckSearchLanguageContext.searchLanguage; - const SearchLanguageMode searchLanguageMode = deckSearchLanguageContext.searchLanguageMode; - auto cardFilter = FilterString(std::any_cast(sv[0]), searchLanguage, searchLanguageMode); + auto cardFilter = FilterString(std::any_cast(sv[0]), deckSearchLanguageContext); auto numberMatcher = sv.size() > 1 ? std::any_cast(sv[1]) : [](int count) { return count > 0; }; return [=](const DeckSearchData &data) -> bool { @@ -199,9 +192,7 @@ DeckFilterString::DeckFilterString() _error = "Not initialized"; } -DeckFilterString::DeckFilterString(const QString &expr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) +DeckFilterString::DeckFilterString(const QString &expr, const CardSearchLanguage &searchLanguage) { QByteArray ba = expr.simplified().toUtf8(); @@ -214,7 +205,7 @@ DeckFilterString::DeckFilterString(const QString &expr, return; } - deckSearchLanguageContext = DeckSearchLanguageContext{searchLanguage, searchLanguageMode}; + deckSearchLanguageContext = searchLanguage; search.set_logger([&](size_t /*ln*/, size_t col, const std::string &msg) { _error = QString("Error at position %1: %2").arg(col).arg(QString::fromStdString(msg)); diff --git a/cockatrice/src/filters/deck_filter_string.h b/cockatrice/src/filters/deck_filter_string.h index 1189c0db5..5b1419004 100644 --- a/cockatrice/src/filters/deck_filter_string.h +++ b/cockatrice/src/filters/deck_filter_string.h @@ -36,9 +36,7 @@ class DeckFilterString { public: DeckFilterString(); - explicit DeckFilterString(const QString &expr, - const QString &searchLanguage = QString(), - SearchLanguageMode searchLanguageMode = SearchLanguageMode::English); + explicit DeckFilterString(const QString &expr, const CardSearchLanguage &searchLanguage = {}); bool check(const DeckSearchData &data) const { return filter(data); diff --git a/cockatrice/src/game_graphics/dialogs/dlg_create_token.cpp b/cockatrice/src/game_graphics/dialogs/dlg_create_token.cpp index f02de7f53..0c02a4462 100644 --- a/cockatrice/src/game_graphics/dialogs/dlg_create_token.cpp +++ b/cockatrice/src/game_graphics/dialogs/dlg_create_token.cpp @@ -92,8 +92,8 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay(); const auto applyCardSearchLanguage = [this, cardsDisplay]() { - cardDatabaseDisplayModel->setSearchLanguage( - cardsDisplay->getCardLang(), static_cast(cardsDisplay->getCardSearchLanguage())); + cardDatabaseDisplayModel->setSearchLanguage(CardSearchLanguage{ + cardsDisplay->getCardLang(), static_cast(cardsDisplay->getCardSearchLanguage())}); }; applyCardSearchLanguage(); connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, applyCardSearchLanguage); diff --git a/cockatrice/src/game_graphics/zones/view_zone.cpp b/cockatrice/src/game_graphics/zones/view_zone.cpp index a82444821..5bd5d262f 100644 --- a/cockatrice/src/game_graphics/zones/view_zone.cpp +++ b/cockatrice/src/game_graphics/zones/view_zone.cpp @@ -257,8 +257,9 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca void ZoneViewZone::setFilterString(const QString &_filterString) { const CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay(); - filterString = FilterString(_filterString, cardsDisplay.getCardLang(), - static_cast(cardsDisplay.getCardSearchLanguage())); + filterString = FilterString( + _filterString, CardSearchLanguage{cardsDisplay.getCardLang(), + static_cast(cardsDisplay.getCardSearchLanguage())}); reorganizeCards(); } diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp index 116cf3498..81ae03451 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp @@ -44,8 +44,8 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay(); const auto applyCardSearchLanguage = [this, cardsDisplay]() { - databaseDisplayModel->setSearchLanguage(cardsDisplay->getCardLang(), - static_cast(cardsDisplay->getCardSearchLanguage())); + databaseDisplayModel->setSearchLanguage(CardSearchLanguage{ + cardsDisplay->getCardLang(), static_cast(cardsDisplay->getCardSearchLanguage())}); }; applyCardSearchLanguage(); connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, applyCardSearchLanguage); diff --git a/cockatrice/src/interface/widgets/utility/completer_utils.cpp b/cockatrice/src/interface/widgets/utility/completer_utils.cpp index 3c8cf69d4..23ddb30b0 100644 --- a/cockatrice/src/interface/widgets/utility/completer_utils.cpp +++ b/cockatrice/src/interface/widgets/utility/completer_utils.cpp @@ -18,9 +18,9 @@ namespace { void applyCardSearchLanguage(CardSearchModel *searchModel) { - const auto &cardsDisplay = SettingsCache::instance().cardsDisplay(); - searchModel->setSearchLanguage(cardsDisplay.getCardLang(), - static_cast(cardsDisplay.getCardSearchLanguage())); + const CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay(); + searchModel->setSearchLanguage(CardSearchLanguage{ + cardsDisplay.getCardLang(), static_cast(cardsDisplay.getCardSearchLanguage())}); } } // namespace diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp index eae7d4b81..656639a3e 100644 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp @@ -43,8 +43,8 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent, CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay(); const auto applyCardSearchLanguage = [this, cardsDisplay]() { - databaseDisplayModel->setSearchLanguage(cardsDisplay->getCardLang(), - static_cast(cardsDisplay->getCardSearchLanguage())); + databaseDisplayModel->setSearchLanguage(CardSearchLanguage{ + cardsDisplay->getCardLang(), static_cast(cardsDisplay->getCardSearchLanguage())}); }; applyCardSearchLanguage(); connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, applyCardSearchLanguage); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_filter_proxy_model.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_filter_proxy_model.cpp index 67451d0a2..61e2f18ad 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_filter_proxy_model.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_filter_proxy_model.cpp @@ -191,8 +191,9 @@ void VisualDeckStorageSortFilterProxyModel::updateSearchMatches() } const auto &cardsDisplay = SettingsCache::instance().cardsDisplay(); - DeckFilterString filterString(searchText, cardsDisplay.getCardLang(), - static_cast(cardsDisplay.getCardSearchLanguage())); + DeckFilterString filterString( + searchText, CardSearchLanguage{cardsDisplay.getCardLang(), + static_cast(cardsDisplay.getCardSearchLanguage())}); for (int row = 0; row < count; ++row) { const DeckPreviewData &data = source->dataForRow(row); diff --git a/libcockatrice_card/libcockatrice/card/card_localization.h b/libcockatrice_card/libcockatrice/card/card_localization.h index 785aaa527..1bde506cb 100644 --- a/libcockatrice_card/libcockatrice/card/card_localization.h +++ b/libcockatrice_card/libcockatrice/card/card_localization.h @@ -14,6 +14,32 @@ enum class SearchLanguageMode Both ///< Search both the English and the selected card language names and texts. }; +/** + * @brief The card language and matching mode searches run against. + * + * Bundles the card language code configured in the settings with the + * SearchLanguageMode, so entry points take one value instead of two related + * parameters. + */ +struct CardSearchLanguage +{ + QString language; ///< Card language code (e.g. "de"); empty means the English fallback. + SearchLanguageMode mode = SearchLanguageMode::English; ///< How the language participates in the search. + + /** + * @brief Whether only the English card data is searched. + * + * @return True when no card language is selected or English itself is selected. + */ + [[nodiscard]] bool isEnglishOnly() const + { + return language.isEmpty() || language == QLatin1String("en"); + } + + bool operator==(const CardSearchLanguage &) const = default; + bool operator!=(const CardSearchLanguage &) const = default; +}; + /** * @namespace CardLocalization * @ingroup Cards diff --git a/libcockatrice_filters/libcockatrice/filters/filter_string.cpp b/libcockatrice_filters/libcockatrice/filters/filter_string.cpp index 47d1d0f61..1b63ca122 100644 --- a/libcockatrice_filters/libcockatrice/filters/filter_string.cpp +++ b/libcockatrice_filters/libcockatrice/filters/filter_string.cpp @@ -80,34 +80,27 @@ static std::once_flag init; // and OracleQuery rule actions through this thread-local context, which is live only // while a FilterString is being parsed. The rule actions copy it into the filter // closures they produce, so card evaluation never reads process-global state. -struct SearchLanguageContext -{ - QString searchLanguage; - SearchLanguageMode searchLanguageMode = SearchLanguageMode::English; -}; -thread_local SearchLanguageContext searchLanguageContext; +thread_local CardSearchLanguage searchLanguageContext; namespace { bool matchesInSearchLanguage(const QString &english, const QString &localized, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode, + const CardSearchLanguage &searchLanguage, const StringMatcher &matcher) { - if (searchLanguageMode == SearchLanguageMode::English) { + if (searchLanguage.mode == SearchLanguageMode::English) { return matcher(english); } - if (searchLanguageMode == SearchLanguageMode::Both && matcher(english)) { - return true; - } - - if (searchLanguage.isEmpty() || searchLanguage == "en") { + if (searchLanguage.mode == SearchLanguageMode::Both) { + if (!searchLanguage.isEnglishOnly() && matcher(localized)) { + return true; + } return matcher(english); } - return matcher(localized); + return searchLanguage.isEnglishOnly() ? matcher(english) : matcher(localized); } } // namespace @@ -370,11 +363,10 @@ static void setupParserRules() search["OracleQuery"] = [](const peg::SemanticValues &sv) -> Filter { const auto matcher = std::any_cast(sv[0]); - const QString searchLanguage = searchLanguageContext.searchLanguage; - const SearchLanguageMode searchLanguageMode = searchLanguageContext.searchLanguageMode; + const CardSearchLanguage searchLanguage = searchLanguageContext; return [=](const CardData &x) { - return matchesInSearchLanguage(x->getText(), x->getLocalizedText(searchLanguage), searchLanguage, - searchLanguageMode, matcher); + return matchesInSearchLanguage(x->getText(), x->getLocalizedText(searchLanguage.language), searchLanguage, + matcher); }; }; @@ -452,11 +444,10 @@ static void setupParserRules() }; search["GenericQuery"] = [](const peg::SemanticValues &sv) -> Filter { const auto matcher = std::any_cast(sv[0]); - const QString searchLanguage = searchLanguageContext.searchLanguage; - const SearchLanguageMode searchLanguageMode = searchLanguageContext.searchLanguageMode; + const CardSearchLanguage searchLanguage = searchLanguageContext; return [=](const CardData &x) { - return matchesInSearchLanguage(x->getName(), x->getLocalizedName(searchLanguage), searchLanguage, - searchLanguageMode, matcher); + return matchesInSearchLanguage(x->getName(), x->getLocalizedName(searchLanguage.language), searchLanguage, + matcher); }; }; @@ -472,7 +463,7 @@ FilterString::FilterString() _error = "Not initialized"; } -FilterString::FilterString(const QString &expr, const QString &searchLanguage, SearchLanguageMode searchLanguageMode) +FilterString::FilterString(const QString &expr, const CardSearchLanguage &searchLanguage) { QByteArray ba = expr.simplified().toUtf8(); @@ -485,7 +476,7 @@ FilterString::FilterString(const QString &expr, const QString &searchLanguage, S return; } - searchLanguageContext = SearchLanguageContext{searchLanguage, searchLanguageMode}; + searchLanguageContext = searchLanguage; search.set_logger([&](size_t /*ln*/, size_t col, const std::string &msg) { _error = QString("Error at position %1: %2").arg(col).arg(QString::fromStdString(msg)); diff --git a/libcockatrice_filters/libcockatrice/filters/filter_string.h b/libcockatrice_filters/libcockatrice/filters/filter_string.h index 5709e9108..015df0cf4 100644 --- a/libcockatrice_filters/libcockatrice/filters/filter_string.h +++ b/libcockatrice_filters/libcockatrice/filters/filter_string.h @@ -36,9 +36,7 @@ class FilterString { public: FilterString(); - explicit FilterString(const QString &exp, - const QString &searchLanguage = QString(), - SearchLanguageMode searchLanguageMode = SearchLanguageMode::English); + explicit FilterString(const QString &exp, const CardSearchLanguage &searchLanguage = {}); [[nodiscard]] bool check(const CardData &card) const { if (card.isNull()) { diff --git a/libcockatrice_filters/libcockatrice/filters/filter_tree.cpp b/libcockatrice_filters/libcockatrice/filters/filter_tree.cpp index 3f54b556e..a5d91d9d3 100644 --- a/libcockatrice_filters/libcockatrice/filters/filter_tree.cpp +++ b/libcockatrice_filters/libcockatrice/filters/filter_tree.cpp @@ -102,15 +102,14 @@ FilterTreeNode *FilterItemList::termNode(const QString &term) bool FilterItemList::testTypeAnd(const CardInfoPtr info, CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const + const CardSearchLanguage &searchLanguage) const { for (auto i = childNodes.constBegin(); i != childNodes.constEnd(); i++) { if (!(*i)->isEnabled()) { continue; } - if (!(*i)->acceptCardAttr(info, attr, searchLanguage, searchLanguageMode)) { + if (!(*i)->acceptCardAttr(info, attr, searchLanguage)) { return false; } } @@ -120,17 +119,15 @@ bool FilterItemList::testTypeAnd(const CardInfoPtr info, bool FilterItemList::testTypeAndNot(const CardInfoPtr info, CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const + const CardSearchLanguage &searchLanguage) const { // if any one in the list is true, return false - return !testTypeOr(info, attr, searchLanguage, searchLanguageMode); + return !testTypeOr(info, attr, searchLanguage); } bool FilterItemList::testTypeOr(const CardInfoPtr info, CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const + const CardSearchLanguage &searchLanguage) const { bool noChildEnabledChild = true; @@ -143,7 +140,7 @@ bool FilterItemList::testTypeOr(const CardInfoPtr info, noChildEnabledChild = false; } - if ((*i)->acceptCardAttr(info, attr, searchLanguage, searchLanguageMode)) { + if ((*i)->acceptCardAttr(info, attr, searchLanguage)) { return true; } } @@ -153,49 +150,56 @@ bool FilterItemList::testTypeOr(const CardInfoPtr info, bool FilterItemList::testTypeOrNot(const CardInfoPtr info, CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const + const CardSearchLanguage &searchLanguage) const { // if any one in the list is false, return true - return !testTypeAnd(info, attr, searchLanguage, searchLanguageMode); + return !testTypeAnd(info, attr, searchLanguage); } -bool FilterItem::acceptName(const CardInfoPtr info, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const +bool FilterItem::acceptName(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const { - if (searchLanguageMode == SearchLanguageMode::English) { - return info->getName().contains(term, Qt::CaseInsensitive); + const QString &englishName = info->getName(); + const QString &localizedName = info->getLocalizedName(searchLanguage.language); + + switch (searchLanguage.mode) { + case SearchLanguageMode::English: + return englishName.contains(term, Qt::CaseInsensitive); + case SearchLanguageMode::Both: + if (englishName.contains(term, Qt::CaseInsensitive)) { + return true; + } + return !searchLanguage.isEnglishOnly() && localizedName.contains(term, Qt::CaseInsensitive); + case SearchLanguageMode::Selected: + if (searchLanguage.isEnglishOnly()) { + return englishName.contains(term, Qt::CaseInsensitive); + } + return localizedName.contains(term, Qt::CaseInsensitive); } - if (searchLanguageMode == SearchLanguageMode::Both && info->getName().contains(term, Qt::CaseInsensitive)) { - return true; - } - - if (searchLanguage.isEmpty() || searchLanguage == "en") { - return info->getName().contains(term, Qt::CaseInsensitive); - } - - return info->getLocalizedName(searchLanguage).contains(term, Qt::CaseInsensitive); + return false; } -bool FilterItem::acceptNameExact(const CardInfoPtr info, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const +bool FilterItem::acceptNameExact(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const { - if (searchLanguageMode == SearchLanguageMode::English) { - return info->getName() == term; + const QString &englishName = info->getName(); + const QString &localizedName = info->getLocalizedName(searchLanguage.language); + + switch (searchLanguage.mode) { + case SearchLanguageMode::English: + return englishName == term; + case SearchLanguageMode::Both: + if (englishName == term) { + return true; + } + return !searchLanguage.isEnglishOnly() && localizedName == term; + case SearchLanguageMode::Selected: + if (searchLanguage.isEnglishOnly()) { + return englishName == term; + } + return localizedName == term; } - if (searchLanguageMode == SearchLanguageMode::Both && info->getName() == term) { - return true; - } - - if (searchLanguage.isEmpty() || searchLanguage == "en") { - return info->getName() == term; - } - - return info->getLocalizedName(searchLanguage) == term; + return false; } bool FilterItem::acceptType(const CardInfoPtr info) const @@ -253,23 +257,27 @@ bool FilterItem::acceptColor(const CardInfoPtr info) const return match_count == converted_term.length(); } -bool FilterItem::acceptText(const CardInfoPtr info, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const +bool FilterItem::acceptText(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const { - if (searchLanguageMode == SearchLanguageMode::English) { - return info->getText().contains(term, Qt::CaseInsensitive); + const QString &englishText = info->getText(); + const QString &localizedText = info->getLocalizedText(searchLanguage.language); + + switch (searchLanguage.mode) { + case SearchLanguageMode::English: + return englishText.contains(term, Qt::CaseInsensitive); + case SearchLanguageMode::Both: + if (englishText.contains(term, Qt::CaseInsensitive)) { + return true; + } + return !searchLanguage.isEnglishOnly() && localizedText.contains(term, Qt::CaseInsensitive); + case SearchLanguageMode::Selected: + if (searchLanguage.isEnglishOnly()) { + return englishText.contains(term, Qt::CaseInsensitive); + } + return localizedText.contains(term, Qt::CaseInsensitive); } - if (searchLanguageMode == SearchLanguageMode::Both && info->getText().contains(term, Qt::CaseInsensitive)) { - return true; - } - - if (searchLanguage.isEmpty() || searchLanguage == "en") { - return info->getText().contains(term, Qt::CaseInsensitive); - } - - return info->getLocalizedText(searchLanguage).contains(term, Qt::CaseInsensitive); + return false; } bool FilterItem::acceptSet(const CardInfoPtr info) const @@ -458,20 +466,19 @@ bool FilterItem::relationCheck(int cardInfo) const bool FilterItem::acceptCardAttr(const CardInfoPtr info, CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const + const CardSearchLanguage &searchLanguage) const { switch (attr) { case CardFilter::AttrName: - return acceptName(info, searchLanguage, searchLanguageMode); + return acceptName(info, searchLanguage); case CardFilter::AttrNameExact: - return acceptNameExact(info, searchLanguage, searchLanguageMode); + return acceptNameExact(info, searchLanguage); case CardFilter::AttrType: return acceptType(info); case CardFilter::AttrColor: return acceptColor(info); case CardFilter::AttrText: - return acceptText(info, searchLanguage, searchLanguageMode); + return acceptText(info, searchLanguage); case CardFilter::AttrSet: return acceptSet(info); case CardFilter::AttrManaCost: @@ -541,21 +548,18 @@ FilterTreeNode *FilterTree::termNode(const CardFilter *f) return termNode(f->attr(), f->type(), f->term()); } -bool FilterTree::testAttr(const CardInfoPtr info, - const LogicMap *lm, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const +bool FilterTree::testAttr(const CardInfoPtr info, const LogicMap *lm, const CardSearchLanguage &searchLanguage) const { const FilterItemList *fil; bool status = true; fil = lm->findTypeList(CardFilter::TypeAnd); - if (fil && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr, searchLanguage, searchLanguageMode)) { + if (fil && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr, searchLanguage)) { return false; } fil = lm->findTypeList(CardFilter::TypeAndNot); - if (fil && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr, searchLanguage, searchLanguageMode)) { + if (fil && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr, searchLanguage)) { return false; } @@ -564,25 +568,23 @@ bool FilterTree::testAttr(const CardInfoPtr info, status = false; // if this is true we can return because it is OR'd with the OrNot list - if (fil->testTypeOr(info, lm->attr, searchLanguage, searchLanguageMode)) { + if (fil->testTypeOr(info, lm->attr, searchLanguage)) { return true; } } fil = lm->findTypeList(CardFilter::TypeOrNot); - if (fil && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr, searchLanguage, searchLanguageMode)) { + if (fil && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr, searchLanguage)) { return true; } return status; } -bool FilterTree::acceptsCard(const CardInfoPtr info, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const +bool FilterTree::acceptsCard(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const { for (auto i = childNodes.constBegin(); i != childNodes.constEnd(); i++) { - if ((*i)->isEnabled() && !testAttr(info, *i, searchLanguage, searchLanguageMode)) { + if ((*i)->isEnabled() && !testAttr(info, *i, searchLanguage)) { return false; } } diff --git a/libcockatrice_filters/libcockatrice/filters/filter_tree.h b/libcockatrice_filters/libcockatrice/filters/filter_tree.h index 116c01dcc..dd47a1ebc 100644 --- a/libcockatrice_filters/libcockatrice/filters/filter_tree.h +++ b/libcockatrice_filters/libcockatrice/filters/filter_tree.h @@ -168,22 +168,14 @@ public: return CardFilter::typeName(type); } - [[nodiscard]] bool testTypeAnd(CardInfoPtr info, - CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const; - [[nodiscard]] bool testTypeAndNot(CardInfoPtr info, - CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const; - [[nodiscard]] bool testTypeOr(CardInfoPtr info, - CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const; - [[nodiscard]] bool testTypeOrNot(CardInfoPtr info, - CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const; + [[nodiscard]] bool + testTypeAnd(CardInfoPtr info, CardFilter::Attr attr, const CardSearchLanguage &searchLanguage) const; + [[nodiscard]] bool + testTypeAndNot(CardInfoPtr info, CardFilter::Attr attr, const CardSearchLanguage &searchLanguage) const; + [[nodiscard]] bool + testTypeOr(CardInfoPtr info, CardFilter::Attr attr, const CardSearchLanguage &searchLanguage) const; + [[nodiscard]] bool + testTypeOrNot(CardInfoPtr info, CardFilter::Attr attr, const CardSearchLanguage &searchLanguage) const; }; class FilterItem : public FilterTreeNode @@ -220,26 +212,21 @@ public: return true; } - [[nodiscard]] bool - acceptName(CardInfoPtr info, const QString &searchLanguage, SearchLanguageMode searchLanguageMode) const; - [[nodiscard]] bool - acceptNameExact(CardInfoPtr info, const QString &searchLanguage, SearchLanguageMode searchLanguageMode) const; + [[nodiscard]] bool acceptName(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const; + [[nodiscard]] bool acceptNameExact(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const; [[nodiscard]] bool acceptType(CardInfoPtr info) const; [[nodiscard]] bool acceptMainType(CardInfoPtr info) const; [[nodiscard]] bool acceptSubType(CardInfoPtr info) const; [[nodiscard]] bool acceptColor(CardInfoPtr info) const; - [[nodiscard]] bool - acceptText(CardInfoPtr info, const QString &searchLanguage, SearchLanguageMode searchLanguageMode) const; + [[nodiscard]] bool acceptText(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const; [[nodiscard]] bool acceptSet(CardInfoPtr info) const; [[nodiscard]] bool acceptManaCost(CardInfoPtr info) const; [[nodiscard]] bool acceptCmc(CardInfoPtr info) const; [[nodiscard]] bool acceptPowerToughness(CardInfoPtr info, CardFilter::Attr attr) const; [[nodiscard]] bool acceptLoyalty(CardInfoPtr info) const; [[nodiscard]] bool acceptRarity(CardInfoPtr info) const; - [[nodiscard]] bool acceptCardAttr(CardInfoPtr info, - CardFilter::Attr attr, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const; + [[nodiscard]] bool + acceptCardAttr(CardInfoPtr info, CardFilter::Attr attr, const CardSearchLanguage &searchLanguage) const; [[nodiscard]] bool acceptFormat(CardInfoPtr info) const; [[nodiscard]] bool relationCheck(int cardInfo) const; }; @@ -259,10 +246,7 @@ private: LogicMap *attrLogicMap(CardFilter::Attr attr); FilterItemList *attrTypeList(CardFilter::Attr attr, CardFilter::Type type); - bool testAttr(CardInfoPtr info, - const LogicMap *lm, - const QString &searchLanguage, - SearchLanguageMode searchLanguageMode) const; + bool testAttr(CardInfoPtr info, const LogicMap *lm, const CardSearchLanguage &searchLanguage) const; void nodeChanged() const override { @@ -301,8 +285,7 @@ public: return 0; } - [[nodiscard]] bool - acceptsCard(CardInfoPtr info, const QString &searchLanguage, SearchLanguageMode searchLanguageMode) const; + [[nodiscard]] bool acceptsCard(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const; void removeFiltersByAttr(CardFilter::Attr filterType); void removeFilter(const CardFilter *toRemove); void clear(); diff --git a/libcockatrice_models/libcockatrice/models/database/card/card_search_model.cpp b/libcockatrice_models/libcockatrice/models/database/card/card_search_model.cpp index 3c876c10d..5d4e0ec9b 100644 --- a/libcockatrice_models/libcockatrice/models/database/card/card_search_model.cpp +++ b/libcockatrice_models/libcockatrice/models/database/card/card_search_model.cpp @@ -68,8 +68,8 @@ void CardSearchModel::updateSearchResults(const QString &query) // The completer suggestions match against the same languages the card // search uses, so typing a localized name finds the card. QString matchName = card->getName(); - if (searchLanguageMode != SearchLanguageMode::English && !searchLanguage.isEmpty() && searchLanguage != "en") { - matchName = card->getLocalizedName(searchLanguage); + if (searchLanguage.mode != SearchLanguageMode::English && !searchLanguage.isEnglishOnly()) { + matchName = card->getLocalizedName(searchLanguage.language); } const QString lowerName = matchName.toLower(); if (!lowerName.contains(lowerQuery)) { @@ -88,9 +88,9 @@ void CardSearchModel::updateSearchResults(const QString &query) auto sortByDistanceThenLength = [this](const SearchResult &a, const SearchResult &b) { QString nameA = a.card->getName(); QString nameB = b.card->getName(); - if (searchLanguageMode != SearchLanguageMode::English && !searchLanguage.isEmpty() && searchLanguage != "en") { - nameA = a.card->getLocalizedName(searchLanguage); - nameB = b.card->getLocalizedName(searchLanguage); + if (searchLanguage.mode != SearchLanguageMode::English && !searchLanguage.isEnglishOnly()) { + nameA = a.card->getLocalizedName(searchLanguage.language); + nameB = b.card->getLocalizedName(searchLanguage.language); } if (a.distance != b.distance) { return a.distance < b.distance; @@ -112,4 +112,4 @@ void CardSearchModel::updateSearchResults(const QString &query) } endResetModel(); -} +} \ No newline at end of file diff --git a/libcockatrice_models/libcockatrice/models/database/card/card_search_model.h b/libcockatrice_models/libcockatrice/models/database/card/card_search_model.h index 02f358eb1..5e810dffd 100644 --- a/libcockatrice_models/libcockatrice/models/database/card/card_search_model.h +++ b/libcockatrice_models/libcockatrice/models/database/card/card_search_model.h @@ -27,13 +27,12 @@ public: void updateSearchResults(const QString &query); // Update results based on input - void setSearchLanguage(const QString &searchLang, SearchLanguageMode mode) + void setSearchLanguage(const CardSearchLanguage &searchLang) { - if (searchLanguage == searchLang && searchLanguageMode == mode) { + if (searchLanguage == searchLang) { return; } searchLanguage = searchLang; - searchLanguageMode = mode; } private: @@ -45,8 +44,7 @@ private: CardDatabaseDisplayModel *sourceModel; QList searchResults; - QString searchLanguage; - SearchLanguageMode searchLanguageMode = SearchLanguageMode::English; + CardSearchLanguage searchLanguage; }; -#endif // CARD_SEARCH_MODEL_H +#endif // CARD_SEARCH_MODEL_H \ No newline at end of file diff --git a/libcockatrice_models/libcockatrice/models/database/card_database_display_model.cpp b/libcockatrice_models/libcockatrice/models/database/card_database_display_model.cpp index 514e1026c..7f89677c8 100644 --- a/libcockatrice_models/libcockatrice/models/database/card_database_display_model.cpp +++ b/libcockatrice_models/libcockatrice/models/database/card_database_display_model.cpp @@ -179,7 +179,7 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex } if (filterString != nullptr) { - if (filterTree != nullptr && !filterTree->acceptsCard(info, searchLanguage, searchLanguageMode)) { + if (filterTree != nullptr && !filterTree->acceptsCard(info, searchLanguage)) { return false; } return filterString->check(info); @@ -190,10 +190,14 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex bool CardDatabaseDisplayModel::rowMatchesCardName(CardInfoPtr info) const { - if (!cardName.isEmpty() && !info->getName().contains(cardName, Qt::CaseInsensitive) && - searchLanguageMode != SearchLanguageMode::English && !searchLanguage.isEmpty() && searchLanguage != "en" && - !info->getLocalizedName(searchLanguage).contains(cardName, Qt::CaseInsensitive)) { - return false; + if (!cardName.isEmpty()) { + const bool matchesEnglish = info->getName().contains(cardName, Qt::CaseInsensitive); + const bool matchesLocalized = + !searchLanguage.isEnglishOnly() && + info->getLocalizedName(searchLanguage.language).contains(cardName, Qt::CaseInsensitive); + if (!matchesEnglish && !matchesLocalized) { + return false; + } } if (!cardNameSet.isEmpty() && !cardNameSet.contains(info->getName())) { @@ -201,7 +205,7 @@ bool CardDatabaseDisplayModel::rowMatchesCardName(CardInfoPtr info) const } if (filterTree != nullptr) { - return filterTree->acceptsCard(info, searchLanguage, searchLanguageMode); + return filterTree->acceptsCard(info, searchLanguage); } return true; @@ -241,18 +245,17 @@ void CardDatabaseDisplayModel::setStringFilter(const QString &_src) { searchText = _src; delete filterString; - filterString = new FilterString(_src, searchLanguage, searchLanguageMode); + filterString = new FilterString(_src, searchLanguage); dirty(); } -void CardDatabaseDisplayModel::setSearchLanguage(const QString &searchLang, SearchLanguageMode mode) +void CardDatabaseDisplayModel::setSearchLanguage(const CardSearchLanguage &searchLang) { - if (searchLanguage == searchLang && searchLanguageMode == mode) { + if (searchLanguage == searchLang) { return; } searchLanguage = searchLang; - searchLanguageMode = mode; if (filterString != nullptr) { setStringFilter(searchText); diff --git a/libcockatrice_models/libcockatrice/models/database/card_database_display_model.h b/libcockatrice_models/libcockatrice/models/database/card_database_display_model.h index ff83bca49..e6aadd8c6 100644 --- a/libcockatrice_models/libcockatrice/models/database/card_database_display_model.h +++ b/libcockatrice_models/libcockatrice/models/database/card_database_display_model.h @@ -33,8 +33,7 @@ private: FilterString *filterString; int loadedRowCount; QTimer dirtyTimer; - QString searchLanguage; - SearchLanguageMode searchLanguageMode = SearchLanguageMode::English; + CardSearchLanguage searchLanguage; QString searchText; /** The translation table that will be used for sanitizeCardName. */ @@ -65,7 +64,7 @@ public: cardNameSet = _cardNameSet; dirty(); } - void setSearchLanguage(const QString &searchLang, SearchLanguageMode mode); + void setSearchLanguage(const CardSearchLanguage &searchLang); void dirty() { diff --git a/tests/carddatabase/filter_string_test.cpp b/tests/carddatabase/filter_string_test.cpp index 1f3a525df..2b92c65df 100644 --- a/tests/carddatabase/filter_string_test.cpp +++ b/tests/carddatabase/filter_string_test.cpp @@ -84,42 +84,42 @@ CardInfoPtr localizedCat() TEST_F(CardQuery, SearchLanguageEnglishMatchesOnlyEnglish) { const CardData localized = localizedCat(); - ASSERT_TRUE(FilterString("Cat", "de", SearchLanguageMode::English).check(localized)); - ASSERT_FALSE(FilterString("Kater", "de", SearchLanguageMode::English).check(localized)); + ASSERT_TRUE(FilterString("Cat", CardSearchLanguage{"de", SearchLanguageMode::English}).check(localized)); + ASSERT_FALSE(FilterString("Kater", CardSearchLanguage{"de", SearchLanguageMode::English}).check(localized)); } TEST_F(CardQuery, SearchLanguageSelectedMatchesLocalizedNameAndText) { const CardData localized = localizedCat(); - ASSERT_TRUE(FilterString("Kater", "de", SearchLanguageMode::Selected).check(localized)); - ASSERT_TRUE(FilterString("o:miaut", "de", SearchLanguageMode::Selected).check(localized)); - ASSERT_FALSE(FilterString("Cat", "de", SearchLanguageMode::Selected).check(localized)); + ASSERT_TRUE(FilterString("Kater", CardSearchLanguage{"de", SearchLanguageMode::Selected}).check(localized)); + ASSERT_TRUE(FilterString("o:miaut", CardSearchLanguage{"de", SearchLanguageMode::Selected}).check(localized)); + ASSERT_FALSE(FilterString("Cat", CardSearchLanguage{"de", SearchLanguageMode::Selected}).check(localized)); } TEST_F(CardQuery, SearchLanguageSelectedFallsBackToEnglishForUntranslatedCards) { const CardData localized = localizedCat(); - ASSERT_TRUE(FilterString("Cat", "fr", SearchLanguageMode::Selected).check(localized)); - ASSERT_FALSE(FilterString("Kater", "fr", SearchLanguageMode::Selected).check(localized)); + ASSERT_TRUE(FilterString("Cat", CardSearchLanguage{"fr", SearchLanguageMode::Selected}).check(localized)); + ASSERT_FALSE(FilterString("Kater", CardSearchLanguage{"fr", SearchLanguageMode::Selected}).check(localized)); } TEST_F(CardQuery, SearchLanguageBothMatchesEitherLanguage) { const CardData localized = localizedCat(); - ASSERT_TRUE(FilterString("Cat", "de", SearchLanguageMode::Both).check(localized)); - ASSERT_TRUE(FilterString("Kater", "de", SearchLanguageMode::Both).check(localized)); + ASSERT_TRUE(FilterString("Cat", CardSearchLanguage{"de", SearchLanguageMode::Both}).check(localized)); + ASSERT_TRUE(FilterString("Kater", CardSearchLanguage{"de", SearchLanguageMode::Both}).check(localized)); } TEST_F(CardQuery, SearchLanguageIsBoundPerInstance) { const CardData localized = localizedCat(); - FilterString germanQuery("Kater", "de", SearchLanguageMode::Selected); + FilterString germanQuery("Kater", CardSearchLanguage{"de", SearchLanguageMode::Selected}); ASSERT_TRUE(germanQuery.check(localized)); // Constructing an English-bound instance afterwards must not change the // language the earlier instance searches in. - FilterString englishQuery("Kater", "", SearchLanguageMode::English); + FilterString englishQuery("Kater", CardSearchLanguage{"", SearchLanguageMode::English}); ASSERT_FALSE(englishQuery.check(localized)); ASSERT_TRUE(germanQuery.check(localized)); }