Compare commits

..

No commits in common. "7a2492ac67b09e7b2e21b9e9d9e49861a9405afe" and "12299abcc87d829ce53635089d9ff0956aaa09f1" have entirely different histories.

28 changed files with 74 additions and 505 deletions

View file

@ -43,12 +43,6 @@ NumericValue <- [0-9]+
static std::once_flag init;
// The peglib parser is a single permanent object, so the rule actions below cannot see
// 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.
thread_local CardSearchLanguage deckSearchLanguageContext;
static void setupParserRules()
{
// plumbing
@ -122,7 +116,7 @@ static void setupParserRules()
// actual functionality
search["DeckContentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto cardFilter = FilterString(std::any_cast<QString>(sv[0]), deckSearchLanguageContext);
auto cardFilter = FilterString(std::any_cast<QString>(sv[0]));
auto numberMatcher = sv.size() > 1 ? std::any_cast<NumberMatcher>(sv[1]) : [](int count) { return count > 0; };
return [=](const DeckSearchData &data) -> bool {
@ -192,7 +186,7 @@ DeckFilterString::DeckFilterString()
_error = "Not initialized";
}
DeckFilterString::DeckFilterString(const QString &expr, const CardSearchLanguage &searchLanguage)
DeckFilterString::DeckFilterString(const QString &expr)
{
QByteArray ba = expr.simplified().toUtf8();
@ -205,8 +199,6 @@ DeckFilterString::DeckFilterString(const QString &expr, const CardSearchLanguage
return;
}
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));
});

View file

@ -12,7 +12,6 @@
#include <QLoggingCategory>
#include <QString>
#include <functional>
#include <libcockatrice/card/card_localization.h>
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
@ -36,7 +35,7 @@ class DeckFilterString
{
public:
DeckFilterString();
explicit DeckFilterString(const QString &expr, const CardSearchLanguage &searchLanguage = {});
explicit DeckFilterString(const QString &expr);
bool check(const DeckSearchData &data) const
{
return filter(data);

View file

@ -16,13 +16,11 @@
#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>
@ -90,17 +88,6 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
cardDatabaseDisplayModel = new TokenDisplayModel(this);
cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel);
const auto applyCardSearchLanguage = [this]() {
const CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay();
cardDatabaseDisplayModel->setSearchLanguage(CardSearchLanguage{
cardsDisplay.getCardLang(), static_cast<SearchLanguageMode>(cardsDisplay.getCardSearchLanguage())});
};
applyCardSearchLanguage();
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
applyCardSearchLanguage);
connect(&SettingsCache::instance().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"));

View file

@ -1,6 +1,5 @@
#include "view_zone.h"
#include "../../client/settings/cache_settings.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../../game/zones/view_zone_logic.h"
@ -12,13 +11,11 @@
#include <QGraphicsSceneWheelEvent>
#include <QPainter>
#include <QtMath>
#include <libcockatrice/card/card_localization.h>
#include <libcockatrice/protocol/pb/command_dump_zone.pb.h>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
#include <libcockatrice/protocol/pb/response_dump_zone.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/settings/cards_display_settings.h>
/**
* @param parent the parent QGraphicsWidget containing the reveal zone
@ -256,10 +253,7 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca
void ZoneViewZone::setFilterString(const QString &_filterString)
{
const CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay();
filterString = FilterString(
_filterString, CardSearchLanguage{cardsDisplay.getCardLang(),
static_cast<SearchLanguageMode>(cardsDisplay.getCardSearchLanguage())});
filterString = FilterString(_filterString);
reorganizeCards();
}

View file

@ -21,7 +21,6 @@
#include <QStyle>
#include <QStyleOption>
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
#include <libcockatrice/settings/cards_display_settings.h>
#include <libcockatrice/settings/interface_settings.h>
namespace
@ -169,12 +168,6 @@ ZoneViewWidget::ZoneViewWidget(PlayerLogic *_player,
}
connect(&searchEdit, &QLineEdit::textChanged, zone, &ZoneViewZone::setFilterString);
const auto applyCardSearchLanguage = [this] { zone->setFilterString(searchEdit.text()); };
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
applyCardSearchLanguage);
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardSearchLanguageChanged, this,
applyCardSearchLanguage);
}
setLayout(vbox);

View file

@ -94,7 +94,8 @@ void CardPictureToLoad::populateSetUrls()
}
}
for (const QString &urlTemplate : urlTemplates) {
const QStringList orderedTemplates = urlTemplates;
for (const QString &urlTemplate : orderedTemplates) {
QString transformedUrl = transformUrl(urlTemplate);
if (!transformedUrl.isEmpty()) {

View file

@ -11,10 +11,8 @@
#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)
@ -42,17 +40,6 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
databaseDisplayModel->setSourceModel(databaseModel);
databaseDisplayModel->setFilterKeyColumn(0);
const auto applyCardSearchLanguage = [this]() {
const CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay();
databaseDisplayModel->setSearchLanguage(CardSearchLanguage{
cardsDisplay.getCardLang(), static_cast<SearchLanguageMode>(cardsDisplay.getCardSearchLanguage())});
};
applyCardSearchLanguage();
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
applyCardSearchLanguage);
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardSearchLanguageChanged, this,
applyCardSearchLanguage);
databaseView = new CardDatabaseView(this, databaseDisplayModel);
databaseView->setObjectName("databaseView");
databaseView->setFocusProxy(searchEdit);

View file

@ -340,27 +340,16 @@ void ChatView::appendMessage(QString message,
pos.relativePosition = match.captured(0).length(); // set message start
auto before = match.captured(1);
auto sentBy = match.captured(2);
// The user level is not carried in the room chat history, so history
// entries used to render as fixed-level user tags. Resolve online users
// against the user list to turn their history entries into full user
// tags (correct level, name casing and moderation context menu).
QString displayName = sentBy;
// Offline users have no known level; render them as zero-level tags.
QString levelMarker = "0";
if (const ServerInfo_User *onlineUser = userListProxy->getOnlineUser(sentBy)) {
displayName = QString::fromStdString(onlineUser->name());
levelMarker = QString::number(onlineUser->user_level());
}
cursor.insertText(before); // add message timestamp
QTextCharFormat senderFormat(defaultFormat);
senderFormat.setAnchor(true);
senderFormat.setAnchorHref("user://" + levelMarker + "_" + displayName);
// this underscore is important, it is used to add the user level, but in this case the level is
// unknown, if the name contains an underscore it would split up the name
senderFormat.setAnchorHref("user://_" + sentBy);
cursor.setCharFormat(senderFormat);
cursor.insertText(displayName); // add username with href so it shows the menu
userMessagePositions[displayName].append(pos); // save message position
message.remove(0, pos.relativePosition - 2); // do not remove semicolon
cursor.insertText(sentBy); // add username with href so it shows the menu
userMessagePositions[sentBy].append(pos); // save message position
message.remove(0, pos.relativePosition - 2); // do not remove semicolon
}
} else {
//! \todo Remove hardcoded color.

View file

@ -63,26 +63,13 @@ 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>(SearchLanguageMode::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(&cardSearchLanguageLabel, 3, 0);
languageGrid->addWidget(&cardSearchLanguageBox, 3, 1);
languageGrid->addWidget(&advertiseTranslationPageLabel, 4, 1, Qt::AlignRight);
languageGrid->addWidget(&advertiseTranslationPageLabel, 3, 1, Qt::AlignRight);
cardLanguageNoteLabel.setWordWrap(true);
cardLanguageNoteLabel.setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
@ -494,11 +481,6 @@ void GeneralSettingsPage::cardLanguageBoxChanged(int index)
}
}
void GeneralSettingsPage::cardSearchLanguageBoxChanged(int index)
{
SettingsCache::instance().cardsDisplay().setCardSearchLanguage(index);
}
void GeneralSettingsPage::updateStartupServerControlsVisibility()
{
const int index = startupTabSelector.currentIndex();
@ -520,12 +502,6 @@ 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>(SearchLanguageMode::English), tr("English"));
cardSearchLanguageBox.setItemText(static_cast<int>(SearchLanguageMode::Selected),
tr("Selected card language (untranslated cards still match in English)"));
cardSearchLanguageBox.setItemText(static_cast<int>(SearchLanguageMode::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")));

View file

@ -38,7 +38,6 @@ private slots:
void resetAllPathsClicked();
void languageBoxChanged(int index);
void cardLanguageBoxChanged(int index);
void cardSearchLanguageBoxChanged(int index);
void updateStartupServerControlsVisibility();
private:
@ -56,9 +55,6 @@ private:
QComboBox cardLanguageBox;
QLabel cardLanguageNoteLabel;
QLabel cardSearchLanguageLabel;
QComboBox cardSearchLanguageBox;
QLabel updateReleaseChannelLabel;
QComboBox updateReleaseChannelBox;
QCheckBox startupUpdateCheckCheckBox;

View file

@ -1,6 +1,5 @@
#include "completer_utils.h"
#include "../../../client/settings/cache_settings.h"
#include "card_completer_styler.h"
#include <QCompleter>
@ -8,26 +7,13 @@
#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 CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay();
searchModel->setSearchLanguage(CardSearchLanguage{
cardsDisplay.getCardLang(), static_cast<SearchLanguageMode>(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);
@ -41,12 +27,6 @@ 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};
}

View file

@ -41,17 +41,6 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
databaseDisplayModel->setSourceModel(database_model);
databaseDisplayModel->setFilterKeyColumn(0);
const auto applyCardSearchLanguage = [this]() {
const CardsDisplaySettings &cardsDisplay = SettingsCache::instance().cardsDisplay();
databaseDisplayModel->setSearchLanguage(CardSearchLanguage{
cardsDisplay.getCardLang(), static_cast<SearchLanguageMode>(cardsDisplay.getCardSearchLanguage())});
};
applyCardSearchLanguage();
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
applyCardSearchLanguage);
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardSearchLanguageChanged, this,
applyCardSearchLanguage);
cards = new QList<ExactCard>;
connect(databaseDisplayModel, &CardDatabaseDisplayModel::modelDirty, this,
&VisualDatabaseDisplayWidget::modelDirty);

View file

@ -1,12 +1,9 @@
#include "visual_deck_storage_sort_filter_proxy_model.h"
#include "../../../client/settings/cache_settings.h"
#include "../../filters/deck_filter_string.h"
#include <QFileInfo>
#include <algorithm>
#include <libcockatrice/card/card_localization.h>
#include <libcockatrice/settings/cards_display_settings.h>
VisualDeckStorageSortFilterProxyModel::VisualDeckStorageSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
@ -218,10 +215,7 @@ void VisualDeckStorageSortFilterProxyModel::updateSearchMatches()
return;
}
const auto &cardsDisplay = SettingsCache::instance().cardsDisplay();
DeckFilterString filterString(
searchText, CardSearchLanguage{cardsDisplay.getCardLang(),
static_cast<SearchLanguageMode>(cardsDisplay.getCardSearchLanguage())});
DeckFilterString filterString(searchText);
for (int row = 0; row < count; ++row) {
const DeckPreviewData &data = source->dataForRow(row);

View file

@ -15,7 +15,6 @@
#include <QTimer>
#include <QVBoxLayout>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/settings/cards_display_settings.h>
#include <libcockatrice/settings/paths_settings.h>
#include <libcockatrice/settings/visual_deck_storage_settings.h>
@ -119,13 +118,6 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
connect(searchWidget, &VisualDeckStorageSearchWidget::searchTextChanged, this,
&VisualDeckStorageWidget::updateSearchFilter);
// The deck content search matches card names in the configured card language;
// re-run it whenever that setting changes so active searches follow immediately.
CardsDisplaySettings *cardsDisplay = &SettingsCache::instance().cardsDisplay();
const auto reapplySearchForLanguage = [this] { storageProxyModel->reapplyFilters(); };
connect(cardsDisplay, &CardsDisplaySettings::cardLangChanged, this, reapplySearchForLanguage);
connect(cardsDisplay, &CardsDisplaySettings::cardSearchLanguageChanged, this, reapplySearchForLanguage);
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
&VisualDeckStorageWidget::createRootFolderWidget);

View file

@ -4,42 +4,6 @@
#include <QString>
#include <QStringList>
/**
* @brief The card languages card search should run against.
*/
enum class SearchLanguageMode
{
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.
};
/**
* @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

View file

@ -74,36 +74,6 @@ NumericValue <- [0-9]+
static std::once_flag init;
// The peglib parser rules (and therefore their rule actions) are set up once per
// process, so a rule action cannot capture per-instance state. The card language
// plain-text name and text queries search in is therefore handed to the GenericQuery
// 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.
thread_local CardSearchLanguage searchLanguageContext;
namespace
{
bool matchesInSearchLanguage(const QString &english,
const QString &localized,
const CardSearchLanguage &searchLanguage,
const StringMatcher &matcher)
{
if (searchLanguage.mode == SearchLanguageMode::English) {
return matcher(english);
}
if (searchLanguage.mode == SearchLanguageMode::Both) {
if (!searchLanguage.isEnglishOnly() && matcher(localized)) {
return true;
}
return matcher(english);
}
return searchLanguage.isEnglishOnly() ? matcher(english) : matcher(localized);
}
} // namespace
static void setupParserRules()
{
auto passthru = [](const peg::SemanticValues &sv) -> Filter {
@ -363,11 +333,7 @@ static void setupParserRules()
search["OracleQuery"] = [](const peg::SemanticValues &sv) -> Filter {
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
const CardSearchLanguage searchLanguage = searchLanguageContext;
return [=](const CardData &x) {
return matchesInSearchLanguage(x->getText(), x->getLocalizedText(searchLanguage.language), searchLanguage,
matcher);
};
return [=](const CardData &x) { return matcher(x->getText()); };
};
search["ColorQuery"] = [](const peg::SemanticValues &sv) -> Filter {
@ -444,11 +410,7 @@ static void setupParserRules()
};
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> Filter {
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
const CardSearchLanguage searchLanguage = searchLanguageContext;
return [=](const CardData &x) {
return matchesInSearchLanguage(x->getName(), x->getLocalizedName(searchLanguage.language), searchLanguage,
matcher);
};
return [=](const CardData &x) { return matcher(x->getName()); };
};
search["Color"] = [](const peg::SemanticValues &sv) -> char { return "WUBRGU"[sv.choice()]; };
@ -463,7 +425,7 @@ FilterString::FilterString()
_error = "Not initialized";
}
FilterString::FilterString(const QString &expr, const CardSearchLanguage &searchLanguage)
FilterString::FilterString(const QString &expr)
{
QByteArray ba = expr.simplified().toUtf8();
@ -476,8 +438,6 @@ FilterString::FilterString(const QString &expr, const CardSearchLanguage &search
return;
}
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));
});

View file

@ -14,7 +14,6 @@
#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");
@ -36,7 +35,7 @@ class FilterString
{
public:
FilterString();
explicit FilterString(const QString &exp, const CardSearchLanguage &searchLanguage = {});
explicit FilterString(const QString &exp);
[[nodiscard]] bool check(const CardData &card) const
{
if (card.isNull()) {

View file

@ -100,16 +100,14 @@ FilterTreeNode *FilterItemList::termNode(const QString &term)
return childNodes.at(i);
}
bool FilterItemList::testTypeAnd(const CardInfoPtr info,
CardFilter::Attr attr,
const CardSearchLanguage &searchLanguage) const
bool FilterItemList::testTypeAnd(const CardInfoPtr info, CardFilter::Attr attr) const
{
for (auto i = childNodes.constBegin(); i != childNodes.constEnd(); i++) {
if (!(*i)->isEnabled()) {
continue;
}
if (!(*i)->acceptCardAttr(info, attr, searchLanguage)) {
if (!(*i)->acceptCardAttr(info, attr)) {
return false;
}
}
@ -117,17 +115,13 @@ bool FilterItemList::testTypeAnd(const CardInfoPtr info,
return true;
}
bool FilterItemList::testTypeAndNot(const CardInfoPtr info,
CardFilter::Attr attr,
const CardSearchLanguage &searchLanguage) const
bool FilterItemList::testTypeAndNot(const CardInfoPtr info, CardFilter::Attr attr) const
{
// if any one in the list is true, return false
return !testTypeOr(info, attr, searchLanguage);
return !testTypeOr(info, attr);
}
bool FilterItemList::testTypeOr(const CardInfoPtr info,
CardFilter::Attr attr,
const CardSearchLanguage &searchLanguage) const
bool FilterItemList::testTypeOr(const CardInfoPtr info, CardFilter::Attr attr) const
{
bool noChildEnabledChild = true;
@ -140,7 +134,7 @@ bool FilterItemList::testTypeOr(const CardInfoPtr info,
noChildEnabledChild = false;
}
if ((*i)->acceptCardAttr(info, attr, searchLanguage)) {
if ((*i)->acceptCardAttr(info, attr)) {
return true;
}
}
@ -148,58 +142,20 @@ bool FilterItemList::testTypeOr(const CardInfoPtr info,
return noChildEnabledChild;
}
bool FilterItemList::testTypeOrNot(const CardInfoPtr info,
CardFilter::Attr attr,
const CardSearchLanguage &searchLanguage) const
bool FilterItemList::testTypeOrNot(const CardInfoPtr info, CardFilter::Attr attr) const
{
// if any one in the list is false, return true
return !testTypeAnd(info, attr, searchLanguage);
return !testTypeAnd(info, attr);
}
bool FilterItem::acceptName(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const
bool FilterItem::acceptName(const CardInfoPtr info) const
{
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);
}
return false;
return info->getName().contains(term, Qt::CaseInsensitive);
}
bool FilterItem::acceptNameExact(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const
bool FilterItem::acceptNameExact(const CardInfoPtr info) const
{
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;
}
return false;
return info->getName() == term;
}
bool FilterItem::acceptType(const CardInfoPtr info) const
@ -257,27 +213,9 @@ bool FilterItem::acceptColor(const CardInfoPtr info) const
return match_count == converted_term.length();
}
bool FilterItem::acceptText(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const
bool FilterItem::acceptText(const CardInfoPtr info) const
{
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);
}
return false;
return info->getText().contains(term, Qt::CaseInsensitive);
}
bool FilterItem::acceptSet(const CardInfoPtr info) const
@ -464,21 +402,19 @@ bool FilterItem::relationCheck(int cardInfo) const
return result;
}
bool FilterItem::acceptCardAttr(const CardInfoPtr info,
CardFilter::Attr attr,
const CardSearchLanguage &searchLanguage) const
bool FilterItem::acceptCardAttr(const CardInfoPtr info, CardFilter::Attr attr) const
{
switch (attr) {
case CardFilter::AttrName:
return acceptName(info, searchLanguage);
return acceptName(info);
case CardFilter::AttrNameExact:
return acceptNameExact(info, searchLanguage);
return acceptNameExact(info);
case CardFilter::AttrType:
return acceptType(info);
case CardFilter::AttrColor:
return acceptColor(info);
case CardFilter::AttrText:
return acceptText(info, searchLanguage);
return acceptText(info);
case CardFilter::AttrSet:
return acceptSet(info);
case CardFilter::AttrManaCost:
@ -548,18 +484,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 CardSearchLanguage &searchLanguage) const
bool FilterTree::testAttr(const CardInfoPtr info, const LogicMap *lm) const
{
const FilterItemList *fil;
bool status = true;
fil = lm->findTypeList(CardFilter::TypeAnd);
if (fil && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr, searchLanguage)) {
if (fil && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr)) {
return false;
}
fil = lm->findTypeList(CardFilter::TypeAndNot);
if (fil && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr, searchLanguage)) {
if (fil && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr)) {
return false;
}
@ -568,23 +504,23 @@ bool FilterTree::testAttr(const CardInfoPtr info, const LogicMap *lm, const Card
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)) {
if (fil->testTypeOr(info, lm->attr)) {
return true;
}
}
fil = lm->findTypeList(CardFilter::TypeOrNot);
if (fil && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr, searchLanguage)) {
if (fil && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr)) {
return true;
}
return status;
}
bool FilterTree::acceptsCard(const CardInfoPtr info, const CardSearchLanguage &searchLanguage) const
bool FilterTree::acceptsCard(const CardInfoPtr info) const
{
for (auto i = childNodes.constBegin(); i != childNodes.constEnd(); i++) {
if ((*i)->isEnabled() && !testAttr(info, *i, searchLanguage)) {
if ((*i)->isEnabled() && !testAttr(info, *i)) {
return false;
}
}

View file

@ -11,7 +11,6 @@
#include <QList>
#include <QObject>
#include <libcockatrice/card/card_localization.h>
#include <libcockatrice/card/database/card_database.h>
#include <utility>
@ -168,14 +167,10 @@ public:
return CardFilter::typeName(type);
}
[[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;
[[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;
};
class FilterItem : public FilterTreeNode
@ -212,21 +207,20 @@ public:
return true;
}
[[nodiscard]] bool acceptName(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const;
[[nodiscard]] bool acceptNameExact(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const;
[[nodiscard]] bool acceptName(CardInfoPtr info) const;
[[nodiscard]] bool acceptNameExact(CardInfoPtr info) 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 CardSearchLanguage &searchLanguage) const;
[[nodiscard]] bool acceptText(CardInfoPtr info) 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 CardSearchLanguage &searchLanguage) const;
[[nodiscard]] bool acceptCardAttr(CardInfoPtr info, CardFilter::Attr attr) const;
[[nodiscard]] bool acceptFormat(CardInfoPtr info) const;
[[nodiscard]] bool relationCheck(int cardInfo) const;
};
@ -246,7 +240,7 @@ private:
LogicMap *attrLogicMap(CardFilter::Attr attr);
FilterItemList *attrTypeList(CardFilter::Attr attr, CardFilter::Type type);
bool testAttr(CardInfoPtr info, const LogicMap *lm, const CardSearchLanguage &searchLanguage) const;
bool testAttr(CardInfoPtr info, const LogicMap *lm) const;
void nodeChanged() const override
{
@ -285,7 +279,7 @@ public:
return 0;
}
[[nodiscard]] bool acceptsCard(CardInfoPtr info, const CardSearchLanguage &searchLanguage) const;
[[nodiscard]] bool acceptsCard(CardInfoPtr info) const;
void removeFiltersByAttr(CardFilter::Attr filterType);
void removeFilter(const CardFilter *toRemove);
void clear();

View file

@ -29,7 +29,6 @@ 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

View file

@ -65,31 +65,25 @@ void CardSearchModel::updateSearchResults(const QString &query)
continue;
}
// The completer suggestions match against the same languages the card
// search uses, so typing a localized name finds the card. In Both mode
// either language can match.
for (const QString &matchName : searchableNames(card)) {
const QString lowerName = matchName.toLower();
if (!lowerName.contains(lowerQuery)) {
continue;
}
const QString lowerName = card->getName().toLower();
if (!lowerName.contains(lowerQuery)) {
continue;
}
const int distance = levenshteinDistance(lowerQuery, lowerName);
const int distance = levenshteinDistance(lowerQuery, lowerName);
if (lowerName.startsWith(lowerQuery)) {
prefixMatches.append({card, distance});
} else {
containsMatches.append({card, distance});
}
break;
if (lowerName.startsWith(lowerQuery)) {
prefixMatches.append({card, distance});
} else {
containsMatches.append({card, distance});
}
}
auto sortByDistanceThenLength = [this](const SearchResult &a, const SearchResult &b) {
auto sortByDistanceThenLength = [](const SearchResult &a, const SearchResult &b) {
if (a.distance != b.distance) {
return a.distance < b.distance;
}
return sortableName(a.card).size() < sortableName(b.card).size();
return a.card->getName().size() < b.card->getName().size();
};
std::sort(prefixMatches.begin(), prefixMatches.end(), sortByDistanceThenLength);
@ -107,25 +101,3 @@ void CardSearchModel::updateSearchResults(const QString &query)
endResetModel();
}
QStringList CardSearchModel::searchableNames(const CardInfoPtr &card) const
{
if (searchLanguage.isEnglishOnly()) {
return {card->getName()};
}
const QString localizedName = card->getLocalizedName(searchLanguage.language);
if (searchLanguage.mode == SearchLanguageMode::Selected) {
return {localizedName};
}
return {card->getName(), localizedName};
}
QString CardSearchModel::sortableName(const CardInfoPtr &card) const
{
if (searchLanguage.isEnglishOnly()) {
return card->getName();
}
return card->getLocalizedName(searchLanguage.language);
}

View file

@ -27,14 +27,6 @@ public:
void updateSearchResults(const QString &query); // Update results based on input
void setSearchLanguage(const CardSearchLanguage &searchLang)
{
if (searchLanguage == searchLang) {
return;
}
searchLanguage = searchLang;
}
private:
struct SearchResult
{
@ -42,15 +34,8 @@ private:
int distance;
};
/** @brief The names a card is searched by with the current search language. */
[[nodiscard]] QStringList searchableNames(const CardInfoPtr &card) const;
/** @brief The name used to break distance ties when sorting suggestions. */
[[nodiscard]] QString sortableName(const CardInfoPtr &card) const;
CardDatabaseDisplayModel *sourceModel;
QList<SearchResult> searchResults;
CardSearchLanguage searchLanguage;
};
#endif // CARD_SEARCH_MODEL_H

View file

@ -179,7 +179,7 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex
}
if (filterString != nullptr) {
if (filterTree != nullptr && !filterTree->acceptsCard(info, searchLanguage)) {
if (filterTree != nullptr && !filterTree->acceptsCard(info)) {
return false;
}
return filterString->check(info);
@ -190,14 +190,8 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex
bool CardDatabaseDisplayModel::rowMatchesCardName(CardInfoPtr info) const
{
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 (!cardName.isEmpty() && !info->getName().contains(cardName, Qt::CaseInsensitive)) {
return false;
}
if (!cardNameSet.isEmpty() && !cardNameSet.contains(info->getName())) {
@ -205,7 +199,7 @@ bool CardDatabaseDisplayModel::rowMatchesCardName(CardInfoPtr info) const
}
if (filterTree != nullptr) {
return filterTree->acceptsCard(info, searchLanguage);
return filterTree->acceptsCard(info);
}
return true;
@ -241,28 +235,6 @@ void CardDatabaseDisplayModel::setFilterTree(FilterTree *_filterTree)
invalidate();
}
void CardDatabaseDisplayModel::setStringFilter(const QString &_src)
{
searchText = _src;
delete filterString;
filterString = new FilterString(_src, searchLanguage);
dirty();
}
void CardDatabaseDisplayModel::setSearchLanguage(const CardSearchLanguage &searchLang)
{
if (searchLanguage == searchLang) {
return;
}
searchLanguage = searchLang;
if (filterString != nullptr) {
setStringFilter(searchText);
}
dirty();
}
void CardDatabaseDisplayModel::filterTreeChanged()
{
invalidate();

View file

@ -10,7 +10,6 @@
#include <QSortFilterProxyModel>
#include <QTimer>
#include <libcockatrice/card/card_localization.h>
#include <libcockatrice/filters/filter_string.h>
class FilterTree;
@ -33,8 +32,6 @@ private:
FilterString *filterString;
int loadedRowCount;
QTimer dirtyTimer;
CardSearchLanguage searchLanguage;
QString searchText;
/** The translation table that will be used for sanitizeCardName. */
static QMap<wchar_t, wchar_t> characterTranslation;
@ -58,13 +55,17 @@ public:
cardName = sanitizeCardName(_cardName, characterTranslation);
dirty();
}
void setStringFilter(const QString &_src);
void setStringFilter(const QString &_src)
{
delete filterString;
filterString = new FilterString(_src);
dirty();
}
void setCardNameSet(const QSet<QString> &_cardNameSet)
{
cardNameSet = _cardNameSet;
dirty();
}
void setSearchLanguage(const CardSearchLanguage &searchLang);
void dirty()
{

View file

@ -110,11 +110,6 @@ QString CardsDisplaySettings::getCardLang() const
return getValue("cardLang", QString(), QString(), "en").toString();
}
int CardsDisplaySettings::getCardSearchLanguage() const
{
return getValue("cardSearchLanguage", QString(), QString(), static_cast<int>(SearchLanguageMode::English)).toInt();
}
void CardsDisplaySettings::setDisplayCardNames(bool _displayCardNames)
{
setValue(_displayCardNames, "displayCardNames");
@ -247,12 +242,3 @@ 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);
}

View file

@ -3,7 +3,6 @@
#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
@ -33,7 +32,6 @@ 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);
@ -56,7 +54,6 @@ public:
void setArchidektPreviewCardSize(int _archidektPreviewCardSize);
void setSampleHandSize(int _sampleHandSize);
void setCardLang(const QString &_cardLang);
void setCardSearchLanguage(int _cardSearchLanguage);
signals:
void displayCardNamesChanged();
@ -74,7 +71,6 @@ 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);

View file

@ -73,57 +73,6 @@ QUERY(Color4, cat, "c!gw", false)
QUERY(BracketNextToUnquotedString, cat, "(o:woof OR o:meow)", true)
CardInfoPtr localizedCat()
{
CardInfoPtr localized = CardInfo::newInstance("Cat", "Meow!", false, {}, {}, {}, {}, {});
localized->setLocalizedName("de", "Kater");
localized->setLocalizedText("de", "miaut");
return localized;
}
TEST_F(CardQuery, SearchLanguageEnglishMatchesOnlyEnglish)
{
const CardData localized = localizedCat();
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", 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", 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", 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", 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", CardSearchLanguage{"", SearchLanguageMode::English});
ASSERT_FALSE(englishQuery.check(localized));
ASSERT_TRUE(germanQuery.check(localized));
}
} // namespace
int main(int argc, char **argv)

View file

@ -575,19 +575,6 @@ 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>(SearchLanguageMode::English));
}
TEST_F(SettingsDefaultsTest, CardsDisplay_CardSearchLanguage_SetAndGet)
{
CardsDisplaySettings s(settingsPath, nullptr);
s.setCardSearchLanguage(static_cast<int>(SearchLanguageMode::Selected));
ASSERT_EQ(s.getCardSearchLanguage(), static_cast<int>(SearchLanguageMode::Selected));
}
// --- VisualDeckStorageSettings ---
TEST_F(SettingsDefaultsTest, VisualDeckStorage_SortingOrder_Default)