mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-10 20:13:24 -08:00
api.scryfall.com rejects requests that lack an Accept header with HTTP 400, and QNetworkAccessManager does not add one. Send application/json for the bulk metadata request and */* for the tag file, and surface the URL plus Scryfall's JSON error body when a request fails. A failed tag load used to call next(), which re-ran validatePage() and started the same failing download again, trapping the user in an error loop. Stay on the page instead, drop the unusable database, and tell the user they can retry, change the source, or untick the option to import without tags. Also explain parent tags inline with a real Scryfall hierarchy example.
250 lines
6.3 KiB
C++
250 lines
6.3 KiB
C++
#ifndef COCKATRICE_PAGES_H
|
|
#define COCKATRICE_PAGES_H
|
|
|
|
#include "pagetemplates.h"
|
|
|
|
#include <QByteArray>
|
|
#include <QFuture>
|
|
#include <QFutureWatcher>
|
|
#include <QPointer>
|
|
#include <QString>
|
|
#include <QStringList>
|
|
#include <QtGlobal>
|
|
#include <memory>
|
|
#include <qtmetamacros.h>
|
|
|
|
class QCheckBox;
|
|
class QComboBox;
|
|
class QLabel;
|
|
class QLineEdit;
|
|
class QNetworkReply;
|
|
class QRadioButton;
|
|
class QProgressBar;
|
|
class QTextEdit;
|
|
class QPushButton;
|
|
class QUrl;
|
|
class QWidget;
|
|
class TagDatabase;
|
|
|
|
class IntroPage : public OracleWizardPage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit IntroPage(QWidget *parent = nullptr);
|
|
void retranslateUi() override;
|
|
|
|
private:
|
|
QStringList findQmFiles();
|
|
|
|
private:
|
|
QLabel *label, *languageLabel, *versionLabel;
|
|
QComboBox *languageBox;
|
|
|
|
private slots:
|
|
void languageBoxChanged(int index);
|
|
|
|
protected slots:
|
|
void initializePage() override;
|
|
};
|
|
|
|
class OutroPage : public OracleWizardPage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit OutroPage(QWidget * = nullptr)
|
|
{
|
|
}
|
|
void retranslateUi() override;
|
|
|
|
protected:
|
|
void initializePage() override;
|
|
};
|
|
|
|
/** @brief Result of a worker-thread sets-file load (read + decompress + dispatch). */
|
|
struct LoadSetsResult
|
|
{
|
|
bool ok = false; ///< JSON scan produced set data (or plain XML was handled)
|
|
bool plainXml = false; ///< input was a plain Cockatrice XML database
|
|
QByteArray xmlData; ///< raw XML for the plain-XML path
|
|
QString errorMessage; ///< set when the input could not be processed
|
|
bool offerUncompressedFallback = false; ///< decompression-only failure: offer the uncompressed URL
|
|
};
|
|
|
|
class LoadSetsPage : public OracleWizardPage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit LoadSetsPage(QWidget *parent = nullptr);
|
|
void retranslateUi() override;
|
|
bool isComplete() const override;
|
|
|
|
protected:
|
|
void initializePage() override;
|
|
bool validatePage() override;
|
|
void readSetsFromByteArray(QByteArray _data);
|
|
void readSetsFromFile(const QString &fileName);
|
|
void downloadSetsFile(const QUrl &url);
|
|
void cancelWork() override;
|
|
|
|
private:
|
|
QRadioButton *urlRadioButton;
|
|
QRadioButton *fileRadioButton;
|
|
QLineEdit *urlLineEdit;
|
|
QLineEdit *fileLineEdit;
|
|
QPushButton *urlButton;
|
|
QPushButton *fileButton;
|
|
QLabel *progressLabel;
|
|
QProgressBar *progressBar;
|
|
|
|
QFutureWatcher<LoadSetsResult> watcher;
|
|
QFuture<LoadSetsResult> future;
|
|
bool loadActive = false;
|
|
|
|
void beginLoadSets(bool compressedFile = false);
|
|
|
|
private slots:
|
|
void actLoadSetsFile();
|
|
void actRestoreDefaultUrl();
|
|
void actDownloadProgressSetsFile(qint64 received, qint64 total);
|
|
void actDownloadFinishedSetsFile();
|
|
void updateParsingProgress(int bytesRead, int totalBytes);
|
|
void scanProgressToStdout(int bytesRead, int totalBytes);
|
|
void importFinished();
|
|
void zipDownloadFailed(const QString &message);
|
|
};
|
|
|
|
/**
|
|
* @brief Optional wizard step that loads the tag database used by the importer.
|
|
*
|
|
* Reloading is skipped when the source and parent-tag setting are unchanged, so
|
|
* going back and forth through the wizard does not re-download the tag data.
|
|
*/
|
|
class TagsPage : public OracleWizardPage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit TagsPage(QWidget *parent = nullptr);
|
|
void retranslateUi() override;
|
|
bool isComplete() const override;
|
|
|
|
protected:
|
|
void initializePage() override;
|
|
bool validatePage() override;
|
|
void cancelWork() override;
|
|
|
|
private:
|
|
struct LoadResult
|
|
{
|
|
std::shared_ptr<TagDatabase> database;
|
|
QString errorMessage;
|
|
};
|
|
|
|
QCheckBox *enableCheckBox;
|
|
QRadioButton *urlRadioButton;
|
|
QRadioButton *fileRadioButton;
|
|
QLineEdit *urlLineEdit;
|
|
QLineEdit *fileLineEdit;
|
|
QPushButton *urlButton;
|
|
QPushButton *fileButton;
|
|
QCheckBox *parentsCheckBox;
|
|
QLabel *parentsExplainer;
|
|
QLabel *statusLabel;
|
|
QLabel *progressLabel;
|
|
QProgressBar *progressBar;
|
|
|
|
QFutureWatcher<LoadResult> watcher;
|
|
QFuture<LoadResult> future;
|
|
QPointer<QNetworkReply> activeReply;
|
|
bool loadActive = false;
|
|
QString loadedSource;
|
|
bool loadedParents = false;
|
|
|
|
[[nodiscard]] QString selectedSource() const;
|
|
void updateSourceEnabled();
|
|
void saveSettings();
|
|
void beginLoad(const QByteArray &data);
|
|
void loadFromFile(const QString &path);
|
|
void downloadMetadata(const QUrl &url);
|
|
void downloadTagFile(const QUrl &url);
|
|
void finishLoad();
|
|
void failLoad(const QString &message);
|
|
void advance();
|
|
|
|
private slots:
|
|
void actChooseFile();
|
|
void actRestoreDefaultSource();
|
|
void actDownloadProgress(qint64 received, qint64 total);
|
|
void actMetadataFinished();
|
|
void actTagFileFinished();
|
|
void actLoadFinished();
|
|
};
|
|
|
|
class SaveSetsPage : public OracleWizardPage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit SaveSetsPage(QWidget *parent = nullptr);
|
|
void retranslateUi() override;
|
|
bool isComplete() const override;
|
|
|
|
private:
|
|
QTextEdit *messageLog;
|
|
QProgressBar *progressBar;
|
|
QCheckBox *defaultPathCheckBox;
|
|
QLabel *pathLabel;
|
|
QLabel *saveLabel;
|
|
|
|
QFutureWatcher<int> importWatcher;
|
|
QFuture<int> importFuture;
|
|
int totalSets = 0;
|
|
bool importActive = false;
|
|
|
|
protected:
|
|
void initializePage() override;
|
|
void cleanupPage() override;
|
|
bool validatePage() override;
|
|
void cancelWork() override;
|
|
|
|
private slots:
|
|
void importFinished();
|
|
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName);
|
|
};
|
|
|
|
class LoadSpoilersPage : public SimpleDownloadFilePage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit LoadSpoilersPage(QWidget * = nullptr)
|
|
{
|
|
}
|
|
void retranslateUi() override;
|
|
|
|
protected:
|
|
QString getDefaultUrl() override;
|
|
QString getCustomUrlSettingsKey() override;
|
|
QString getDefaultSavePath() override;
|
|
QString getWindowTitle() override;
|
|
QString getFileType() override;
|
|
QString getFilePromptName() override;
|
|
};
|
|
|
|
class LoadTokensPage : public SimpleDownloadFilePage
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit LoadTokensPage(QWidget * = nullptr)
|
|
{
|
|
}
|
|
void retranslateUi() override;
|
|
|
|
protected:
|
|
QString getDefaultUrl() override;
|
|
QString getCustomUrlSettingsKey() override;
|
|
QString getDefaultSavePath() override;
|
|
QString getWindowTitle() override;
|
|
QString getFileType() override;
|
|
QString getFilePromptName() override;
|
|
void initializePage() override;
|
|
};
|
|
|
|
#endif // COCKATRICE_PAGES_H
|