[Client] Keep Commander Spellbook requests bound to the active deck (#7722)

* [Client] Keep Commander Spellbook requests bound to the active deck [skip ci]

* [Client] Restore the bracket info tooltip when idle

retranslateUi() used to install the static "Why this bracket?" tooltip, but it now calls displayEstimate(), which returned early while no estimate existed. That left the info button without its idle tooltip.

Set the fallback where displayEstimate() owns the button's tooltip. An existing estimate still wins, and a language change refreshes the text.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
Bryce! 2026-11-03 23:49:31 -05:00 • committed by GitHub
parent 94f7de42f2
commit 624163916f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 182 additions and 45 deletions

View file

@ -26,6 +26,11 @@ quint64 CommanderBracketService::estimateBracket(const DeckList &deck, QObject *
return CommanderSpellbookApiAccessor::instance().estimateBracket(deck, requester); return CommanderSpellbookApiAccessor::instance().estimateBracket(deck, requester);
} }
void CommanderBracketService::cancelEstimate(quint64 requestId)
{
CommanderSpellbookApiAccessor::instance().cancelEstimate(requestId);
}
void CommanderBracketService::onEstimateBracketFinished(CommanderSpellbookApiAccessor::RequestId id, void CommanderBracketService::onEstimateBracketFinished(CommanderSpellbookApiAccessor::RequestId id,
QObject *requester, QObject *requester,
const EstimateBracketResult &result) const EstimateBracketResult &result)

View file

@ -30,6 +30,7 @@ public:
static CommanderBracketService &instance(); static CommanderBracketService &instance();
quint64 estimateBracket(const DeckList &deck, QObject *requester); quint64 estimateBracket(const DeckList &deck, QObject *requester);
void cancelEstimate(quint64 requestId);
signals: signals:
void estimateFinished(quint64 requestId, QObject *requester, const CommanderBracketEstimate &estimate); void estimateFinished(quint64 requestId, QObject *requester, const CommanderBracketEstimate &estimate);

View file

@ -28,9 +28,18 @@ template <class T> class QSharedPointer;
CommanderBracketWidget::CommanderBracketWidget(QWidget *parent) : QWidget(parent) CommanderBracketWidget::CommanderBracketWidget(QWidget *parent) : QWidget(parent)
{ {
autoEstimateTimer = new QTimer(this);
autoEstimateTimer->setSingleShot(true);
connect(autoEstimateTimer, &QTimer::timeout, this, [this]() {
if (SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled() ==
commanderSpellbookIntegrationEnabledIndexAutomatic) {
requestBracketEstimate();
}
});
bracketLabel = new QLabel(tr("Bracket:"), this); bracketLabel = new QLabel(tr("Bracket:"), this);
bracketValueLabel = new QLabel(this); bracketValueLabel = new QLabel(this);
bracketValueLabel->setTextFormat(Qt::PlainText);
bracketValueLabel->setText("-"); bracketValueLabel->setText("-");
bracketValueLabel->setObjectName("bracketValueLabel"); bracketValueLabel->setObjectName("bracketValueLabel");
@ -65,18 +74,38 @@ CommanderBracketWidget::CommanderBracketWidget(QWidget *parent) : QWidget(parent
this, &CommanderBracketWidget::maybeAutoEstimateBracket); this, &CommanderBracketWidget::maybeAutoEstimateBracket);
connect(&SettingsCache::instance().deckEditor(), connect(&SettingsCache::instance().deckEditor(),
&DeckEditorSettings::commanderSpellbookIntegrationUseOfficialBracketNamesChanged, this, &DeckEditorSettings::commanderSpellbookIntegrationUseOfficialBracketNamesChanged, this,
&CommanderBracketWidget::maybeAutoEstimateBracket); &CommanderBracketWidget::displayEstimate);
setVisible(false); setVisible(false);
} }
CommanderBracketWidget::~CommanderBracketWidget()
{
cancelEstimate();
}
void CommanderBracketWidget::cancelEstimate()
{
autoEstimateTimer->stop();
const quint64 canceledRequest = requestId;
requestId = 0;
CommanderBracketService::instance().cancelEstimate(canceledRequest);
bracketRefreshButton->setEnabled(true);
if (canceledRequest) {
bracketValueLabel->setText("-");
bracketValueLabel->setToolTip({});
}
}
void CommanderBracketWidget::setDeck(const QSharedPointer<DeckList> &_deck) void CommanderBracketWidget::setDeck(const QSharedPointer<DeckList> &_deck)
{ {
cancelEstimate();
deck = _deck; deck = _deck;
requestId = 0; // invalidate any in-flight estimate for the previous deck hasEstimate = false;
// Reset the displayed bracket // Reset the displayed bracket
bracketValueLabel->setText("-"); bracketValueLabel->setText("-");
bracketValueLabel->setToolTip({});
bracketInfoButton->setToolTip({}); bracketInfoButton->setToolTip({});
bracketInfoButton->setEnabled(false); bracketInfoButton->setEnabled(false);
bracketRefreshButton->setEnabled(true); bracketRefreshButton->setEnabled(true);
@ -144,7 +173,7 @@ bool CommanderBracketWidget::promptCommanderSpellbookIntegration()
dialog.exec(); dialog.exec();
// Persist naming choice (if not disabled) // Persist naming choice (if not disabled)
if (clickedButton != disableBtn) { if (clickedButton == enableBtn || clickedButton == automaticBtn) {
bool useOfficial = namingCombo->currentIndex() == 1; bool useOfficial = namingCombo->currentIndex() == 1;
SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationUseOfficialBracketNames(useOfficial); SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationUseOfficialBracketNames(useOfficial);
} }
@ -176,9 +205,20 @@ void CommanderBracketWidget::updateBracketVisibility(bool visible)
void CommanderBracketWidget::requestBracketEstimate() void CommanderBracketWidget::requestBracketEstimate()
{ {
const int mode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled();
if (!deck || deck->getGameFormat().compare("commander", Qt::CaseInsensitive) != 0 || requestId ||
(mode != commanderSpellbookIntegrationEnabledIndexEnabled &&
mode != commanderSpellbookIntegrationEnabledIndexAutomatic)) {
return;
}
autoEstimateTimer->stop();
hasEstimate = false;
bracketRefreshButton->setEnabled(false); bracketRefreshButton->setEnabled(false);
bracketInfoButton->setEnabled(false); bracketInfoButton->setEnabled(false);
bracketInfoButton->setToolTip({});
bracketValueLabel->setText(tr("Calculating…")); bracketValueLabel->setText(tr("Calculating…"));
bracketValueLabel->setToolTip({});
requestId = CommanderBracketService::instance().estimateBracket(*deck, this); requestId = CommanderBracketService::instance().estimateBracket(*deck, this);
} }
@ -191,22 +231,35 @@ void CommanderBracketWidget::onEstimateBracketFinished(quint64 id,
return; return;
} }
requestId = 0;
hasEstimate = true;
lastEstimate = result;
displayEstimate();
bracketRefreshButton->setEnabled(true);
}
void CommanderBracketWidget::displayEstimate()
{
if (!hasEstimate) {
bracketInfoButton->setToolTip(tr("Why this bracket?"));
return;
}
BracketExplainer explainer; BracketExplainer explainer;
lastBracketExplanation = explainer.explain(result.rawResult); lastBracketExplanation = explainer.explain(lastEstimate.rawResult);
// Display bracket // Display bracket
bracketValueLabel->setText( bracketValueLabel->setText(
SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationUseOfficialBracketNames() SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationUseOfficialBracketNames()
? result.officialName ? lastEstimate.officialName
: result.displayName); : lastEstimate.displayName);
bracketRefreshButton->setEnabled(true);
// Build tooltip // Build tooltip
QString tooltip; QString tooltip;
for (const auto &section : lastBracketExplanation.sections) { for (const auto &section : lastBracketExplanation.sections) {
tooltip += "<b>" + section.title + "</b><br>"; tooltip += "<b>" + section.title.toHtmlEscaped() + "</b><br>";
for (const auto &line : section.bulletPoints) { for (const auto &line : section.bulletPoints) {
tooltip += "• " + line + "<br>"; tooltip += "• " + line.toHtmlEscaped() + "<br>";
} }
tooltip += "<br>"; tooltip += "<br>";
} }
@ -215,13 +268,17 @@ void CommanderBracketWidget::onEstimateBracketFinished(quint64 id,
bracketInfoButton->setEnabled(!tooltip.isEmpty()); bracketInfoButton->setEnabled(!tooltip.isEmpty());
} }
void CommanderBracketWidget::onEstimateBracketError(quint64 id, QObject *requester, const QString & /*error*/) void CommanderBracketWidget::onEstimateBracketError(quint64 id, QObject *requester, const QString &error)
{ {
if (requester != this || id != requestId) { if (requester != this || id != requestId) {
return; return;
} }
requestId = 0;
hasEstimate = false;
bracketValueLabel->setText("-"); bracketValueLabel->setText("-");
bracketValueLabel->setToolTip(
QStringLiteral("<qt>%1</qt>").arg(tr("Unable to estimate bracket: %1").arg(error).toHtmlEscaped()));
bracketRefreshButton->setEnabled(true); bracketRefreshButton->setEnabled(true);
bracketInfoButton->setToolTip({}); bracketInfoButton->setToolTip({});
bracketInfoButton->setEnabled(false); bracketInfoButton->setEnabled(false);
@ -229,6 +286,15 @@ void CommanderBracketWidget::onEstimateBracketError(quint64 id, QObject *request
void CommanderBracketWidget::maybeAutoEstimateBracket() void CommanderBracketWidget::maybeAutoEstimateBracket()
{ {
if (prompting) {
return;
}
autoEstimateTimer->stop();
if (!deck) {
cancelEstimate();
updateBracketVisibility(false);
return;
}
const QString formatKey = deck->getGameFormat(); const QString formatKey = deck->getGameFormat();
const bool isCommander = (formatKey.compare("commander", Qt::CaseInsensitive) == 0); const bool isCommander = (formatKey.compare("commander", Qt::CaseInsensitive) == 0);
@ -236,17 +302,20 @@ void CommanderBracketWidget::maybeAutoEstimateBracket()
int mode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled(); int mode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled();
if (!isCommander || mode == commanderSpellbookIntegrationEnabledIndexDisabled) { if (!isCommander || mode == commanderSpellbookIntegrationEnabledIndexDisabled) {
cancelEstimate();
updateBracketVisibility(false); updateBracketVisibility(false);
return; return;
} }
if (mode == commanderSpellbookIntegrationEnabledIndexUnprompted) { if (mode == commanderSpellbookIntegrationEnabledIndexUnprompted) {
if (prompting) { const auto promptedDeck = deck;
return;
}
prompting = true; prompting = true;
const bool accepted = promptCommanderSpellbookIntegration(); const bool accepted = promptCommanderSpellbookIntegration();
prompting = false; prompting = false;
if (deck != promptedDeck || !deck || deck->getGameFormat().compare("commander", Qt::CaseInsensitive) != 0) {
maybeAutoEstimateBracket();
return;
}
if (!accepted) { if (!accepted) {
updateBracketVisibility(false); updateBracketVisibility(false);
return; return;
@ -261,17 +330,17 @@ void CommanderBracketWidget::maybeAutoEstimateBracket()
} }
// Avoid firing if we already have a result or a request in flight // Avoid firing if we already have a result or a request in flight
if (!bracketRefreshButton->isEnabled()) { if (requestId || hasEstimate) {
return; return;
} }
// Defer to avoid races during init / model rebuild // Defer to avoid races during init / model rebuild
QTimer::singleShot(0, this, &CommanderBracketWidget::requestBracketEstimate); autoEstimateTimer->start(0);
} }
void CommanderBracketWidget::retranslateUi() void CommanderBracketWidget::retranslateUi()
{ {
bracketLabel->setText(tr("Bracket:")); bracketLabel->setText(tr("Bracket:"));
bracketInfoButton->setToolTip(tr("Why this bracket?")); displayEstimate();
bracketRefreshButton->setToolTip(tr("Recalculate bracket")); bracketRefreshButton->setToolTip(tr("Recalculate bracket"));
} }

View file

@ -1,6 +1,7 @@
#ifndef COCKATRICE_COMMANDER_BRACKET_WIDGET_H #ifndef COCKATRICE_COMMANDER_BRACKET_WIDGET_H
#define COCKATRICE_COMMANDER_BRACKET_WIDGET_H #define COCKATRICE_COMMANDER_BRACKET_WIDGET_H
#include "commander_bracket_service.h"
#include "commander_spellbook_bracket_explainer.h" #include "commander_spellbook_bracket_explainer.h"
#include <QSharedPointer> #include <QSharedPointer>
@ -11,6 +12,7 @@
class QLabel; class QLabel;
class QToolButton; class QToolButton;
class QTimer;
struct CommanderBracketEstimate; struct CommanderBracketEstimate;
class DeckList; class DeckList;
class QObject; class QObject;
@ -22,6 +24,7 @@ class CommanderBracketWidget : public QWidget
public: public:
explicit CommanderBracketWidget(QWidget *parent = nullptr); explicit CommanderBracketWidget(QWidget *parent = nullptr);
~CommanderBracketWidget() override;
void setDeck(const QSharedPointer<DeckList> &_deck); void setDeck(const QSharedPointer<DeckList> &_deck);
void retranslateUi(); void retranslateUi();
@ -35,10 +38,15 @@ private slots:
private: private:
bool promptCommanderSpellbookIntegration(); bool promptCommanderSpellbookIntegration();
void updateBracketVisibility(bool visible); void updateBracketVisibility(bool visible);
void cancelEstimate();
void displayEstimate();
QSharedPointer<DeckList> deck; QSharedPointer<DeckList> deck;
bool prompting = false; bool prompting = false;
quint64 requestId = 0; quint64 requestId = 0;
QTimer *autoEstimateTimer;
bool hasEstimate = false;
CommanderBracketEstimate lastEstimate;
QLabel *bracketLabel; QLabel *bracketLabel;
QLabel *bracketValueLabel; QLabel *bracketValueLabel;

View file

@ -9,9 +9,10 @@
#include <QJsonParseError> #include <QJsonParseError>
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QPointer>
#include <QStringLiteral> #include <QStringLiteral>
#include <QUrl> #include <QUrl>
#include <QVariant> #include <libcockatrice/network/network_manager.h>
#include <version_string.h> #include <version_string.h>
class DeckList; class DeckList;
@ -24,13 +25,18 @@ CommanderSpellbookApiAccessor &CommanderSpellbookApiAccessor::instance()
return instance; return instance;
} }
CommanderSpellbookApiAccessor::CommanderSpellbookApiAccessor(QObject *parent) : QObject(parent) CommanderSpellbookApiAccessor::CommanderSpellbookApiAccessor(QObject *parent)
: QObject(parent), network(NetworkManagerFactory::create(this))
{ {
} }
CommanderSpellbookApiAccessor::RequestId CommanderSpellbookApiAccessor::estimateBracket(const DeckList &deck, CommanderSpellbookApiAccessor::RequestId CommanderSpellbookApiAccessor::estimateBracket(const DeckList &deck,
QObject *requester) QObject *requester)
{ {
if (!requester) {
return 0;
}
CommanderSpellbookDeckRequest deckRequest = CommanderSpellbookDeckRequest::fromDeckList(deck); CommanderSpellbookDeckRequest deckRequest = CommanderSpellbookDeckRequest::fromDeckList(deck);
QJsonDocument doc(deckRequest.toJson()); QJsonDocument doc(deckRequest.toJson());
@ -40,30 +46,39 @@ CommanderSpellbookApiAccessor::RequestId CommanderSpellbookApiAccessor::estimate
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
QNetworkReply *reply = network.post(req, body); QNetworkReply *reply = network->post(req, body);
const RequestId id = nextRequestId++; const RequestId id = nextRequestId++;
reply->setProperty("requestId", QVariant::fromValue(id)); pendingRequests.insert(id, reply);
reply->setProperty("requester", QVariant::fromValue(requester)); const QPointer<QObject> guardedRequester(requester);
connect(requester, &QObject::destroyed, reply, [this, id]() { cancelEstimate(id); });
connect(reply, &QNetworkReply::finished, this, [this, reply]() { onEstimateReplyFinished(reply); }); connect(reply, &QNetworkReply::finished, this, [this, reply, id, guardedRequester]() {
if (pendingRequests.take(id) != reply) {
return;
}
reply->deleteLater();
if (guardedRequester) {
onEstimateReplyFinished(reply, id, guardedRequester);
}
});
return id; return id;
} }
void CommanderSpellbookApiAccessor::onEstimateReplyFinished(QNetworkReply *reply) void CommanderSpellbookApiAccessor::cancelEstimate(RequestId id)
{ {
reply->deleteLater(); const QPointer<QNetworkReply> reply = pendingRequests.take(id);
if (!reply) {
const RequestId id = reply->property("requestId").toULongLong();
QObject *requester = reply->property("requester").value<QObject *>();
if (!requester) {
// Requester died — silently drop
return; return;
} }
disconnect(reply, nullptr, this, nullptr);
reply->abort();
reply->deleteLater();
}
void CommanderSpellbookApiAccessor::onEstimateReplyFinished(QNetworkReply *reply, RequestId id, QObject *requester)
{
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
emit estimateBracketError(id, requester, reply->errorString()); emit estimateBracketError(id, requester, reply->errorString());
return; return;
@ -78,6 +93,10 @@ void CommanderSpellbookApiAccessor::onEstimateReplyFinished(QNetworkReply *reply
} }
EstimateBracketResult result = EstimateBracketResult::fromJson(doc.object()); EstimateBracketResult result = EstimateBracketResult::fromJson(doc.object());
if (result.bracketTag.trimmed().isEmpty()) {
emit estimateBracketError(id, requester, QStringLiteral("Missing bracket in response"));
return;
}
emit estimateBracketFinished(id, requester, result); emit estimateBracketFinished(id, requester, result);
} }

View file

@ -1,14 +1,16 @@
#ifndef COCKATRICE_COMMANDER_SPELLBOOK_API_ACCESSOR_H #ifndef COCKATRICE_COMMANDER_SPELLBOOK_API_ACCESSOR_H
#define COCKATRICE_COMMANDER_SPELLBOOK_API_ACCESSOR_H #define COCKATRICE_COMMANDER_SPELLBOOK_API_ACCESSOR_H
#include <QNetworkAccessManager> #include <QHash>
#include <QObject> #include <QObject>
#include <QPointer>
#include <QString> #include <QString>
#include <QtGlobal> #include <QtGlobal>
#include <qtmetamacros.h> #include <qtmetamacros.h>
class DeckList; class DeckList;
class QNetworkReply; class QNetworkReply;
class QNetworkAccessManager;
struct EstimateBracketResult; struct EstimateBracketResult;
class CommanderSpellbookApiAccessor final : public QObject class CommanderSpellbookApiAccessor final : public QObject
@ -21,6 +23,7 @@ public:
using RequestId = quint64; using RequestId = quint64;
RequestId estimateBracket(const DeckList &deck, QObject *requester); RequestId estimateBracket(const DeckList &deck, QObject *requester);
void cancelEstimate(RequestId id);
signals: signals:
void estimateBracketFinished(RequestId id, QObject *requester, const EstimateBracketResult &result); void estimateBracketFinished(RequestId id, QObject *requester, const EstimateBracketResult &result);
@ -31,9 +34,10 @@ private:
explicit CommanderSpellbookApiAccessor(QObject *parent = nullptr); explicit CommanderSpellbookApiAccessor(QObject *parent = nullptr);
Q_DISABLE_COPY_MOVE(CommanderSpellbookApiAccessor) Q_DISABLE_COPY_MOVE(CommanderSpellbookApiAccessor)
void onEstimateReplyFinished(QNetworkReply *reply); void onEstimateReplyFinished(QNetworkReply *reply, RequestId id, QObject *requester);
QNetworkAccessManager network; QNetworkAccessManager *network;
QHash<RequestId, QPointer<QNetworkReply>> pendingRequests;
RequestId nextRequestId = 1; RequestId nextRequestId = 1;
}; };

View file

@ -3,11 +3,14 @@
#include "../../../../../client/settings/cache_settings.h" #include "../../../../../client/settings/cache_settings.h"
#include <QByteArray> #include <QByteArray>
#include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError> #include <QJsonParseError>
#include <QMap> #include <QMap>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QSet>
#include <QString> #include <QString>
#include <QStringLiteral> #include <QStringLiteral>
#include <QUrl> #include <QUrl>
@ -22,6 +25,14 @@ HandleCommanderBrackets::HandleCommanderBrackets(QObject *parent)
{ {
} }
HandleCommanderBrackets::~HandleCommanderBrackets()
{
if (reply) {
disconnect(reply, nullptr, this, nullptr);
reply->abort();
}
}
void HandleCommanderBrackets::downloadBracketDefinitions() void HandleCommanderBrackets::downloadBracketDefinitions()
{ {
if (reply) { if (reply) {
@ -35,31 +46,49 @@ void HandleCommanderBrackets::downloadBracketDefinitions()
void HandleCommanderBrackets::actFinishParsingDownloadedData() void HandleCommanderBrackets::actFinishParsingDownloadedData()
{ {
reply = qobject_cast<QNetworkReply *>(sender()); auto *finishedReply = qobject_cast<QNetworkReply *>(sender());
if (!finishedReply || finishedReply != reply) {
return;
}
if (reply->error() != QNetworkReply::NoError) { // Clear the active request before notifying listeners, which may immediately retry.
emit sigBracketDefinitionsDownloadFailed(reply->error()); reply = nullptr;
finishedReply->deleteLater();
reply->deleteLater(); if (finishedReply->error() != QNetworkReply::NoError) {
emit sigBracketDefinitionsDownloadFailed(finishedReply->error());
return; return;
} }
QJsonParseError parseError; QJsonParseError parseError;
auto document = QJsonDocument::fromJson(reply->readAll(), &parseError); auto document = QJsonDocument::fromJson(finishedReply->readAll(), &parseError);
if (parseError.error != QJsonParseError::NoError) { if (parseError.error != QJsonParseError::NoError || !document.isObject() ||
!document.object().value("brackets").isArray() || document.object().value("brackets").toArray().isEmpty()) {
emit sigBracketDefinitionsDownloadFailed(QNetworkReply::UnknownContentError); emit sigBracketDefinitionsDownloadFailed(QNetworkReply::UnknownContentError);
reply->deleteLater();
return; return;
} }
// Validate the complete replacement before touching the last usable definitions.
// Tags are QSettings group names, so path separators must not create nested groups.
QSet<QString> tags;
for (const auto &value : document.object().value("brackets").toArray()) {
const auto definition = value.toObject();
const auto tag = definition.value("tag").toString();
if (!value.isObject() || tag.trimmed().isEmpty() || tag.contains('/') || tag.contains('\\') ||
tags.contains(tag) || definition.value("officialName").toString().trimmed().isEmpty() ||
definition.value("displayName").toString().trimmed().isEmpty() ||
!definition.value("explanation").isString()) {
emit sigBracketDefinitionsDownloadFailed(QNetworkReply::UnknownContentError);
return;
}
tags.insert(tag);
}
updateBracketDefinitions(document.toVariant().toMap()); updateBracketDefinitions(document.toVariant().toMap());
emit sigBracketDefinitionsDownloaded(); emit sigBracketDefinitionsDownloaded();
reply->deleteLater();
} }
void HandleCommanderBrackets::updateBracketDefinitions(const QVariantMap &jsonMap) void HandleCommanderBrackets::updateBracketDefinitions(const QVariantMap &jsonMap)

View file

@ -3,6 +3,7 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QObject> #include <QObject>
#include <QPointer>
#include <QVariantMap> #include <QVariantMap>
#include <qtmetamacros.h> #include <qtmetamacros.h>
@ -14,6 +15,7 @@ class HandleCommanderBrackets : public QObject
public: public:
explicit HandleCommanderBrackets(QObject *parent = nullptr); explicit HandleCommanderBrackets(QObject *parent = nullptr);
~HandleCommanderBrackets() override;
void downloadBracketDefinitions(); void downloadBracketDefinitions();
@ -28,7 +30,7 @@ private:
void updateBracketDefinitions(const QVariantMap &jsonMap); void updateBracketDefinitions(const QVariantMap &jsonMap);
QNetworkAccessManager *nam; QNetworkAccessManager *nam;
QNetworkReply *reply; QPointer<QNetworkReply> reply;
}; };
#endif // COCKATRICE_HANDLE_COMMANDER_BRACKETS_H #endif // COCKATRICE_HANDLE_COMMANDER_BRACKETS_H