diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp
index 0182f7c5..b4f90662 100644
--- a/cockatrice/src/dlg_settings.cpp
+++ b/cockatrice/src/dlg_settings.cpp
@@ -3,6 +3,7 @@
#include "carddatabase.h"
#include "gettextwithmax.h"
#include "main.h"
+#include "pictureloader.h"
#include "releasechannel.h"
#include "sequenceEdit/sequenceedit.h"
#include "settingscache.h"
@@ -68,18 +69,9 @@ GeneralSettingsPage::GeneralSettingsPage()
updateNotificationCheckBox.setChecked(settings.getNotifyAboutUpdates());
newVersionOracleCheckBox.setChecked(settings.getNotifyAboutNewVersion());
- // pixmap cache
- pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
- // 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size)
- pixmapCacheEdit.setMaximum(PIXMAPCACHE_SIZE_MAX);
- pixmapCacheEdit.setSingleStep(64);
- pixmapCacheEdit.setValue(settings.getPixmapCacheSize());
- pixmapCacheEdit.setSuffix(" MB");
-
showTipsOnStartup.setChecked(settings.getShowTipsOnStartup());
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
- connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &settings, SLOT(setPixmapCacheSize(int)));
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), &settings, SLOT(setUpdateReleaseChannel(int)));
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutUpdate(int)));
connect(&newVersionOracleCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutNewVersion(int)));
@@ -90,8 +82,6 @@ GeneralSettingsPage::GeneralSettingsPage()
personalGrid->addWidget(&languageBox, 0, 1);
personalGrid->addWidget(&updateReleaseChannelLabel, 1, 0);
personalGrid->addWidget(&updateReleaseChannelBox, 1, 1);
- personalGrid->addWidget(&pixmapCacheLabel, 2, 0);
- personalGrid->addWidget(&pixmapCacheEdit, 2, 1);
personalGrid->addWidget(&updateNotificationCheckBox, 3, 0, 1, 2);
personalGrid->addWidget(&newVersionOracleCheckBox, 4, 0, 1, 2);
personalGrid->addWidget(&showTipsOnStartup, 5, 0, 1, 2);
@@ -301,7 +291,6 @@ void GeneralSettingsPage::retranslateUi()
cardDatabasePathLabel.setText(tr("Card database:"));
customCardDatabasePathLabel.setText(tr("Custom database directory:"));
tokenDatabasePathLabel.setText(tr("Token database:"));
- pixmapCacheLabel.setText(tr("Picture cache size:"));
updateReleaseChannelLabel.setText(tr("Update channel"));
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
@@ -591,12 +580,38 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
messageListLayout->addWidget(messageToolBar);
messageListLayout->addWidget(urlList);
+ // pixmap cache
+ pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
+ // 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size)
+ pixmapCacheEdit.setMaximum(PIXMAPCACHE_SIZE_MAX);
+ pixmapCacheEdit.setSingleStep(64);
+ pixmapCacheEdit.setValue(SettingsCache::instance().getPixmapCacheSize());
+ pixmapCacheEdit.setSuffix(" MB");
+
+ networkCacheEdit.setMinimum(NETWORK_CACHE_SIZE_MIN);
+ networkCacheEdit.setMaximum(NETWORK_CACHE_SIZE_MAX);
+ networkCacheEdit.setSingleStep(1);
+ networkCacheEdit.setValue(SettingsCache::instance().getNetworkCacheSizeInMB());
+ networkCacheEdit.setSuffix(tr(" MB"));
+
+ auto networkCacheLayout = new QHBoxLayout;
+ networkCacheLayout->addStretch();
+ networkCacheLayout->addWidget(&networkCacheLabel);
+ networkCacheLayout->addWidget(&networkCacheEdit);
+
+ auto pixmapCacheLayout = new QHBoxLayout;
+ pixmapCacheLayout->addStretch();
+ pixmapCacheLayout->addWidget(&pixmapCacheLabel);
+ pixmapCacheLayout->addWidget(&pixmapCacheEdit);
+
// Top Layout
lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0);
lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1);
lpGeneralGrid->addLayout(messageListLayout, 1, 0, 1, 2);
- lpGeneralGrid->addWidget(&urlLinkLabel, 2, 0);
- lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 2, 1);
+ lpGeneralGrid->addLayout(networkCacheLayout, 2, 0, 1, 2);
+ lpGeneralGrid->addLayout(pixmapCacheLayout, 3, 0, 1, 2);
+ lpGeneralGrid->addWidget(&urlLinkLabel, 4, 0);
+ lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 4, 1);
// Spoiler Layout
lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0);
@@ -611,6 +626,9 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), &SettingsCache::instance(),
SLOT(setDownloadSpoilerStatus(bool)));
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSpoilersEnabled(bool)));
+ connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(), SLOT(setPixmapCacheSize(int)));
+ connect(&networkCacheEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(),
+ SLOT(setNetworkCacheSizeInMB(int)));
mpGeneralGroupBox = new QGroupBox;
mpGeneralGroupBox->setLayout(lpGeneralGrid);
@@ -635,6 +653,11 @@ void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked()
void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
{
+ PictureLoader::clearNetworkCache();
+
+ // These are not used anymore, but we don't delete them automatically, so
+ // we should do it here lest we leave pictures hanging around on users'
+ // machines.
QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics/";
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
bool outerSuccessRemove = true;
@@ -662,6 +685,7 @@ void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
}
if (outerSuccessRemove) {
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
+ QDir(SettingsCache::instance().getPicsPath()).rmdir("downloadedPics");
} else {
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
}
@@ -785,6 +809,10 @@ void DeckEditorSettingsPage::retranslateUi()
urlLinkLabel.setText(QString("%2").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL")));
clearDownloadedPicsButton.setText(tr("Delete Downloaded Images"));
resetDownloadURLs.setText(tr("Reset Download URLs"));
+ networkCacheLabel.setText(tr("Downloaded images directory size:"));
+ networkCacheEdit.setToolTip(tr("On-disk cache for downloaded pictures"));
+ pixmapCacheLabel.setText(tr("Picture cache size:"));
+ pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen"));
}
MessagesSettingsPage::MessagesSettingsPage()
diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h
index 416def89..d6dd1718 100644
--- a/cockatrice/src/dlg_settings.h
+++ b/cockatrice/src/dlg_settings.h
@@ -58,7 +58,6 @@ private:
QLineEdit *tokenDatabasePathEdit;
QPushButton *resetAllPathsButton;
QLabel *allPathsResetLabel;
- QSpinBox pixmapCacheEdit;
QGroupBox *personalGroupBox;
QGroupBox *pathsGroupBox;
QComboBox languageBox;
@@ -66,7 +65,6 @@ private:
QCheckBox newVersionOracleCheckBox;
QComboBox updateReleaseChannelBox;
QLabel languageLabel;
- QLabel pixmapCacheLabel;
QLabel deckPathLabel;
QLabel replaysPathLabel;
QLabel picsPathLabel;
@@ -168,6 +166,10 @@ private:
QLabel infoOnSpoilersLabel;
QPushButton *mpSpoilerPathButton;
QPushButton *updateNowButton;
+ QLabel networkCacheLabel;
+ QSpinBox networkCacheEdit;
+ QSpinBox pixmapCacheEdit;
+ QLabel pixmapCacheLabel;
};
class MessagesSettingsPage : public AbstractSettingsPage
diff --git a/cockatrice/src/pictureloader.cpp b/cockatrice/src/pictureloader.cpp
index 966e9c30..4ca0d528 100644
--- a/cockatrice/src/pictureloader.cpp
+++ b/cockatrice/src/pictureloader.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -116,6 +117,21 @@ PictureLoaderWorker::PictureLoaderWorker()
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
networkManager = new QNetworkAccessManager(this);
+ // We need a timeout to ensure requests don't hang indefinitely in case of
+ // cache corruption, see related Qt bug: https://bugreports.qt.io/browse/QTBUG-111397
+ // Use Qt's default timeout (30s, as of 2023-02-22)
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ networkManager->setTransferTimeout();
+#endif
+ auto cache = new QNetworkDiskCache(this);
+ cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
+ // Note: the settings is in MB, but QNetworkDiskCache uses bytes
+ connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, cache,
+ [cache](int newSizeInMB) { cache->setMaximumCacheSize(1024L * 1024L * static_cast(newSizeInMB)); });
+ networkManager->setCache(cache);
+ // Use a ManualRedirectPolicy since we keep track of redirects in picDownloadFinished
+ // We can't use NoLessSafeRedirectPolicy because it is not applied with AlwaysCache
+ networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
pictureLoaderThread = new QThread;
@@ -149,37 +165,19 @@ void PictureLoaderWorker::processLoadQueue()
QString cardName = cardBeingLoaded.getCard()->getName();
QString correctedCardName = cardBeingLoaded.getCard()->getCorrectedName();
- qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Trying to load picture";
+ qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
+ << "]: Trying to load picture";
if (cardImageExistsOnDisk(setName, correctedCardName)) {
continue;
}
- if (picDownload) {
- qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
- << "]: Picture not found on disk, trying to download";
- cardsToDownload.append(cardBeingLoaded);
- cardBeingLoaded.clear();
- if (!downloadRunning) {
- startNextPicDownload();
- }
- } else {
- if (cardBeingLoaded.nextSet()) {
- qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
- << "]: Picture NOT found and download disabled, moving to next "
- "set (new set: "
- << setName << " card: " << cardName << ")";
- mutex.lock();
- loadQueue.prepend(cardBeingLoaded);
- cardBeingLoaded.clear();
- mutex.unlock();
- } else {
- qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
- << "]: Picture NOT found, download disabled, no more sets to "
- "try: BAILING OUT (old set: "
- << setName << " card: " << cardName << ")";
- imageLoaded(cardBeingLoaded.getCard(), QImage());
- }
+ qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
+ << "]: No custom picture, trying to download";
+ cardsToDownload.append(cardBeingLoaded);
+ cardBeingLoaded.clear();
+ if (!downloadRunning) {
+ startNextPicDownload();
}
}
}
@@ -206,6 +204,8 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
if (!setName.isEmpty()) {
picsPaths << picsPath + "/" + setName + "/" + correctedCardname
+ // We no longer store downloaded images there, but don't just ignore
+ // stuff that old versions have put there.
<< picsPath + "/downloadedPics/" + setName + "/" + correctedCardname;
}
@@ -215,22 +215,22 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
for (const auto &picsPath : picsPaths) {
imgReader.setFileName(picsPath);
if (imgReader.read(&image)) {
- qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
- << "]: Picture found on disk.";
+ qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
+ << "]: Picture found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image);
return true;
}
imgReader.setFileName(picsPath + ".full");
if (imgReader.read(&image)) {
- qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
- << "]: Picture.full found on disk.";
+ qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
+ << "]: Picture.full found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image);
return true;
}
imgReader.setFileName(picsPath + ".xlhq");
if (imgReader.read(&image)) {
- qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
- << "]: Picture.xlhq found on disk.";
+ qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
+ << "]: Picture.xlhq found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image);
return true;
}
@@ -385,11 +385,10 @@ void PictureLoaderWorker::startNextPicDownload()
picDownloadFailed();
} else {
QUrl url(picUrl);
- QNetworkRequest req(url);
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
- << " set: " << cardBeingDownloaded.getSetName()
- << "]: Trying to download picture from url:" << url.toDisplayString();
- networkManager->get(req);
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
+ << " set: " << cardBeingDownloaded.getSetName() << "]: Trying to fetch picture from url "
+ << url.toDisplayString();
+ makeRequest(url);
}
}
@@ -404,10 +403,10 @@ void PictureLoaderWorker::picDownloadFailed()
loadQueue.prepend(cardBeingDownloaded);
mutex.unlock();
} else {
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
- << " set: " << cardBeingDownloaded.getSetName()
- << "]: Picture NOT found, download failed, no more url combinations "
- "to try: BAILING OUT";
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
+ << " set: " << cardBeingDownloaded.getSetName() << "]: Picture NOT found, "
+ << (picDownload ? "download failed" : "downloads disabled")
+ << ", no more url combinations to try: BAILING OUT";
imageLoaded(cardBeingDownloaded.getCard(), QImage());
cardBeingDownloaded.clear();
}
@@ -420,20 +419,53 @@ bool PictureLoaderWorker::imageIsBlackListed(const QByteArray &picData)
return md5Blacklist.contains(md5sum);
}
+QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url)
+{
+ QNetworkRequest req(url);
+ if (!picDownload) {
+ req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
+ }
+ return networkManager->get(req);
+}
+
void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
{
+ bool isFromCache = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
+
if (reply->error()) {
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
- << " set: " << cardBeingDownloaded.getSetName() << "]: Download failed:" << reply->errorString();
+ if (isFromCache) {
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
+ << " set: " << cardBeingDownloaded.getSetName()
+ << "]: Removing corrupted cache file for url " << reply->url().toDisplayString()
+ << " and retrying (" << reply->errorString() << ")";
+
+ networkManager->cache()->remove(reply->url());
+
+ makeRequest(reply->url());
+ } else {
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
+ << " set: " << cardBeingDownloaded.getSetName()
+ << "]: " << (picDownload ? "Download" : "Cache search") << " failed for url "
+ << reply->url().toDisplayString() << " (" << reply->errorString() << ")";
+
+ picDownloadFailed();
+ startNextPicDownload();
+ }
+
+ reply->deleteLater();
+ return;
}
+ // List of status codes from https://doc.qt.io/qt-6/qnetworkreply.html#redirected
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- if (statusCode == 301 || statusCode == 302) {
- QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
- QNetworkRequest req(redirectUrl);
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
- << " set: " << cardBeingDownloaded.getSetName() << "]: following redirect:" << req.url().toString();
- networkManager->get(req);
+ if (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 ||
+ statusCode == 308) {
+ QUrl redirectUrl = reply->header(QNetworkRequest::LocationHeader).toUrl();
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
+ << " set: " << cardBeingDownloaded.getSetName() << "]: following "
+ << (isFromCache ? "cached redirect" : "redirect") << " to " << redirectUrl.toDisplayString();
+ makeRequest(redirectUrl);
+ reply->deleteLater();
return;
}
@@ -441,10 +473,10 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
const QByteArray &picData = reply->peek(reply->size());
if (imageIsBlackListed(picData)) {
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
- << " set: " << cardBeingDownloaded.getSetName()
- << "]:Picture downloaded, but blacklisted, will consider it as "
- "not found";
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
+ << " set: " << cardBeingDownloaded.getSetName()
+ << "]: Picture found, but blacklisted, will consider it as not found";
+
picDownloadFailed();
reply->deleteLater();
startNextPicDownload();
@@ -456,40 +488,19 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
imgReader.setDevice(reply);
- // the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the
- // QImageReader buffer
- QString extension = "." + imgReader.format();
- if (extension == ".jpeg") {
- extension = ".jpg";
- }
if (imgReader.read(&testImage)) {
- QString setName = cardBeingDownloaded.getSetName();
- if (!setName.isEmpty()) {
- if (!QDir().mkpath(picsPath + "/downloadedPics/" + setName)) {
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
- << " set: " << cardBeingDownloaded.getSetName()
- << "]: " << picsPath + "/downloadedPics/" + setName + " could not be created.";
- return;
- }
-
- QFile newPic(picsPath + "/downloadedPics/" + setName + "/" +
- cardBeingDownloaded.getCard()->getCorrectedName() + extension);
- if (!newPic.open(QIODevice::WriteOnly)) {
- return;
- }
- newPic.write(picData);
- newPic.close();
- }
-
imageLoaded(cardBeingDownloaded.getCard(), testImage);
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
- << " set: " << cardBeingDownloaded.getSetName() << "]: Image successfully downloaded from "
- << reply->request().url().toDisplayString();
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
+ << " set: " << cardBeingDownloaded.getSetName() << "]: Image successfully "
+ << (isFromCache ? "loaded from cached" : "downloaded from") << " url "
+ << reply->url().toDisplayString();
} else {
- qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
- << " set: " << cardBeingDownloaded.getSetName() << "]: Possible picture at "
- << reply->request().url().toDisplayString() << " could not be loaded";
+ qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
+ << " set: " << cardBeingDownloaded.getSetName() << "]: Possible "
+ << (isFromCache ? "cached" : "downloaded") << " picture at "
+ << reply->url().toDisplayString() << " could not be loaded";
+
picDownloadFailed();
}
@@ -533,6 +544,11 @@ void PictureLoaderWorker::picsPathChanged()
customPicsPath = SettingsCache::instance().getCustomPicsPath();
}
+void PictureLoaderWorker::clearNetworkCache()
+{
+ networkManager->cache()->clear();
+}
+
PictureLoader::PictureLoader() : QObject(nullptr)
{
worker = new PictureLoaderWorker;
@@ -613,6 +629,11 @@ void PictureLoader::clearPixmapCache()
QPixmapCache::clear();
}
+void PictureLoader::clearNetworkCache()
+{
+ getInstance().worker->clearNetworkCache();
+}
+
void PictureLoader::cacheCardPixmaps(QList cards)
{
QPixmap tmp;
diff --git a/cockatrice/src/pictureloader.h b/cockatrice/src/pictureloader.h
index f085ecde..65eafaea 100644
--- a/cockatrice/src/pictureloader.h
+++ b/cockatrice/src/pictureloader.h
@@ -73,6 +73,7 @@ public:
~PictureLoaderWorker() override;
void enqueueImageLoad(CardInfoPtr card);
+ void clearNetworkCache();
private:
static QStringList md5Blacklist;
@@ -87,8 +88,9 @@ private:
PictureToLoad cardBeingDownloaded;
bool picDownload, downloadRunning, loadQueueRunning;
void startNextPicDownload();
- bool cardImageExistsOnDisk(QString &, QString &);
+ bool cardImageExistsOnDisk(QString &setName, QString &correctedCardName);
bool imageIsBlackListed(const QByteArray &);
+ QNetworkReply *makeRequest(const QUrl &url);
private slots:
void picDownloadFinished(QNetworkReply *reply);
void picDownloadFailed();
@@ -97,6 +99,7 @@ private slots:
void picsPathChanged();
public slots:
void processLoadQueue();
+
signals:
void startLoadQueue();
void imageLoaded(CardInfoPtr card, const QImage &image);
@@ -127,9 +130,14 @@ public:
static void clearPixmapCache(CardInfoPtr card);
static void clearPixmapCache();
static void cacheCardPixmaps(QList cards);
+
+public slots:
+ static void clearNetworkCache();
+
private slots:
void picDownloadChanged();
void picsPathChanged();
+
public slots:
void imageLoaded(CardInfoPtr card, const QImage &image);
};
diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp
index 8e95fe4b..696cc7b7 100644
--- a/cockatrice/src/settingscache.cpp
+++ b/cockatrice/src/settingscache.cpp
@@ -26,6 +26,19 @@ QString SettingsCache::getSettingsPath()
return getDataPath() + "/settings/";
}
+QString SettingsCache::getCachePath() const
+{
+ if (isPortableBuild)
+ return qApp->applicationDirPath() + "/cache";
+ else
+ return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+}
+
+QString SettingsCache::getNetworkCachePath() const
+{
+ return getCachePath() + "/downloaded/";
+}
+
void SettingsCache::translateLegacySettings()
{
if (isPortableBuild)
@@ -206,6 +219,8 @@ SettingsCache::SettingsCache()
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX)
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
+ networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
+
picDownload = settings->value("personal/picturedownload", true).toBool();
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
@@ -609,6 +624,13 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
emit pixmapCacheSizeChanged(pixmapCacheSize);
}
+void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
+{
+ networkCacheSize = _networkCacheSize;
+ settings->setValue("personal/networkCacheSize", networkCacheSize);
+ emit networkCacheSizeChanged(networkCacheSize);
+}
+
void SettingsCache::setClientID(const QString &_clientID)
{
clientID = _clientID;
diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h
index a12a1023..01d6aafc 100644
--- a/cockatrice/src/settingscache.h
+++ b/cockatrice/src/settingscache.h
@@ -20,6 +20,11 @@ class ReleaseChannel;
#define PIXMAPCACHE_SIZE_MIN 64
#define PIXMAPCACHE_SIZE_MAX 2047
+// In MB
+constexpr int NETWORK_CACHE_SIZE_DEFAULT = 1024 * 4; // 4 GB
+constexpr int NETWORK_CACHE_SIZE_MIN = 1; // 1 MB
+constexpr int NETWORK_CACHE_SIZE_MAX = 1024 * 1024; // 1 TB
+
#define DEFAULT_LANG_NAME "English"
#define CLIENT_INFO_NOT_SET "notset"
@@ -46,6 +51,7 @@ signals:
void ignoreUnregisteredUsersChanged();
void ignoreUnregisteredUserMessagesChanged();
void pixmapCacheSizeChanged(int newSizeInMBs);
+ void networkCacheSizeChanged(int newSizeInMBs);
void masterVolumeChanged(int value);
void chatMentionCompleterChanged();
void downloadSpoilerTimeIndexChanged();
@@ -106,6 +112,7 @@ private:
QString knownMissingFeatures;
bool useTearOffMenus;
int pixmapCacheSize;
+ int networkCacheSize;
bool scaleCards;
bool showMessagePopups;
bool showMentionPopups;
@@ -137,6 +144,8 @@ public:
SettingsCache();
QString getDataPath();
QString getSettingsPath();
+ QString getCachePath() const;
+ QString getNetworkCachePath() const;
const QByteArray &getMainWindowGeometry() const
{
return mainWindowGeometry;
@@ -330,6 +339,10 @@ public:
{
return pixmapCacheSize;
}
+ int getNetworkCacheSizeInMB() const
+ {
+ return networkCacheSize;
+ }
bool getScaleCards() const
{
return scaleCards;
@@ -520,6 +533,7 @@ public slots:
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
void setPixmapCacheSize(const int _pixmapCacheSize);
+ void setNetworkCacheSizeInMB(const int _networkCacheSize);
void setCardScaling(const int _scaleCards);
void setShowMessagePopups(const int _showMessagePopups);
void setShowMentionPopups(const int _showMentionPopups);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 999da190..867a406c 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -202,6 +202,9 @@ void SettingsCache::setTokenDialogGeometry(const QByteArray & /* _tokenDialogGeo
void SettingsCache::setPixmapCacheSize(const int /* _pixmapCacheSize */)
{
}
+void SettingsCache::setNetworkCacheSizeInMB(const int /* _networkCacheSize */)
+{
+}
void SettingsCache::setClientID(const QString & /* _clientID */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index c780574f..b78a17b3 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -206,6 +206,9 @@ void SettingsCache::setTokenDialogGeometry(const QByteArray & /* _tokenDialogGeo
void SettingsCache::setPixmapCacheSize(const int /* _pixmapCacheSize */)
{
}
+void SettingsCache::setNetworkCacheSizeInMB(const int /* _networkCacheSize */)
+{
+}
void SettingsCache::setClientID(const QString & /* _clientID */)
{
}