mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-15 06:52:15 -07:00
380 lines
14 KiB
C++
380 lines
14 KiB
C++
#include "tab_edhrec_main.h"
|
|
|
|
#include "../../../../game/cards/card_completer_proxy_model.h"
|
|
#include "../../../../game/cards/card_database_manager.h"
|
|
#include "../../../../game/cards/card_search_model.h"
|
|
#include "../../tab_supervisor.h"
|
|
#include "api_response/average_deck/edhrec_average_deck_api_response.h"
|
|
#include "api_response/commander/edhrec_commander_api_response.h"
|
|
#include "api_response/top_cards/edhrec_top_cards_api_response.h"
|
|
#include "api_response/top_commanders/edhrec_top_commanders_api_response.h"
|
|
#include "api_response/top_tags/edhrec_top_tags_api_response.h"
|
|
#include "display/commander/edhrec_commander_api_response_display_widget.h"
|
|
#include "display/top_cards/edhrec_top_cards_api_response_display_widget.h"
|
|
#include "display/top_commander/edhrec_top_commanders_api_response_display_widget.h"
|
|
#include "display/top_tags/edhrec_top_tags_api_response_display_widget.h"
|
|
|
|
#include <QCompleter>
|
|
#include <QDebug>
|
|
#include <QHBoxLayout>
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QNetworkAccessManager>
|
|
#include <QNetworkReply>
|
|
#include <QPushButton>
|
|
#include <QRegularExpression>
|
|
#include <QResizeEvent>
|
|
|
|
static bool canBeCommander(const CardInfoPtr &cardInfo)
|
|
{
|
|
return ((cardInfo->getCardType().contains("Legendary", Qt::CaseInsensitive) &&
|
|
cardInfo->getCardType().contains("Creature", Qt::CaseInsensitive))) ||
|
|
cardInfo->getText().contains("can be your commander", Qt::CaseInsensitive);
|
|
}
|
|
|
|
TabEdhRecMain::TabEdhRecMain(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
|
|
{
|
|
networkManager = new QNetworkAccessManager(this);
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
|
networkManager->setTransferTimeout(); // Use Qt's default timeout
|
|
#endif
|
|
|
|
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
|
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *)));
|
|
|
|
container = new QWidget(this);
|
|
mainLayout = new QVBoxLayout(container);
|
|
container->setLayout(mainLayout);
|
|
|
|
navigationContainer = new QWidget(container);
|
|
navigationContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
|
navigationLayout = new QHBoxLayout(navigationContainer);
|
|
navigationLayout->setSpacing(5);
|
|
navigationContainer->setLayout(navigationLayout);
|
|
|
|
cardsPushButton = new QPushButton(navigationContainer);
|
|
connect(cardsPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopCards);
|
|
topCommandersPushButton = new QPushButton(navigationContainer);
|
|
connect(topCommandersPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopCommanders);
|
|
tagsPushButton = new QPushButton(navigationContainer);
|
|
connect(tagsPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopTags);
|
|
|
|
searchBar = new QLineEdit(this);
|
|
auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
|
auto displayModel = new CardDatabaseDisplayModel(this);
|
|
displayModel->setSourceModel(cardDatabaseModel);
|
|
CardSearchModel *searchModel = new CardSearchModel(displayModel, this);
|
|
|
|
CardCompleterProxyModel *proxyModel = new CardCompleterProxyModel(this);
|
|
proxyModel->setSourceModel(searchModel);
|
|
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
proxyModel->setFilterRole(Qt::DisplayRole);
|
|
|
|
QCompleter *completer = new QCompleter(proxyModel, this);
|
|
completer->setCompletionRole(Qt::DisplayRole);
|
|
completer->setCompletionMode(QCompleter::PopupCompletion);
|
|
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
|
completer->setFilterMode(Qt::MatchContains);
|
|
completer->setMaxVisibleItems(10);
|
|
searchBar->setCompleter(completer);
|
|
|
|
// Update suggestions dynamically
|
|
connect(searchBar, &QLineEdit::textChanged, searchModel, &CardSearchModel::updateSearchResults);
|
|
connect(searchBar, &QLineEdit::textChanged, this, [=](const QString &text) {
|
|
// Ensure substring matching
|
|
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
|
|
proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
|
|
|
|
if (!text.isEmpty()) {
|
|
completer->complete(); // Force the dropdown to appear
|
|
}
|
|
});
|
|
|
|
searchPushButton = new QPushButton(navigationContainer);
|
|
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { doSearch(); });
|
|
|
|
navigationLayout->addWidget(cardsPushButton);
|
|
navigationLayout->addWidget(topCommandersPushButton);
|
|
navigationLayout->addWidget(tagsPushButton);
|
|
navigationLayout->addWidget(searchBar);
|
|
navigationLayout->addWidget(searchPushButton);
|
|
|
|
currentPageDisplay = new QWidget(container);
|
|
currentPageLayout = new QVBoxLayout(currentPageDisplay);
|
|
currentPageDisplay->setLayout(currentPageLayout);
|
|
|
|
mainLayout->addWidget(navigationContainer);
|
|
mainLayout->addWidget(currentPageDisplay);
|
|
|
|
// Ensure navigation stays at the top and currentPageDisplay takes remaining space
|
|
mainLayout->setStretch(0, 0); // navigationContainer gets minimum space
|
|
mainLayout->setStretch(1, 1); // currentPageDisplay expands as much as possible
|
|
|
|
setCentralWidget(container);
|
|
|
|
TabEdhRecMain::retranslateUi();
|
|
|
|
getTopCards();
|
|
}
|
|
|
|
void TabEdhRecMain::retranslateUi()
|
|
{
|
|
cardsPushButton->setText(tr("&Cards"));
|
|
topCommandersPushButton->setText(tr("Top Commanders"));
|
|
tagsPushButton->setText(tr("Tags"));
|
|
searchBar->setPlaceholderText(tr("Search for a card ..."));
|
|
searchPushButton->setText(tr("Search"));
|
|
}
|
|
|
|
void TabEdhRecMain::doSearch()
|
|
{
|
|
CardInfoPtr searchedCard = CardDatabaseManager::getInstance()->getCard(searchBar->text());
|
|
if (!searchedCard) {
|
|
return;
|
|
}
|
|
|
|
setCard(searchedCard, canBeCommander(searchedCard));
|
|
}
|
|
|
|
void TabEdhRecMain::setCard(CardInfoPtr _cardToQuery, bool isCommander)
|
|
{
|
|
cardToQuery = _cardToQuery;
|
|
|
|
if (!cardToQuery) {
|
|
qDebug() << "Invalid card information provided.";
|
|
return;
|
|
}
|
|
|
|
QString cardName = cardToQuery->getName();
|
|
QString formattedName = cardName.toLower().replace(" ", "-").remove(QRegularExpression("[^a-z0-9\\-]"));
|
|
|
|
QString url;
|
|
if (isCommander) {
|
|
url = QString("https://json.edhrec.com/pages/commanders/%1.json").arg(formattedName);
|
|
} else {
|
|
url = QString("https://json.edhrec.com/pages/cards/%1.json").arg(formattedName);
|
|
}
|
|
|
|
QNetworkRequest request{QUrl(url)};
|
|
|
|
networkManager->get(request);
|
|
}
|
|
|
|
void TabEdhRecMain::actNavigatePage(QString url)
|
|
{
|
|
QNetworkRequest request{QUrl("https://json.edhrec.com/pages" + url + ".json")};
|
|
|
|
networkManager->get(request);
|
|
}
|
|
|
|
void TabEdhRecMain::getTopCards()
|
|
{
|
|
QNetworkRequest request{QUrl("https://json.edhrec.com/pages/top/year.json")};
|
|
|
|
networkManager->get(request);
|
|
}
|
|
|
|
void TabEdhRecMain::getTopCommanders()
|
|
{
|
|
QNetworkRequest request{QUrl("https://json.edhrec.com/pages/commanders/year.json")};
|
|
|
|
networkManager->get(request);
|
|
}
|
|
|
|
void TabEdhRecMain::getTopTags()
|
|
{
|
|
QNetworkRequest request{QUrl("https://json.edhrec.com/pages/tags.json")};
|
|
|
|
networkManager->get(request);
|
|
}
|
|
|
|
void TabEdhRecMain::processApiJson(QNetworkReply *reply)
|
|
{
|
|
if (reply->error() != QNetworkReply::NoError) {
|
|
qDebug() << "Network error occurred:" << reply->errorString();
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
QByteArray responseData = reply->readAll();
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
|
|
|
|
if (!jsonDoc.isObject()) {
|
|
qDebug() << "Invalid JSON response received.";
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
QJsonObject jsonObj = jsonDoc.object();
|
|
|
|
// Get the actual URL from the reply
|
|
QString responseUrl = reply->url().toString();
|
|
|
|
// Check if the response URL matches a commander request
|
|
if (responseUrl.startsWith("https://json.edhrec.com/pages/commanders/year.json")) {
|
|
processTopCommandersResponse(jsonObj);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/commanders/")) {
|
|
qInfo() << "Received top kek";
|
|
processCommanderResponse(jsonObj, responseUrl);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/cards/")) {
|
|
processCommanderResponse(jsonObj);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/tags/")) {
|
|
processCommanderResponse(jsonObj);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/tags.json")) {
|
|
processTopTagsResponse(jsonObj);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/top/year.json")) {
|
|
processTopCardsResponse(jsonObj);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/combos/")) {
|
|
qInfo() << "Received combos";
|
|
processCommanderResponse(jsonObj);
|
|
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/average-decks/")) {
|
|
processAverageDeckResponse(jsonObj);
|
|
} else {
|
|
prettyPrintJson(jsonObj, 4);
|
|
}
|
|
|
|
reply->deleteLater();
|
|
}
|
|
|
|
void TabEdhRecMain::processTopCardsResponse(QJsonObject reply)
|
|
{
|
|
EdhrecTopCardsApiResponse deckData;
|
|
deckData.fromJson(reply);
|
|
|
|
// **Remove previous page display to prevent stacking**
|
|
if (currentPageDisplay) {
|
|
mainLayout->removeWidget(currentPageDisplay);
|
|
delete currentPageDisplay;
|
|
currentPageDisplay = nullptr;
|
|
}
|
|
|
|
// **Create new currentPageDisplay**
|
|
currentPageDisplay = new QWidget(container);
|
|
currentPageLayout = new QVBoxLayout(currentPageDisplay);
|
|
currentPageDisplay->setLayout(currentPageLayout);
|
|
|
|
auto display = new EdhrecTopCardsApiResponseDisplayWidget(currentPageDisplay, deckData);
|
|
currentPageLayout->addWidget(display);
|
|
|
|
mainLayout->addWidget(currentPageDisplay);
|
|
|
|
// **Ensure layout stays correct**
|
|
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
|
|
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
|
|
}
|
|
|
|
void TabEdhRecMain::processTopTagsResponse(QJsonObject reply)
|
|
{
|
|
EdhrecTopTagsApiResponse deckData;
|
|
deckData.fromJson(reply);
|
|
|
|
// **Remove previous page display to prevent stacking**
|
|
if (currentPageDisplay) {
|
|
mainLayout->removeWidget(currentPageDisplay);
|
|
delete currentPageDisplay;
|
|
currentPageDisplay = nullptr;
|
|
}
|
|
|
|
// **Create new currentPageDisplay**
|
|
currentPageDisplay = new QWidget(container);
|
|
currentPageLayout = new QVBoxLayout(currentPageDisplay);
|
|
currentPageDisplay->setLayout(currentPageLayout);
|
|
|
|
auto display = new EdhrecTopTagsApiResponseDisplayWidget(currentPageDisplay, deckData);
|
|
currentPageLayout->addWidget(display);
|
|
|
|
mainLayout->addWidget(currentPageDisplay);
|
|
|
|
// **Ensure layout stays correct**
|
|
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
|
|
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
|
|
}
|
|
|
|
void TabEdhRecMain::processTopCommandersResponse(QJsonObject reply)
|
|
{
|
|
EdhrecTopCommandersApiResponse deckData;
|
|
deckData.fromJson(reply);
|
|
|
|
// **Remove previous page display to prevent stacking**
|
|
if (currentPageDisplay) {
|
|
mainLayout->removeWidget(currentPageDisplay);
|
|
delete currentPageDisplay;
|
|
currentPageDisplay = nullptr;
|
|
}
|
|
|
|
// **Create new currentPageDisplay**
|
|
currentPageDisplay = new QWidget(container);
|
|
currentPageLayout = new QVBoxLayout(currentPageDisplay);
|
|
currentPageDisplay->setLayout(currentPageLayout);
|
|
|
|
auto display = new EdhrecTopCommandersApiResponseDisplayWidget(currentPageDisplay, deckData);
|
|
currentPageLayout->addWidget(display);
|
|
|
|
mainLayout->addWidget(currentPageDisplay);
|
|
|
|
// **Ensure layout stays correct**
|
|
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
|
|
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
|
|
}
|
|
|
|
void TabEdhRecMain::processCommanderResponse(QJsonObject reply, QString responseUrl)
|
|
{
|
|
EdhrecCommanderApiResponse deckData;
|
|
deckData.fromJson(reply);
|
|
|
|
// **Remove previous page display to prevent stacking**
|
|
if (currentPageDisplay) {
|
|
mainLayout->removeWidget(currentPageDisplay);
|
|
delete currentPageDisplay;
|
|
currentPageDisplay = nullptr;
|
|
}
|
|
|
|
// **Create new currentPageDisplay**
|
|
currentPageDisplay = new QWidget(container);
|
|
currentPageLayout = new QVBoxLayout(currentPageDisplay);
|
|
currentPageDisplay->setLayout(currentPageLayout);
|
|
|
|
auto display = new EdhrecCommanderApiResponseDisplayWidget(currentPageDisplay, deckData, responseUrl);
|
|
currentPageLayout->addWidget(display);
|
|
|
|
mainLayout->addWidget(currentPageDisplay);
|
|
|
|
// **Ensure layout stays correct**
|
|
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
|
|
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
|
|
}
|
|
|
|
void TabEdhRecMain::processAverageDeckResponse(QJsonObject reply)
|
|
{
|
|
EdhrecAverageDeckApiResponse deckData;
|
|
deckData.fromJson(reply);
|
|
tabSupervisor->addVisualDeckEditorTab(deckData.deck.deckLoader);
|
|
}
|
|
|
|
void TabEdhRecMain::prettyPrintJson(const QJsonValue &value, int indentLevel)
|
|
{
|
|
const QString indent(indentLevel * 2, ' '); // Adjust spacing as needed for pretty printing
|
|
|
|
if (value.isObject()) {
|
|
QJsonObject obj = value.toObject();
|
|
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
|
qDebug().noquote() << indent + it.key() + ":";
|
|
prettyPrintJson(it.value(), indentLevel + 1);
|
|
}
|
|
} else if (value.isArray()) {
|
|
QJsonArray array = value.toArray();
|
|
for (int i = 0; i < array.size(); ++i) {
|
|
qDebug().noquote() << indent + QString("[%1]:").arg(i);
|
|
prettyPrintJson(array[i], indentLevel + 1);
|
|
}
|
|
} else if (value.isString()) {
|
|
qDebug().noquote() << indent + "\"" + value.toString() + "\"";
|
|
} else if (value.isDouble()) {
|
|
qDebug().noquote() << indent + QString::number(value.toDouble());
|
|
} else if (value.isBool()) {
|
|
qDebug().noquote() << indent + (value.toBool() ? "true" : "false");
|
|
} else if (value.isNull()) {
|
|
qDebug().noquote() << indent + "null";
|
|
}
|
|
}
|