mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 09:05:10 -07:00
[Card] Add a setting for the language used in card search
Localized card names and texts can now be searched too, controlled by a 'Language used in card search' toggle (English, selected card language, or both) on the general settings page. Untranslated cards always keep matching in English. Removed the redundant local copy of the URL templates list in the localized picture loader while here.
This commit is contained in:
parent
1c93309952
commit
e029173e29
20 changed files with 360 additions and 52 deletions
|
|
@ -16,11 +16,13 @@
|
|||
#include <QLineEdit>
|
||||
#include <QRadioButton>
|
||||
#include <QTreeView>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/models/database/card_database_model.h>
|
||||
#include <libcockatrice/models/database/token/token_display_model.h>
|
||||
#include <libcockatrice/settings/card_override_settings.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/settings/layouts_settings.h>
|
||||
#include <libcockatrice/utility/string_limits.h>
|
||||
|
|
@ -88,6 +90,15 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
|||
cardDatabaseDisplayModel = new TokenDisplayModel(this);
|
||||
cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel);
|
||||
|
||||
CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay();
|
||||
const auto applyCardSearchLanguage = [this, cardsDisplay]() {
|
||||
cardDatabaseDisplayModel->setSearchLanguage(
|
||||
cardsDisplay->getCardLang(), static_cast<CardSearchLanguage>(cardsDisplay->getCardSearchLanguage()));
|
||||
};
|
||||
applyCardSearchLanguage();
|
||||
connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, applyCardSearchLanguage);
|
||||
connect(cardsDisplay, &CardsDisplaySettings::cardSearchLanguageChanged, this, applyCardSearchLanguage);
|
||||
|
||||
chooseTokenFromAllRadioButton = new QRadioButton(tr("Show &all tokens"));
|
||||
connect(chooseTokenFromAllRadioButton, &QRadioButton::toggled, this, &DlgCreateToken::actChooseTokenFromAll);
|
||||
chooseTokenFromDeckRadioButton = new QRadioButton(tr("Show tokens from this &deck"));
|
||||
|
|
|
|||
|
|
@ -94,8 +94,7 @@ void CardPictureToLoad::populateSetUrls()
|
|||
}
|
||||
}
|
||||
|
||||
const QStringList orderedTemplates = urlTemplates;
|
||||
for (const QString &urlTemplate : orderedTemplates) {
|
||||
for (const QString &urlTemplate : urlTemplates) {
|
||||
QString transformedUrl = transformUrl(urlTemplate);
|
||||
|
||||
if (!transformedUrl.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@
|
|||
#include <QHeaderView>
|
||||
#include <QToolButton>
|
||||
#include <QTreeView>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
|
||||
DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent, CardDatabaseModel *databaseModel)
|
||||
: QWidget(parent)
|
||||
|
|
@ -40,6 +42,15 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
|
|||
databaseDisplayModel->setSourceModel(databaseModel);
|
||||
databaseDisplayModel->setFilterKeyColumn(0);
|
||||
|
||||
CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay();
|
||||
const auto applyCardSearchLanguage = [this, cardsDisplay]() {
|
||||
databaseDisplayModel->setSearchLanguage(cardsDisplay->getCardLang(),
|
||||
static_cast<CardSearchLanguage>(cardsDisplay->getCardSearchLanguage()));
|
||||
};
|
||||
applyCardSearchLanguage();
|
||||
connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, applyCardSearchLanguage);
|
||||
connect(cardsDisplay, &CardsDisplaySettings::cardSearchLanguageChanged, this, applyCardSearchLanguage);
|
||||
|
||||
databaseView = new CardDatabaseView(this, databaseDisplayModel);
|
||||
databaseView->setObjectName("databaseView");
|
||||
databaseView->setFocusProxy(searchEdit);
|
||||
|
|
|
|||
|
|
@ -63,13 +63,26 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
connect(&cardLanguageBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&GeneralSettingsPage::cardLanguageBoxChanged);
|
||||
|
||||
// card search language, independent of the card display language
|
||||
cardSearchLanguageBox.addItem(""); // texts set in retranslateUi
|
||||
cardSearchLanguageBox.addItem("");
|
||||
cardSearchLanguageBox.addItem("");
|
||||
const int cardSearchLanguageIndex = SettingsCache::instance().cardsDisplay().getCardSearchLanguage();
|
||||
cardSearchLanguageBox.setCurrentIndex(cardSearchLanguageIndex < 0 ? static_cast<int>(CardSearchLanguage::English)
|
||||
: cardSearchLanguageIndex);
|
||||
|
||||
connect(&cardSearchLanguageBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&GeneralSettingsPage::cardSearchLanguageBoxChanged);
|
||||
|
||||
auto *languageGrid = new QGridLayout;
|
||||
languageGrid->addWidget(&languageLabel, 0, 0);
|
||||
languageGrid->addWidget(&languageBox, 0, 1);
|
||||
languageGrid->addWidget(&cardLanguageLabel, 1, 0);
|
||||
languageGrid->addWidget(&cardLanguageBox, 1, 1);
|
||||
languageGrid->addWidget(&cardLanguageNoteLabel, 2, 1);
|
||||
languageGrid->addWidget(&advertiseTranslationPageLabel, 3, 1, Qt::AlignRight);
|
||||
languageGrid->addWidget(&cardSearchLanguageLabel, 3, 0);
|
||||
languageGrid->addWidget(&cardSearchLanguageBox, 3, 1);
|
||||
languageGrid->addWidget(&advertiseTranslationPageLabel, 4, 1, Qt::AlignRight);
|
||||
|
||||
cardLanguageNoteLabel.setWordWrap(true);
|
||||
cardLanguageNoteLabel.setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
|
|
@ -481,6 +494,11 @@ void GeneralSettingsPage::cardLanguageBoxChanged(int index)
|
|||
}
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::cardSearchLanguageBoxChanged(int index)
|
||||
{
|
||||
SettingsCache::instance().cardsDisplay().setCardSearchLanguage(index);
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::updateStartupServerControlsVisibility()
|
||||
{
|
||||
const int index = startupTabSelector.currentIndex();
|
||||
|
|
@ -502,6 +520,12 @@ void GeneralSettingsPage::retranslateUi()
|
|||
cardLanguageLabel.setText(tr("Card text & images language:"));
|
||||
cardLanguageNoteLabel.setText(
|
||||
tr("Foreign card names, text and art apply after you update the card database (Oracle)."));
|
||||
cardSearchLanguageLabel.setText(tr("Language used in card search:"));
|
||||
cardSearchLanguageBox.setItemText(static_cast<int>(CardSearchLanguage::English), tr("English"));
|
||||
cardSearchLanguageBox.setItemText(static_cast<int>(CardSearchLanguage::Selected),
|
||||
tr("Selected card language (untranslated cards still match in English)"));
|
||||
cardSearchLanguageBox.setItemText(static_cast<int>(CardSearchLanguage::Both),
|
||||
tr("English and selected card language"));
|
||||
advertiseTranslationPageLabel.setText(
|
||||
QString("<a href='%1'>%2</a>").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations")));
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ private slots:
|
|||
void resetAllPathsClicked();
|
||||
void languageBoxChanged(int index);
|
||||
void cardLanguageBoxChanged(int index);
|
||||
void cardSearchLanguageBoxChanged(int index);
|
||||
void updateStartupServerControlsVisibility();
|
||||
|
||||
private:
|
||||
|
|
@ -55,6 +56,9 @@ private:
|
|||
QComboBox cardLanguageBox;
|
||||
QLabel cardLanguageNoteLabel;
|
||||
|
||||
QLabel cardSearchLanguageLabel;
|
||||
QComboBox cardSearchLanguageBox;
|
||||
|
||||
QLabel updateReleaseChannelLabel;
|
||||
QComboBox updateReleaseChannelBox;
|
||||
QCheckBox startupUpdateCheckCheckBox;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "completer_utils.h"
|
||||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "card_completer_styler.h"
|
||||
|
||||
#include <QCompleter>
|
||||
|
|
@ -7,13 +8,26 @@
|
|||
#include <QObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringListModel>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/models/database/card/card_completer_proxy_model.h>
|
||||
#include <libcockatrice/models/database/card/card_search_model.h>
|
||||
#include <libcockatrice/models/database/card_database_display_model.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
void applyCardSearchLanguage(CardSearchModel *searchModel)
|
||||
{
|
||||
const auto &cardsDisplay = SettingsCache::instance().cardsDisplay();
|
||||
searchModel->setSearchLanguage(cardsDisplay.getCardLang(),
|
||||
static_cast<CardSearchLanguage>(cardsDisplay.getCardSearchLanguage()));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CardCompleterSetup createCardCompleter(CardDatabaseDisplayModel *displayModel, QObject *parent, int maxVisibleItems)
|
||||
{
|
||||
auto *searchModel = new CardSearchModel(displayModel, parent);
|
||||
applyCardSearchLanguage(searchModel);
|
||||
|
||||
auto *proxyModel = new CardCompleterProxyModel(parent);
|
||||
proxyModel->setSourceModel(searchModel);
|
||||
|
|
@ -27,6 +41,12 @@ CardCompleterSetup createCardCompleter(CardDatabaseDisplayModel *displayModel, Q
|
|||
completer->setMaxVisibleItems(maxVisibleItems);
|
||||
CardCompleterStyler::apply(completer);
|
||||
|
||||
auto *cardsDisplay = &SettingsCache::instance().cardsDisplay();
|
||||
QObject::connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, searchModel,
|
||||
[searchModel] { applyCardSearchLanguage(searchModel); });
|
||||
QObject::connect(cardsDisplay, &CardsDisplaySettings::cardSearchLanguageChanged, searchModel,
|
||||
[searchModel] { applyCardSearchLanguage(searchModel); });
|
||||
|
||||
return {searchModel, proxyModel, completer};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,15 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
|||
databaseDisplayModel->setSourceModel(database_model);
|
||||
databaseDisplayModel->setFilterKeyColumn(0);
|
||||
|
||||
CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay();
|
||||
const auto applyCardSearchLanguage = [this, cardsDisplay]() {
|
||||
databaseDisplayModel->setSearchLanguage(cardsDisplay->getCardLang(),
|
||||
static_cast<CardSearchLanguage>(cardsDisplay->getCardSearchLanguage()));
|
||||
};
|
||||
applyCardSearchLanguage();
|
||||
connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, applyCardSearchLanguage);
|
||||
connect(cardsDisplay, &CardsDisplaySettings::cardSearchLanguageChanged, this, applyCardSearchLanguage);
|
||||
|
||||
cards = new QList<ExactCard>;
|
||||
connect(databaseDisplayModel, &CardDatabaseDisplayModel::modelDirty, this,
|
||||
&VisualDatabaseDisplayWidget::modelDirty);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@
|
|||
* imports the selected language's card data) and the client settings UI (which
|
||||
* offers the language choice).
|
||||
*/
|
||||
/**
|
||||
* @brief The card languages card search should run against.
|
||||
*/
|
||||
enum class CardSearchLanguage
|
||||
{
|
||||
English, ///< Only search the English card names and texts.
|
||||
Selected, ///< Search the selected card language (untranslated cards still match in English).
|
||||
Both ///< Search both the English and the selected card language names and texts.
|
||||
};
|
||||
|
||||
namespace CardLocalization
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -74,6 +74,38 @@ NumericValue <- [0-9]+
|
|||
|
||||
static std::once_flag init;
|
||||
|
||||
// The peg parser rules are set up once per process, which means the GenericQuery/
|
||||
// OracleQuery lambdas cannot capture per-instance state. The card language the
|
||||
// plain-text name and text queries search in is therefore kept here and applied
|
||||
// by those lambdas; every FilterString shares it because it reflects a single
|
||||
// global user setting.
|
||||
static QString globalSearchLanguage;
|
||||
static CardSearchLanguage globalSearchLanguageMode = CardSearchLanguage::English;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool matchesInSearchLanguage(const QString &english,
|
||||
const QString &localized,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode,
|
||||
const StringMatcher &matcher)
|
||||
{
|
||||
if (searchLanguageMode == CardSearchLanguage::English) {
|
||||
return matcher(english);
|
||||
}
|
||||
|
||||
if (searchLanguageMode == CardSearchLanguage::Both && matcher(english)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (searchLanguage.isEmpty() || searchLanguage == "en") {
|
||||
return matcher(english);
|
||||
}
|
||||
|
||||
return matcher(localized);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
static void setupParserRules()
|
||||
{
|
||||
auto passthru = [](const peg::SemanticValues &sv) -> Filter {
|
||||
|
|
@ -333,7 +365,10 @@ static void setupParserRules()
|
|||
|
||||
search["OracleQuery"] = [](const peg::SemanticValues &sv) -> Filter {
|
||||
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||
return [=](const CardData &x) { return matcher(x->getText()); };
|
||||
return [=](const CardData &x) {
|
||||
return matchesInSearchLanguage(x->getText(), x->getLocalizedText(globalSearchLanguage),
|
||||
globalSearchLanguage, globalSearchLanguageMode, matcher);
|
||||
};
|
||||
};
|
||||
|
||||
search["ColorQuery"] = [](const peg::SemanticValues &sv) -> Filter {
|
||||
|
|
@ -410,7 +445,10 @@ static void setupParserRules()
|
|||
};
|
||||
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> Filter {
|
||||
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||
return [=](const CardData &x) { return matcher(x->getName()); };
|
||||
return [=](const CardData &x) {
|
||||
return matchesInSearchLanguage(x->getName(), x->getLocalizedName(globalSearchLanguage),
|
||||
globalSearchLanguage, globalSearchLanguageMode, matcher);
|
||||
};
|
||||
};
|
||||
|
||||
search["Color"] = [](const peg::SemanticValues &sv) -> char { return "WUBRGU"[sv.choice()]; };
|
||||
|
|
@ -447,3 +485,9 @@ FilterString::FilterString(const QString &expr)
|
|||
result = [](const CardData &) -> bool { return false; };
|
||||
}
|
||||
}
|
||||
|
||||
void FilterString::setSearchLanguage(const QString &searchLanguage, CardSearchLanguage searchLanguageMode)
|
||||
{
|
||||
globalSearchLanguage = searchLanguage;
|
||||
globalSearchLanguageMode = searchLanguageMode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <QString>
|
||||
#include <functional>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <utility>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(FilterStringLog, "filter_string");
|
||||
|
|
@ -55,6 +56,17 @@ public:
|
|||
return _error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the card language plain-text name and text queries run against.
|
||||
*
|
||||
* The peg parser rules are set up once per process, so this propagates to
|
||||
* every FilterString instance created through the shared parser.
|
||||
*
|
||||
* @param searchLanguage Empty string for English only, otherwise the card language code.
|
||||
* @param searchLanguageMode The search language mode from CardSearchLanguage.
|
||||
*/
|
||||
void setSearchLanguage(const QString &searchLanguage, CardSearchLanguage searchLanguageMode);
|
||||
|
||||
private:
|
||||
QString _error;
|
||||
Filter result;
|
||||
|
|
|
|||
|
|
@ -100,14 +100,17 @@ FilterTreeNode *FilterItemList::termNode(const QString &term)
|
|||
return childNodes.at(i);
|
||||
}
|
||||
|
||||
bool FilterItemList::testTypeAnd(const CardInfoPtr info, CardFilter::Attr attr) const
|
||||
bool FilterItemList::testTypeAnd(const CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
for (auto i = childNodes.constBegin(); i != childNodes.constEnd(); i++) {
|
||||
if (!(*i)->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(*i)->acceptCardAttr(info, attr)) {
|
||||
if (!(*i)->acceptCardAttr(info, attr, searchLanguage, searchLanguageMode)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -115,13 +118,19 @@ bool FilterItemList::testTypeAnd(const CardInfoPtr info, CardFilter::Attr attr)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FilterItemList::testTypeAndNot(const CardInfoPtr info, CardFilter::Attr attr) const
|
||||
bool FilterItemList::testTypeAndNot(const CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
// if any one in the list is true, return false
|
||||
return !testTypeOr(info, attr);
|
||||
return !testTypeOr(info, attr, searchLanguage, searchLanguageMode);
|
||||
}
|
||||
|
||||
bool FilterItemList::testTypeOr(const CardInfoPtr info, CardFilter::Attr attr) const
|
||||
bool FilterItemList::testTypeOr(const CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
bool noChildEnabledChild = true;
|
||||
|
||||
|
|
@ -134,7 +143,7 @@ bool FilterItemList::testTypeOr(const CardInfoPtr info, CardFilter::Attr attr) c
|
|||
noChildEnabledChild = false;
|
||||
}
|
||||
|
||||
if ((*i)->acceptCardAttr(info, attr)) {
|
||||
if ((*i)->acceptCardAttr(info, attr, searchLanguage, searchLanguageMode)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -142,20 +151,51 @@ bool FilterItemList::testTypeOr(const CardInfoPtr info, CardFilter::Attr attr) c
|
|||
return noChildEnabledChild;
|
||||
}
|
||||
|
||||
bool FilterItemList::testTypeOrNot(const CardInfoPtr info, CardFilter::Attr attr) const
|
||||
bool FilterItemList::testTypeOrNot(const CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
// if any one in the list is false, return true
|
||||
return !testTypeAnd(info, attr);
|
||||
return !testTypeAnd(info, attr, searchLanguage, searchLanguageMode);
|
||||
}
|
||||
|
||||
bool FilterItem::acceptName(const CardInfoPtr info) const
|
||||
bool FilterItem::acceptName(const CardInfoPtr info,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
return info->getName().contains(term, Qt::CaseInsensitive);
|
||||
if (searchLanguageMode == CardSearchLanguage::English) {
|
||||
return info->getName().contains(term, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
if (searchLanguageMode == CardSearchLanguage::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);
|
||||
}
|
||||
|
||||
bool FilterItem::acceptNameExact(const CardInfoPtr info) const
|
||||
bool FilterItem::acceptNameExact(const CardInfoPtr info,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
return info->getName() == term;
|
||||
if (searchLanguageMode == CardSearchLanguage::English) {
|
||||
return info->getName() == term;
|
||||
}
|
||||
|
||||
if (searchLanguageMode == CardSearchLanguage::Both && info->getName() == term) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (searchLanguage.isEmpty() || searchLanguage == "en") {
|
||||
return info->getName() == term;
|
||||
}
|
||||
|
||||
return info->getLocalizedName(searchLanguage) == term;
|
||||
}
|
||||
|
||||
bool FilterItem::acceptType(const CardInfoPtr info) const
|
||||
|
|
@ -213,9 +253,23 @@ bool FilterItem::acceptColor(const CardInfoPtr info) const
|
|||
return match_count == converted_term.length();
|
||||
}
|
||||
|
||||
bool FilterItem::acceptText(const CardInfoPtr info) const
|
||||
bool FilterItem::acceptText(const CardInfoPtr info,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
return info->getText().contains(term, Qt::CaseInsensitive);
|
||||
if (searchLanguageMode == CardSearchLanguage::English) {
|
||||
return info->getText().contains(term, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
if (searchLanguageMode == CardSearchLanguage::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);
|
||||
}
|
||||
|
||||
bool FilterItem::acceptSet(const CardInfoPtr info) const
|
||||
|
|
@ -402,19 +456,22 @@ bool FilterItem::relationCheck(int cardInfo) const
|
|||
return result;
|
||||
}
|
||||
|
||||
bool FilterItem::acceptCardAttr(const CardInfoPtr info, CardFilter::Attr attr) const
|
||||
bool FilterItem::acceptCardAttr(const CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
switch (attr) {
|
||||
case CardFilter::AttrName:
|
||||
return acceptName(info);
|
||||
return acceptName(info, searchLanguage, searchLanguageMode);
|
||||
case CardFilter::AttrNameExact:
|
||||
return acceptNameExact(info);
|
||||
return acceptNameExact(info, searchLanguage, searchLanguageMode);
|
||||
case CardFilter::AttrType:
|
||||
return acceptType(info);
|
||||
case CardFilter::AttrColor:
|
||||
return acceptColor(info);
|
||||
case CardFilter::AttrText:
|
||||
return acceptText(info);
|
||||
return acceptText(info, searchLanguage, searchLanguageMode);
|
||||
case CardFilter::AttrSet:
|
||||
return acceptSet(info);
|
||||
case CardFilter::AttrManaCost:
|
||||
|
|
@ -484,18 +541,21 @@ FilterTreeNode *FilterTree::termNode(const CardFilter *f)
|
|||
return termNode(f->attr(), f->type(), f->term());
|
||||
}
|
||||
|
||||
bool FilterTree::testAttr(const CardInfoPtr info, const LogicMap *lm) const
|
||||
bool FilterTree::testAttr(const CardInfoPtr info,
|
||||
const LogicMap *lm,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
const FilterItemList *fil;
|
||||
bool status = true;
|
||||
|
||||
fil = lm->findTypeList(CardFilter::TypeAnd);
|
||||
if (fil && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr)) {
|
||||
if (fil && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr, searchLanguage, searchLanguageMode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fil = lm->findTypeList(CardFilter::TypeAndNot);
|
||||
if (fil && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr)) {
|
||||
if (fil && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr, searchLanguage, searchLanguageMode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -504,23 +564,25 @@ bool FilterTree::testAttr(const CardInfoPtr info, const LogicMap *lm) const
|
|||
status = false;
|
||||
|
||||
// if this is true we can return because it is OR'd with the OrNot list
|
||||
if (fil->testTypeOr(info, lm->attr)) {
|
||||
if (fil->testTypeOr(info, lm->attr, searchLanguage, searchLanguageMode)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fil = lm->findTypeList(CardFilter::TypeOrNot);
|
||||
if (fil && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr)) {
|
||||
if (fil && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr, searchLanguage, searchLanguageMode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool FilterTree::acceptsCard(const CardInfoPtr info) const
|
||||
bool FilterTree::acceptsCard(const CardInfoPtr info,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const
|
||||
{
|
||||
for (auto i = childNodes.constBegin(); i != childNodes.constEnd(); i++) {
|
||||
if ((*i)->isEnabled() && !testAttr(info, *i)) {
|
||||
if ((*i)->isEnabled() && !testAttr(info, *i, searchLanguage, searchLanguageMode)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -167,10 +168,22 @@ public:
|
|||
return CardFilter::typeName(type);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool testTypeAnd(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
[[nodiscard]] bool testTypeAndNot(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
[[nodiscard]] bool testTypeOr(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
[[nodiscard]] bool testTypeOrNot(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
[[nodiscard]] bool testTypeAnd(CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const;
|
||||
[[nodiscard]] bool testTypeAndNot(CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const;
|
||||
[[nodiscard]] bool testTypeOr(CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const;
|
||||
[[nodiscard]] bool testTypeOrNot(CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const;
|
||||
};
|
||||
|
||||
class FilterItem : public FilterTreeNode
|
||||
|
|
@ -207,20 +220,26 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool acceptName(CardInfoPtr info) const;
|
||||
[[nodiscard]] bool acceptNameExact(CardInfoPtr info) const;
|
||||
[[nodiscard]] bool
|
||||
acceptName(CardInfoPtr info, const QString &searchLanguage, CardSearchLanguage searchLanguageMode) const;
|
||||
[[nodiscard]] bool
|
||||
acceptNameExact(CardInfoPtr info, const QString &searchLanguage, CardSearchLanguage searchLanguageMode) 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;
|
||||
[[nodiscard]] bool
|
||||
acceptText(CardInfoPtr info, const QString &searchLanguage, CardSearchLanguage searchLanguageMode) 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;
|
||||
[[nodiscard]] bool acceptCardAttr(CardInfoPtr info,
|
||||
CardFilter::Attr attr,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const;
|
||||
[[nodiscard]] bool acceptFormat(CardInfoPtr info) const;
|
||||
[[nodiscard]] bool relationCheck(int cardInfo) const;
|
||||
};
|
||||
|
|
@ -240,7 +259,10 @@ private:
|
|||
LogicMap *attrLogicMap(CardFilter::Attr attr);
|
||||
FilterItemList *attrTypeList(CardFilter::Attr attr, CardFilter::Type type);
|
||||
|
||||
bool testAttr(CardInfoPtr info, const LogicMap *lm) const;
|
||||
bool testAttr(CardInfoPtr info,
|
||||
const LogicMap *lm,
|
||||
const QString &searchLanguage,
|
||||
CardSearchLanguage searchLanguageMode) const;
|
||||
|
||||
void nodeChanged() const override
|
||||
{
|
||||
|
|
@ -279,7 +301,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool acceptsCard(CardInfoPtr info) const;
|
||||
[[nodiscard]] bool
|
||||
acceptsCard(CardInfoPtr info, const QString &searchLanguage, CardSearchLanguage searchLanguageMode) const;
|
||||
void removeFiltersByAttr(CardFilter::Attr filterType);
|
||||
void removeFilter(const CardFilter *toRemove);
|
||||
void clear();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public:
|
|||
[[nodiscard]] virtual int getArchidektPreviewSize() const = 0;
|
||||
[[nodiscard]] virtual int getSampleHandSize() const = 0;
|
||||
[[nodiscard]] virtual QString getCardLang() const = 0;
|
||||
[[nodiscard]] virtual int getCardSearchLanguage() const = 0;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTERFACE_CARDS_DISPLAY_SETTINGS_PROVIDER_H
|
||||
|
|
|
|||
|
|
@ -65,7 +65,13 @@ void CardSearchModel::updateSearchResults(const QString &query)
|
|||
continue;
|
||||
}
|
||||
|
||||
const QString lowerName = card->getName().toLower();
|
||||
// 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 != CardSearchLanguage::English && !searchLanguage.isEmpty() && searchLanguage != "en") {
|
||||
matchName = card->getLocalizedName(searchLanguage);
|
||||
}
|
||||
const QString lowerName = matchName.toLower();
|
||||
if (!lowerName.contains(lowerQuery)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -79,11 +85,17 @@ void CardSearchModel::updateSearchResults(const QString &query)
|
|||
}
|
||||
}
|
||||
|
||||
auto sortByDistanceThenLength = [](const SearchResult &a, const SearchResult &b) {
|
||||
auto sortByDistanceThenLength = [this](const SearchResult &a, const SearchResult &b) {
|
||||
QString nameA = a.card->getName();
|
||||
QString nameB = b.card->getName();
|
||||
if (searchLanguageMode != CardSearchLanguage::English && !searchLanguage.isEmpty() && searchLanguage != "en") {
|
||||
nameA = a.card->getLocalizedName(searchLanguage);
|
||||
nameB = b.card->getLocalizedName(searchLanguage);
|
||||
}
|
||||
if (a.distance != b.distance) {
|
||||
return a.distance < b.distance;
|
||||
}
|
||||
return a.card->getName().size() < b.card->getName().size();
|
||||
return nameA.size() < nameB.size();
|
||||
};
|
||||
|
||||
std::sort(prefixMatches.begin(), prefixMatches.end(), sortByDistanceThenLength);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ public:
|
|||
|
||||
void updateSearchResults(const QString &query); // Update results based on input
|
||||
|
||||
void setSearchLanguage(const QString &searchLang, CardSearchLanguage mode)
|
||||
{
|
||||
if (searchLanguage == searchLang && searchLanguageMode == mode) {
|
||||
return;
|
||||
}
|
||||
searchLanguage = searchLang;
|
||||
searchLanguageMode = mode;
|
||||
}
|
||||
|
||||
private:
|
||||
struct SearchResult
|
||||
{
|
||||
|
|
@ -36,6 +45,8 @@ private:
|
|||
|
||||
CardDatabaseDisplayModel *sourceModel;
|
||||
QList<SearchResult> searchResults;
|
||||
QString searchLanguage;
|
||||
CardSearchLanguage searchLanguageMode = CardSearchLanguage::English;
|
||||
};
|
||||
|
||||
#endif // CARD_SEARCH_MODEL_H
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex
|
|||
}
|
||||
|
||||
if (filterString != nullptr) {
|
||||
if (filterTree != nullptr && !filterTree->acceptsCard(info)) {
|
||||
if (filterTree != nullptr && !filterTree->acceptsCard(info, searchLanguage, searchLanguageMode)) {
|
||||
return false;
|
||||
}
|
||||
return filterString->check(info);
|
||||
|
|
@ -190,7 +190,9 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex
|
|||
|
||||
bool CardDatabaseDisplayModel::rowMatchesCardName(CardInfoPtr info) const
|
||||
{
|
||||
if (!cardName.isEmpty() && !info->getName().contains(cardName, Qt::CaseInsensitive)) {
|
||||
if (!cardName.isEmpty() && !info->getName().contains(cardName, Qt::CaseInsensitive) &&
|
||||
searchLanguageMode != CardSearchLanguage::English && !searchLanguage.isEmpty() && searchLanguage != "en" &&
|
||||
!info->getLocalizedName(searchLanguage).contains(cardName, Qt::CaseInsensitive)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +201,7 @@ bool CardDatabaseDisplayModel::rowMatchesCardName(CardInfoPtr info) const
|
|||
}
|
||||
|
||||
if (filterTree != nullptr) {
|
||||
return filterTree->acceptsCard(info);
|
||||
return filterTree->acceptsCard(info, searchLanguage, searchLanguageMode);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -235,6 +237,29 @@ void CardDatabaseDisplayModel::setFilterTree(FilterTree *_filterTree)
|
|||
invalidate();
|
||||
}
|
||||
|
||||
void CardDatabaseDisplayModel::setStringFilter(const QString &_src)
|
||||
{
|
||||
delete filterString;
|
||||
filterString = new FilterString(_src);
|
||||
filterString->setSearchLanguage(searchLanguage, searchLanguageMode);
|
||||
dirty();
|
||||
}
|
||||
|
||||
void CardDatabaseDisplayModel::setSearchLanguage(const QString &searchLang, CardSearchLanguage mode)
|
||||
{
|
||||
if (searchLanguage == searchLang && searchLanguageMode == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
searchLanguage = searchLang;
|
||||
searchLanguageMode = mode;
|
||||
|
||||
if (filterString != nullptr) {
|
||||
filterString->setSearchLanguage(searchLanguage, searchLanguageMode);
|
||||
}
|
||||
dirty();
|
||||
}
|
||||
|
||||
void CardDatabaseDisplayModel::filterTreeChanged()
|
||||
{
|
||||
invalidate();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTimer>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/filters/filter_string.h>
|
||||
|
||||
class FilterTree;
|
||||
|
|
@ -32,6 +33,8 @@ private:
|
|||
FilterString *filterString;
|
||||
int loadedRowCount;
|
||||
QTimer dirtyTimer;
|
||||
QString searchLanguage;
|
||||
CardSearchLanguage searchLanguageMode = CardSearchLanguage::English;
|
||||
|
||||
/** The translation table that will be used for sanitizeCardName. */
|
||||
static QMap<wchar_t, wchar_t> characterTranslation;
|
||||
|
|
@ -55,17 +58,13 @@ public:
|
|||
cardName = sanitizeCardName(_cardName, characterTranslation);
|
||||
dirty();
|
||||
}
|
||||
void setStringFilter(const QString &_src)
|
||||
{
|
||||
delete filterString;
|
||||
filterString = new FilterString(_src);
|
||||
dirty();
|
||||
}
|
||||
void setStringFilter(const QString &_src);
|
||||
void setCardNameSet(const QSet<QString> &_cardNameSet)
|
||||
{
|
||||
cardNameSet = _cardNameSet;
|
||||
dirty();
|
||||
}
|
||||
void setSearchLanguage(const QString &searchLang, CardSearchLanguage mode);
|
||||
|
||||
void dirty()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -110,6 +110,11 @@ QString CardsDisplaySettings::getCardLang() const
|
|||
return getValue("cardLang", QString(), QString(), "en").toString();
|
||||
}
|
||||
|
||||
int CardsDisplaySettings::getCardSearchLanguage() const
|
||||
{
|
||||
return getValue("cardSearchLanguage", QString(), QString(), static_cast<int>(CardSearchLanguage::English)).toInt();
|
||||
}
|
||||
|
||||
void CardsDisplaySettings::setDisplayCardNames(bool _displayCardNames)
|
||||
{
|
||||
setValue(_displayCardNames, "displayCardNames");
|
||||
|
|
@ -242,3 +247,12 @@ void CardsDisplaySettings::setCardLang(const QString &_cardLang)
|
|||
sync();
|
||||
emit cardLangChanged(_cardLang);
|
||||
}
|
||||
|
||||
void CardsDisplaySettings::setCardSearchLanguage(int _cardSearchLanguage)
|
||||
{
|
||||
if (_cardSearchLanguage == getCardSearchLanguage()) {
|
||||
return;
|
||||
}
|
||||
setValue(_cardSearchLanguage, "cardSearchLanguage");
|
||||
emit cardSearchLanguageChanged(_cardSearchLanguage);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "settings_manager.h"
|
||||
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/interfaces/interface_cards_display_settings_provider.h>
|
||||
|
||||
class CardsDisplaySettings : public SettingsManager, public ICardsDisplaySettingsProvider
|
||||
|
|
@ -32,6 +33,7 @@ public:
|
|||
[[nodiscard]] int getArchidektPreviewSize() const override;
|
||||
[[nodiscard]] int getSampleHandSize() const override;
|
||||
[[nodiscard]] QString getCardLang() const override;
|
||||
[[nodiscard]] int getCardSearchLanguage() const override;
|
||||
|
||||
void setDisplayCardNames(bool _displayCardNames);
|
||||
void setRoundCardCorners(bool _roundCardCorners);
|
||||
|
|
@ -54,6 +56,7 @@ public:
|
|||
void setArchidektPreviewCardSize(int _archidektPreviewCardSize);
|
||||
void setSampleHandSize(int _sampleHandSize);
|
||||
void setCardLang(const QString &_cardLang);
|
||||
void setCardSearchLanguage(int _cardSearchLanguage);
|
||||
|
||||
signals:
|
||||
void displayCardNamesChanged();
|
||||
|
|
@ -71,6 +74,7 @@ signals:
|
|||
void archidektPreviewSizeChanged();
|
||||
void sampleHandSizeChanged(int amount);
|
||||
void cardLangChanged(const QString &lang);
|
||||
void cardSearchLanguageChanged(int cardSearchLanguage);
|
||||
|
||||
public:
|
||||
explicit CardsDisplaySettings(const QString &settingPath, QObject *parent = nullptr);
|
||||
|
|
|
|||
|
|
@ -562,6 +562,19 @@ TEST_F(SettingsDefaultsTest, CardsDisplay_CardLang_SetAndGet)
|
|||
ASSERT_EQ(s.getCardLang(), QString("de"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, CardsDisplay_CardSearchLanguage_Default)
|
||||
{
|
||||
CardsDisplaySettings s(settingsPath, nullptr);
|
||||
ASSERT_EQ(s.getCardSearchLanguage(), static_cast<int>(CardSearchLanguage::English));
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, CardsDisplay_CardSearchLanguage_SetAndGet)
|
||||
{
|
||||
CardsDisplaySettings s(settingsPath, nullptr);
|
||||
s.setCardSearchLanguage(static_cast<int>(CardSearchLanguage::Selected));
|
||||
ASSERT_EQ(s.getCardSearchLanguage(), static_cast<int>(CardSearchLanguage::Selected));
|
||||
}
|
||||
|
||||
// --- VisualDeckStorageSettings ---
|
||||
|
||||
TEST_F(SettingsDefaultsTest, VisualDeckStorage_SortingOrder_Default)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue