From 64885f4c20c5a4da03c3314942211f34608b800d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Sun, 22 Feb 2026 10:44:34 +0100 Subject: [PATCH 1/9] [PictureLoader] Allow saving downloaded images to local storage and not just the QNetworkManager cache. Took 1 hour 11 minutes Took 4 seconds Took 25 seconds --- .../src/client/settings/cache_settings.cpp | 17 ++++ .../src/client/settings/cache_settings.h | 14 ++++ .../card_picture_loader.cpp | 82 ++++++++++++++++++- .../card_picture_loader/card_picture_loader.h | 1 + .../widgets/dialogs/dlg_settings.cpp | 25 +++++- .../interface/widgets/dialogs/dlg_settings.h | 4 + 6 files changed, 138 insertions(+), 5 deletions(-) diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp index a66897b4a..8f96efd7b 100644 --- a/cockatrice/src/client/settings/cache_settings.cpp +++ b/cockatrice/src/client/settings/cache_settings.cpp @@ -264,6 +264,9 @@ SettingsCache::SettingsCache() networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt(); redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt(); + saveCardImagesToLocalStorage = settings->value("personal/saveCardImagesToLocalStorage", true).toBool(); + localCardImageStorageNamingScheme = + settings->value("personal/localCardImageStorageNamingScheme", "{set}/{name}_{collector}_{uuid}.png").toString(); picDownload = settings->value("personal/picturedownload", true).toBool(); showStatusBar = settings->value("personal/showStatusBar", false).toBool(); @@ -1111,6 +1114,20 @@ void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl) emit redirectCacheTtlChanged(redirectCacheTtl); } +void SettingsCache::setSaveCardImagesToLocalStorage(QT_STATE_CHANGED_T _saveCardImagesToLocalStorage) +{ + saveCardImagesToLocalStorage = _saveCardImagesToLocalStorage; + settings->setValue("personal/saveCardImagesToLocalStorage", saveCardImagesToLocalStorage); + emit saveCardImagesToLocalStorageChanged(saveCardImagesToLocalStorage); +} + +void SettingsCache::setLocalCardImageStorageNamingScheme(const QString _localCardImageStorageNamingScheme) +{ + localCardImageStorageNamingScheme = _localCardImageStorageNamingScheme; + settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme); + emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme); +} + void SettingsCache::setClientID(const QString &_clientID) { clientID = _clientID; diff --git a/cockatrice/src/client/settings/cache_settings.h b/cockatrice/src/client/settings/cache_settings.h index ece61487f..e5fa3d3fc 100644 --- a/cockatrice/src/client/settings/cache_settings.h +++ b/cockatrice/src/client/settings/cache_settings.h @@ -184,6 +184,8 @@ signals: void pixmapCacheSizeChanged(int newSizeInMBs); void networkCacheSizeChanged(int newSizeInMBs); void redirectCacheTtlChanged(int newTtl); + void saveCardImagesToLocalStorageChanged(bool saveCardImagesToLocalStorage); + void localCardImageStorageNamingSchemeChanged(QString localCardImageStorageNamingScheme); void masterVolumeChanged(int value); void chatMentionCompleterChanged(); void downloadSpoilerTimeIndexChanged(); @@ -302,6 +304,8 @@ private: int pixmapCacheSize; int networkCacheSize; int redirectCacheTtl; + bool saveCardImagesToLocalStorage; + QString localCardImageStorageNamingScheme; bool scaleCards; int verticalCardOverlapPercent; bool showMessagePopups; @@ -789,6 +793,14 @@ public: { return redirectCacheTtl; } + [[nodiscard]] bool getSaveCardImagesToLocalStorage() const + { + return saveCardImagesToLocalStorage; + } + [[nodiscard]] QString getLocalCardImageStorageNamingScheme() const + { + return localCardImageStorageNamingScheme; + } [[nodiscard]] bool getScaleCards() const { return scaleCards; @@ -1095,6 +1107,8 @@ public slots: void setPixmapCacheSize(const int _pixmapCacheSize); void setNetworkCacheSizeInMB(const int _networkCacheSize); void setNetworkRedirectCacheTtl(const int _redirectCacheTtl); + void setSaveCardImagesToLocalStorage(QT_STATE_CHANGED_T _saveCardImagesToLocalStorage); + void setLocalCardImageStorageNamingScheme(const QString _localCardImageStorageNamingScheme); void setCardScaling(const QT_STATE_CHANGED_T _scaleCards); void setStackCardOverlapPercent(const int _verticalCardOverlapPercent); void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp index dbd51b973..52109fa2e 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp @@ -150,9 +150,10 @@ void CardPictureLoader::getPixmap(QPixmap &pixmap, const ExactCard &card, QSize void CardPictureLoader::imageLoaded(const ExactCard &card, const QImage &image) { + QPixmap finalPixmap; + if (image.isNull()) { qCDebug(CardPictureLoaderLog) << "Caching NULL pixmap for" << card.getName(); - QPixmapCache::insert(card.getPixmapCacheKey(), QPixmap()); } else { if (card.getInfo().getUiAttributes().upsideDownArt) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)) @@ -160,12 +161,18 @@ void CardPictureLoader::imageLoaded(const ExactCard &card, const QImage &image) #else QImage mirrorImage = image.mirrored(true, true); #endif - QPixmapCache::insert(card.getPixmapCacheKey(), QPixmap::fromImage(mirrorImage)); + finalPixmap = QPixmap::fromImage(mirrorImage); } else { - QPixmapCache::insert(card.getPixmapCacheKey(), QPixmap::fromImage(image)); + finalPixmap = QPixmap::fromImage(image); } } + QPixmapCache::insert(card.getPixmapCacheKey(), finalPixmap); + + if (SettingsCache::instance().getSaveCardImagesToLocalStorage()) { + saveCardImageToLocalStorage(card, finalPixmap); + } + // imageLoaded should only be reached if the exactCard isn't already in cache. // (plus there's a deduplication mechanism in CardPictureLoaderWorker) // It should be safe to connect the CardInfo here without worrying about redundant connections. @@ -175,6 +182,75 @@ void CardPictureLoader::imageLoaded(const ExactCard &card, const QImage &image) card.emitPixmapUpdated(); } +void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card, const QPixmap &pixmap) +{ + if (pixmap.isNull() || !card) { + return; + } + + const QString picsRoot = SettingsCache::instance().getPicsPath(); + const QString scheme = SettingsCache::instance().getLocalCardImageStorageNamingScheme(); + + if (picsRoot.isEmpty() || scheme.isEmpty()) { + return; + } + + // Base directory: /downloadedPics + QDir baseDir(picsRoot); + if (!baseDir.exists("downloadedPics")) { + baseDir.mkpath("downloadedPics"); + } + baseDir.cd("downloadedPics"); + + // Collect card metadata + const QString cardName = card.getInfo().getCorrectedName(); + + QString setName; + QString collectorNumber; + QString uuid; + + PrintingInfo printing = card.getPrinting(); + if (printing.getSet()) { + setName = printing.getSet()->getCorrectedShortName(); + collectorNumber = printing.getProperty("num"); + uuid = printing.getUuid(); + } + + // Build path from scheme + QString relativePath = scheme; + + relativePath.replace("{name}", cardName); + relativePath.replace("{set}", setName); + relativePath.replace("{collector}", collectorNumber); + relativePath.replace("{uuid}", uuid); + relativePath.replace("{ext}", "png"); + + // Normalize slashes + relativePath = QDir::cleanPath(relativePath); + + QFileInfo outInfo(baseDir.filePath(relativePath)); + QDir outDir = outInfo.dir(); + + // Ensure directory exists + if (!outDir.exists()) { + if (!baseDir.mkpath(outDir.path())) { + qCWarning(CardPictureLoaderLog) << "Failed to create directory for downloaded card image:" << outDir.path(); + return; + } + } + + // Do not overwrite existing files + if (outInfo.exists()) { + return; + } + + // Save image + QImage image = pixmap.toImage(); + if (!image.save(outInfo.absoluteFilePath(), "PNG")) { + qCWarning(CardPictureLoaderLog) << "Failed to save card image to" << outInfo.absoluteFilePath(); + } +} + void CardPictureLoader::clearPixmapCache() { QPixmapCache::clear(); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h index 4000fd99a..0c114ae92 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h @@ -117,6 +117,7 @@ public slots: * @param image Loaded QImage. */ void imageLoaded(const ExactCard &card, const QImage &image); + void saveCardImageToLocalStorage(const ExactCard &card, const QPixmap &pixmap); private slots: /** diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 6238bc80b..6187d93d5 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1075,6 +1075,15 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() networkRedirectCacheTtlEdit.setSingleStep(1); networkRedirectCacheTtlEdit.setValue(SettingsCache::instance().getRedirectCacheTtl()); + saveCardImagesToLocalStorageCheckBox.setChecked(SettingsCache::instance().getSaveCardImagesToLocalStorage()); + connect(&saveCardImagesToLocalStorageCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), + &SettingsCache::setSaveCardImagesToLocalStorage); + + localCardImageStorageNamingSchemeLineEdit = + new QLineEdit(SettingsCache::instance().getLocalCardImageStorageNamingScheme()); + connect(localCardImageStorageNamingSchemeLineEdit, &QLineEdit::textChanged, &SettingsCache::instance(), + &SettingsCache::setLocalCardImageStorageNamingScheme); + auto networkCacheLayout = new QHBoxLayout; networkCacheLayout->addStretch(); networkCacheLayout->addWidget(&networkCacheLabel); @@ -1090,6 +1099,14 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() pixmapCacheLayout->addWidget(&pixmapCacheLabel); pixmapCacheLayout->addWidget(&pixmapCacheEdit); + auto saveCardImagesToLocalStorageLayout = new QHBoxLayout; + saveCardImagesToLocalStorageLayout->addWidget(&saveCardImagesToLocalStorageLabel); + saveCardImagesToLocalStorageLayout->addWidget(&saveCardImagesToLocalStorageCheckBox); + + auto localCardImageStorageNamingSchemeLayout = new QHBoxLayout; + localCardImageStorageNamingSchemeLayout->addWidget(&localCardImageStorageNamingSchemeLabel); + localCardImageStorageNamingSchemeLayout->addWidget(localCardImageStorageNamingSchemeLineEdit); + // Top Layout lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0); lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1); @@ -1097,8 +1114,10 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() lpGeneralGrid->addLayout(networkCacheLayout, 2, 1); lpGeneralGrid->addLayout(networkRedirectCacheLayout, 3, 0); lpGeneralGrid->addLayout(pixmapCacheLayout, 3, 1); - lpGeneralGrid->addWidget(&urlLinkLabel, 5, 0); - lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 5, 1); + lpGeneralGrid->addLayout(saveCardImagesToLocalStorageLayout, 4, 0, 1, 2); + lpGeneralGrid->addLayout(localCardImageStorageNamingSchemeLayout, 5, 0, 1, 2); + lpGeneralGrid->addWidget(&urlLinkLabel, 7, 0); + lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 7, 1); // Spoiler Layout lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0); @@ -1310,6 +1329,8 @@ void DeckEditorSettingsPage::retranslateUi() networkRedirectCacheTtlEdit.setToolTip(tr("How long cached redirects for urls are valid for.")); pixmapCacheLabel.setText(tr("Picture Cache Size:")); pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen")); + saveCardImagesToLocalStorageLabel.setText(tr("Save downloaded images to local storage")); + localCardImageStorageNamingSchemeLabel.setText(tr("Save downloaded images using this naming scheme:")); updateNowButton->setText(tr("Update Spoilers")); aAdd->setText(tr("Add New URL")); aEdit->setText(tr("Edit URL")); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index b655a30bc..a7608578a 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -239,6 +239,10 @@ private: QSpinBox networkRedirectCacheTtlEdit; QSpinBox pixmapCacheEdit; QLabel pixmapCacheLabel; + QCheckBox saveCardImagesToLocalStorageCheckBox; + QLabel saveCardImagesToLocalStorageLabel; + QLabel localCardImageStorageNamingSchemeLabel; + QLineEdit *localCardImageStorageNamingSchemeLineEdit; }; class MessagesSettingsPage : public AbstractSettingsPage From 37cb86f16af3646ad1d606e0c8fd86a646f2d3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Sun, 12 Apr 2026 08:19:41 +0200 Subject: [PATCH 2/9] Give people options from a dropdown. Took 1 hour 6 minutes Took 3 seconds --- .../src/client/settings/cache_settings.cpp | 11 +- .../src/client/settings/cache_settings.h | 12 +- .../card_picture_loader.cpp | 39 ++++--- .../card_picture_loader_local.cpp | 23 +--- .../card_picture_loader_local_schemes.h | 109 ++++++++++++++++++ .../widgets/dialogs/dlg_settings.cpp | 24 +++- .../interface/widgets/dialogs/dlg_settings.h | 2 +- 7 files changed, 173 insertions(+), 47 deletions(-) create mode 100644 cockatrice/src/interface/card_picture_loader/card_picture_loader_local_schemes.h diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp index 8f96efd7b..e7840e61b 100644 --- a/cockatrice/src/client/settings/cache_settings.cpp +++ b/cockatrice/src/client/settings/cache_settings.cpp @@ -1,5 +1,6 @@ #include "cache_settings.h" +#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h" #include "../network/update/client/release_channel.h" #include "card_counter_settings.h" #include "version_string.h" @@ -266,7 +267,10 @@ SettingsCache::SettingsCache() redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt(); saveCardImagesToLocalStorage = settings->value("personal/saveCardImagesToLocalStorage", true).toBool(); localCardImageStorageNamingScheme = - settings->value("personal/localCardImageStorageNamingScheme", "{set}/{name}_{collector}_{uuid}.png").toString(); + settings + ->value("personal/localCardImageStorageNamingScheme", + static_cast(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_ProviderId)) + .toInt(); picDownload = settings->value("personal/picturedownload", true).toBool(); showStatusBar = settings->value("personal/showStatusBar", false).toBool(); @@ -1121,9 +1125,10 @@ void SettingsCache::setSaveCardImagesToLocalStorage(QT_STATE_CHANGED_T _saveCard emit saveCardImagesToLocalStorageChanged(saveCardImagesToLocalStorage); } -void SettingsCache::setLocalCardImageStorageNamingScheme(const QString _localCardImageStorageNamingScheme) +void SettingsCache::setLocalCardImageStorageNamingScheme( + const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme) { - localCardImageStorageNamingScheme = _localCardImageStorageNamingScheme; + localCardImageStorageNamingScheme = static_cast(_localCardImageStorageNamingScheme); settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme); emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme); } diff --git a/cockatrice/src/client/settings/cache_settings.h b/cockatrice/src/client/settings/cache_settings.h index e5fa3d3fc..bbd1aaf98 100644 --- a/cockatrice/src/client/settings/cache_settings.h +++ b/cockatrice/src/client/settings/cache_settings.h @@ -7,6 +7,7 @@ #ifndef SETTINGSCACHE_H #define SETTINGSCACHE_H +#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h" #include "shortcuts_settings.h" #include @@ -185,7 +186,7 @@ signals: void networkCacheSizeChanged(int newSizeInMBs); void redirectCacheTtlChanged(int newTtl); void saveCardImagesToLocalStorageChanged(bool saveCardImagesToLocalStorage); - void localCardImageStorageNamingSchemeChanged(QString localCardImageStorageNamingScheme); + void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme); void masterVolumeChanged(int value); void chatMentionCompleterChanged(); void downloadSpoilerTimeIndexChanged(); @@ -305,7 +306,7 @@ private: int networkCacheSize; int redirectCacheTtl; bool saveCardImagesToLocalStorage; - QString localCardImageStorageNamingScheme; + int localCardImageStorageNamingScheme; bool scaleCards; int verticalCardOverlapPercent; bool showMessagePopups; @@ -797,9 +798,9 @@ public: { return saveCardImagesToLocalStorage; } - [[nodiscard]] QString getLocalCardImageStorageNamingScheme() const + [[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const { - return localCardImageStorageNamingScheme; + return static_cast(localCardImageStorageNamingScheme); } [[nodiscard]] bool getScaleCards() const { @@ -1108,7 +1109,8 @@ public slots: void setNetworkCacheSizeInMB(const int _networkCacheSize); void setNetworkRedirectCacheTtl(const int _redirectCacheTtl); void setSaveCardImagesToLocalStorage(QT_STATE_CHANGED_T _saveCardImagesToLocalStorage); - void setLocalCardImageStorageNamingScheme(const QString _localCardImageStorageNamingScheme); + void setLocalCardImageStorageNamingScheme( + const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme); void setCardScaling(const QT_STATE_CHANGED_T _scaleCards); void setStackCardOverlapPercent(const int _verticalCardOverlapPercent); void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp index 52109fa2e..6a9bc0806 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp @@ -189,9 +189,19 @@ void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card, const } const QString picsRoot = SettingsCache::instance().getPicsPath(); - const QString scheme = SettingsCache::instance().getLocalCardImageStorageNamingScheme(); + CardPictureLoaderLocalSchemes::NamingScheme scheme = + SettingsCache::instance().getLocalCardImageStorageNamingScheme(); - if (picsRoot.isEmpty() || scheme.isEmpty()) { + QString pattern; + + for (const auto &s : CardPictureLoaderLocalSchemes::exportSchemes()) { + if (s.id == scheme) { + pattern = s.pattern; + break; + } + } + + if (picsRoot.isEmpty() || pattern.isEmpty()) { return; } @@ -217,18 +227,26 @@ void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card, const } // Build path from scheme - QString relativePath = scheme; + QString relativePath = + CardPictureLoaderLocalSchemes::expandPattern(pattern, cardName, setName, collectorNumber, uuid); - relativePath.replace("{name}", cardName); - relativePath.replace("{set}", setName); - relativePath.replace("{collector}", collectorNumber); - relativePath.replace("{uuid}", uuid); - relativePath.replace("{ext}", "png"); + if (relativePath.isEmpty()) { + return; + } + + // append extension + relativePath += ".png"; // Normalize slashes relativePath = QDir::cleanPath(relativePath); QFileInfo outInfo(baseDir.filePath(relativePath)); + + // Do not overwrite existing files + if (outInfo.exists()) { + return; + } + QDir outDir = outInfo.dir(); // Ensure directory exists @@ -239,11 +257,6 @@ void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card, const } } - // Do not overwrite existing files - if (outInfo.exists()) { - return; - } - // Save image QImage image = pixmap.toImage(); if (!image.save(outInfo.absoluteFilePath(), "PNG")) { diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp index dd00e6e1d..bb10d1c42 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp @@ -1,6 +1,7 @@ #include "card_picture_loader_local.h" #include "../../client/settings/cache_settings.h" +#include "card_picture_loader_local_schemes.h" #include "card_picture_to_load.h" #include @@ -77,26 +78,8 @@ QImage CardPictureLoaderLocal::tryLoadCardImageFromDisk(const QString &setName, imgReader.setDecideFormatFromContent(true); // Most-to-least specific, these will fall through in order. - QStringList nameVariants; - - // cardName_providerId - if (!providerId.isEmpty()) { - nameVariants << QString("%1-%2").arg(correctedCardName, providerId) - << QString("%1_%2").arg(correctedCardName, providerId); - } - // cardName_setName_collectorNumber & setName-collectorNumber-cardName - if (!setName.isEmpty() && !collectorNumber.isEmpty()) { - nameVariants << QString("%1_%2_%3").arg(correctedCardName, setName, collectorNumber) - << QString("%1-%2-%3").arg(setName, collectorNumber, correctedCardName); - } - // cardName_setName - if (!setName.isEmpty()) { - nameVariants << QString("%1_%2").arg(correctedCardName, setName) - << QString("%1-%2").arg(setName, correctedCardName); - } - - // cardName - nameVariants << correctedCardName; + QStringList nameVariants = + CardPictureLoaderLocalSchemes::generateImportVariants(correctedCardName, setName, collectorNumber, providerId); for (const QString &nameVariant : nameVariants) { if (nameVariant.isEmpty()) { diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local_schemes.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local_schemes.h new file mode 100644 index 000000000..cad7d2d5f --- /dev/null +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local_schemes.h @@ -0,0 +1,109 @@ +#ifndef COCKATRICE_CARD_PICTURE_LOADER_LOCAL_SCHEMES_H +#define COCKATRICE_CARD_PICTURE_LOADER_LOCAL_SCHEMES_H + +#include +#include +#include +#include + +namespace CardPictureLoaderLocalSchemes +{ + +enum class NamingScheme +{ + NameOnly, + Name_Set, + Name_Set_Collector, + Set_Collector_Name, + Name_ProviderId, + Set_Folder_Name_ProviderId, + Set_Folder_Name_Set_Collector +}; + +struct NamingSchemeInfo +{ + NamingScheme id; + QString displayName; + QString pattern; +}; + +inline const QList &importSchemes() +{ + static QList list = { + {NamingScheme::Name_ProviderId, "Card Name + Provider ID", "{name}_{providerId}"}, + {NamingScheme::Name_Set_Collector, "Card Name + Set + Collector", "{name}_{set}_{collector}"}, + {NamingScheme::Set_Collector_Name, "Set + Collector + Card Name", "{set}_{collector}_{name}"}, + {NamingScheme::Name_Set, "Card Name + Set", "{name}_{set}"}, + {NamingScheme::NameOnly, "Card Name", "{name}"}, + }; + return list; +} + +inline const QList &exportSchemes() +{ + static QList list = { + {NamingScheme::Set_Folder_Name_ProviderId, "Set Folder / Name + Provider ID", "{set}/{name}_{providerId}"}, + {NamingScheme::Set_Folder_Name_Set_Collector, "Set Folder / Name + Set Name + Collector", + "{set}/{name}_{set}_{collector}"}, + {NamingScheme::Name_ProviderId, "Card Name + Provider ID", "{name}_{providerId}"}, + {NamingScheme::Name_Set_Collector, "Card Name + Set + Collector", "{name}_{set}_{collector}"}, + {NamingScheme::Set_Collector_Name, "Set + Collector + Card Name", "{set}_{collector}_{name}"}, + }; + return list; +} + +inline QString expandPattern(const QString &pattern, + const QString &name, + const QString &set, + const QString &collector, + const QString &providerId) +{ + QString result = pattern; + + auto replaceIfPresent = [&](const QString &token, const QString &value) -> bool { + if (!result.contains(token)) + return true; + + if (value.isEmpty()) + return false; + + result.replace(token, value); + return true; + }; + + if (!replaceIfPresent("{name}", name)) + return {}; + if (!replaceIfPresent("{set}", set)) + return {}; + if (!replaceIfPresent("{collector}", collector)) + return {}; + if (!replaceIfPresent("{providerId}", providerId)) + return {}; + + return result; +} + +inline QStringList +generateImportVariants(const QString &name, const QString &set, const QString &collector, const QString &providerId) +{ + QStringList variants; + const QStringList separators = {"_", "-"}; + + for (const auto &scheme : importSchemes()) { + for (const QString &sep : separators) { + + QString pattern = scheme.pattern; + pattern.replace("_", sep); + + QString v = expandPattern(pattern, name, set, collector, providerId); + if (!v.isEmpty()) + variants << v; + } + } + + return variants; +} + +} // namespace CardPictureLoaderLocalSchemes + +#endif // COCKATRICE_CARD_PICTURE_LOADER_LOCAL_SCHEMES_H \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 6187d93d5..3f9cd611d 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1079,10 +1079,24 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() connect(&saveCardImagesToLocalStorageCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), &SettingsCache::setSaveCardImagesToLocalStorage); - localCardImageStorageNamingSchemeLineEdit = - new QLineEdit(SettingsCache::instance().getLocalCardImageStorageNamingScheme()); - connect(localCardImageStorageNamingSchemeLineEdit, &QLineEdit::textChanged, &SettingsCache::instance(), - &SettingsCache::setLocalCardImageStorageNamingScheme); + localCardImageStorageNamingSchemeComboBox = new QComboBox; + for (const auto &scheme : CardPictureLoaderLocalSchemes::exportSchemes()) { + localCardImageStorageNamingSchemeComboBox->addItem(scheme.displayName, static_cast(scheme.id)); + } + + int current = static_cast(SettingsCache::instance().getLocalCardImageStorageNamingScheme()); + + int index = localCardImageStorageNamingSchemeComboBox->findData(current); + if (index >= 0) { + localCardImageStorageNamingSchemeComboBox->setCurrentIndex(index); + } + + connect(localCardImageStorageNamingSchemeComboBox, qOverload(&QComboBox::currentIndexChanged), this, + [this](int index) { + auto scheme = static_cast( + localCardImageStorageNamingSchemeComboBox->itemData(index).toInt()); + SettingsCache::instance().setLocalCardImageStorageNamingScheme(scheme); + }); auto networkCacheLayout = new QHBoxLayout; networkCacheLayout->addStretch(); @@ -1105,7 +1119,7 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() auto localCardImageStorageNamingSchemeLayout = new QHBoxLayout; localCardImageStorageNamingSchemeLayout->addWidget(&localCardImageStorageNamingSchemeLabel); - localCardImageStorageNamingSchemeLayout->addWidget(localCardImageStorageNamingSchemeLineEdit); + localCardImageStorageNamingSchemeLayout->addWidget(localCardImageStorageNamingSchemeComboBox); // Top Layout lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index a7608578a..c05fb50b7 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -242,7 +242,7 @@ private: QCheckBox saveCardImagesToLocalStorageCheckBox; QLabel saveCardImagesToLocalStorageLabel; QLabel localCardImageStorageNamingSchemeLabel; - QLineEdit *localCardImageStorageNamingSchemeLineEdit; + QComboBox *localCardImageStorageNamingSchemeComboBox; }; class MessagesSettingsPage : public AbstractSettingsPage From ac41fe7d3cefb5320d34d1b58184309543e4430e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Sun, 12 Apr 2026 08:24:51 +0200 Subject: [PATCH 3/9] Simplify directory removal code. Took 5 minutes Took 8 seconds --- .../widgets/dialogs/dlg_settings.cpp | 34 +++---------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 3f9cd611d..dd7b32152 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1181,37 +1181,13 @@ void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked() { CardPictureLoader::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; - for (const auto &dir : dirs) { - QString currentPath = picsPath + dir + "/"; - QStringList files = QDir(currentPath).entryList(QDir::Files); - bool innerSuccessRemove = true; - for (int j = 0; j < files.length(); j++) { - if (!QDir(currentPath).remove(files.at(j))) { - qInfo() << "Failed to remove " + currentPath.toUtf8() + files.at(j).toUtf8(); - outerSuccessRemove = false; - innerSuccessRemove = false; - } - qInfo() << "Removed " << currentPath << files.at(j); - } + QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics"; - if (innerSuccessRemove) { - bool success = QDir(picsPath).rmdir(dir); - if (!success) { - qInfo() << "Failed to remove inner directory" << picsPath; - } else { - qInfo() << "Removed" << currentPath; - } - } - } - if (outerSuccessRemove) { + QDir dir(picsPath); + bool success = dir.removeRecursively(); + + if (success) { 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.")); } From b4b78a0a9d1dfd8af3a03b8bcdccf8390b791465 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Sun, 12 Apr 2026 21:33:15 -0700 Subject: [PATCH 4/9] Merge pull request #8 * Create new category for new settings --- .../widgets/dialogs/dlg_settings.cpp | 40 ++++++++++++------- .../interface/widgets/dialogs/dlg_settings.h | 5 ++- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index dd7b32152..304017a08 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1009,6 +1009,7 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() auto *lpGeneralGrid = new QGridLayout; auto *lpSpoilerGrid = new QGridLayout; + auto *lpImageBackupGrid = new QGridLayout; mcDownloadSpoilersCheckBox.setChecked(SettingsCache::instance().getDownloadSpoilersStatus()); @@ -1075,6 +1076,7 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() networkRedirectCacheTtlEdit.setSingleStep(1); networkRedirectCacheTtlEdit.setValue(SettingsCache::instance().getRedirectCacheTtl()); + // Image Backup saveCardImagesToLocalStorageCheckBox.setChecked(SettingsCache::instance().getSaveCardImagesToLocalStorage()); connect(&saveCardImagesToLocalStorageCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), &SettingsCache::setSaveCardImagesToLocalStorage); @@ -1098,6 +1100,8 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() SettingsCache::instance().setLocalCardImageStorageNamingScheme(scheme); }); + connect(&clearBackupsButton, &QPushButton::clicked, this, &DeckEditorSettingsPage::clearImageBackupsButtonClicked); + auto networkCacheLayout = new QHBoxLayout; networkCacheLayout->addStretch(); networkCacheLayout->addWidget(&networkCacheLabel); @@ -1113,14 +1117,6 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() pixmapCacheLayout->addWidget(&pixmapCacheLabel); pixmapCacheLayout->addWidget(&pixmapCacheEdit); - auto saveCardImagesToLocalStorageLayout = new QHBoxLayout; - saveCardImagesToLocalStorageLayout->addWidget(&saveCardImagesToLocalStorageLabel); - saveCardImagesToLocalStorageLayout->addWidget(&saveCardImagesToLocalStorageCheckBox); - - auto localCardImageStorageNamingSchemeLayout = new QHBoxLayout; - localCardImageStorageNamingSchemeLayout->addWidget(&localCardImageStorageNamingSchemeLabel); - localCardImageStorageNamingSchemeLayout->addWidget(localCardImageStorageNamingSchemeComboBox); - // Top Layout lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0); lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1); @@ -1128,10 +1124,8 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() lpGeneralGrid->addLayout(networkCacheLayout, 2, 1); lpGeneralGrid->addLayout(networkRedirectCacheLayout, 3, 0); lpGeneralGrid->addLayout(pixmapCacheLayout, 3, 1); - lpGeneralGrid->addLayout(saveCardImagesToLocalStorageLayout, 4, 0, 1, 2); - lpGeneralGrid->addLayout(localCardImageStorageNamingSchemeLayout, 5, 0, 1, 2); - lpGeneralGrid->addWidget(&urlLinkLabel, 7, 0); - lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 7, 1); + lpGeneralGrid->addWidget(&urlLinkLabel, 4, 0); + lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 4, 1); // Spoiler Layout lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0); @@ -1142,6 +1136,12 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() lpSpoilerGrid->addWidget(updateNowButton, 2, 1); lpSpoilerGrid->addWidget(&infoOnSpoilersLabel, 3, 0, 1, 3, Qt::AlignTop); + // Image Backup Layout + lpImageBackupGrid->addWidget(&saveCardImagesToLocalStorageCheckBox, 0, 0, 1, 2); + lpImageBackupGrid->addWidget(&localCardImageStorageNamingSchemeLabel, 1, 0); + lpImageBackupGrid->addWidget(localCardImageStorageNamingSchemeComboBox, 1, 1); + lpImageBackupGrid->addWidget(&clearBackupsButton, 3, 1); + // On a change to the checkbox, hide/un-hide the other fields connect(&mcDownloadSpoilersCheckBox, &QCheckBox::toggled, &SettingsCache::instance(), &SettingsCache::setDownloadSpoilerStatus); @@ -1159,9 +1159,13 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() mpSpoilerGroupBox = new QGroupBox; mpSpoilerGroupBox->setLayout(lpSpoilerGrid); + mpImageBackupGroupBox = new QGroupBox; + mpImageBackupGroupBox->setLayout(lpImageBackupGrid); + auto *lpMainLayout = new QVBoxLayout; lpMainLayout->addWidget(mpGeneralGroupBox); lpMainLayout->addWidget(mpSpoilerGroupBox); + lpMainLayout->addWidget(mpImageBackupGroupBox); setLayout(lpMainLayout); @@ -1180,7 +1184,11 @@ void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked() void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked() { CardPictureLoader::clearNetworkCache(); + QMessageBox::information(this, tr("Success"), tr("Cached card pictures have been reset.")); +} +void DeckEditorSettingsPage::clearImageBackupsButtonClicked() +{ QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics"; QDir dir(picsPath); @@ -1303,6 +1311,7 @@ void DeckEditorSettingsPage::retranslateUi() { mpGeneralGroupBox->setTitle(tr("URL Download Priority")); mpSpoilerGroupBox->setTitle(tr("Spoilers")); + mpImageBackupGroupBox->setTitle(tr("Image Backup")); mcDownloadSpoilersCheckBox.setText(tr("Download Spoilers Automatically")); mcSpoilerSaveLabel.setText(tr("Spoiler Location:")); lastUpdatedLabel.setText(tr("Last Change") + ": " + getLastUpdateTime()); @@ -1311,7 +1320,8 @@ void DeckEditorSettingsPage::retranslateUi() tr("Do not close settings until manual update is complete")); picDownloadCheckBox.setText(tr("Download card pictures on the fly")); urlLinkLabel.setText(QString("%2").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL"))); - clearDownloadedPicsButton.setText(tr("Delete Downloaded Images")); + clearDownloadedPicsButton.setText(tr("Delete Cached Images")); + clearBackupsButton.setText(tr("Delete Saved Images")); resetDownloadURLs.setText(tr("Reset Download URLs")); networkCacheLabel.setText(tr("Network Cache Size:")); networkCacheEdit.setToolTip(tr("On-disk cache for downloaded pictures")); @@ -1319,8 +1329,8 @@ void DeckEditorSettingsPage::retranslateUi() networkRedirectCacheTtlEdit.setToolTip(tr("How long cached redirects for urls are valid for.")); pixmapCacheLabel.setText(tr("Picture Cache Size:")); pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen")); - saveCardImagesToLocalStorageLabel.setText(tr("Save downloaded images to local storage")); - localCardImageStorageNamingSchemeLabel.setText(tr("Save downloaded images using this naming scheme:")); + saveCardImagesToLocalStorageCheckBox.setText(tr("Back up downloaded images to local storage")); + localCardImageStorageNamingSchemeLabel.setText(tr("Naming scheme:")); updateNowButton->setText(tr("Update Spoilers")); aAdd->setText(tr("Add New URL")); aEdit->setText(tr("Edit URL")); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index c05fb50b7..5ea7c780c 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -215,9 +215,11 @@ private slots: void actEditURL(); void clearDownloadedPicsButtonClicked(); void resetDownloadedURLsButtonClicked(); + void clearImageBackupsButtonClicked(); private: QPushButton clearDownloadedPicsButton; + QPushButton clearBackupsButton; QPushButton resetDownloadURLs; QLabel urlLinkLabel; QCheckBox picDownloadCheckBox; @@ -227,6 +229,8 @@ private: QLabel msDownloadSpoilersLabel; QGroupBox *mpGeneralGroupBox; QGroupBox *mpSpoilerGroupBox; + QGroupBox *mpImageBackupGroupBox; + QLineEdit *mpSpoilerSavePathLineEdit; QLabel mcSpoilerSaveLabel; QLabel lastUpdatedLabel; @@ -240,7 +244,6 @@ private: QSpinBox pixmapCacheEdit; QLabel pixmapCacheLabel; QCheckBox saveCardImagesToLocalStorageCheckBox; - QLabel saveCardImagesToLocalStorageLabel; QLabel localCardImageStorageNamingSchemeLabel; QComboBox *localCardImageStorageNamingSchemeComboBox; }; From b1286866dd58e51bff5daba374f9ff1ca79d26c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Mon, 13 Apr 2026 07:25:53 +0200 Subject: [PATCH 5/9] Split off storage settings Took 47 minutes Took 4 seconds --- .../widgets/dialogs/dlg_settings.cpp | 285 +++++++++++------- .../interface/widgets/dialogs/dlg_settings.h | 34 ++- 2 files changed, 203 insertions(+), 116 deletions(-) diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 304017a08..b5b404246 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1003,13 +1003,10 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse); urlLinkLabel.setOpenExternalLinks(true); - connect(&clearDownloadedPicsButton, &QPushButton::clicked, this, - &DeckEditorSettingsPage::clearDownloadedPicsButtonClicked); connect(&resetDownloadURLs, &QPushButton::clicked, this, &DeckEditorSettingsPage::resetDownloadedURLsButtonClicked); auto *lpGeneralGrid = new QGridLayout; auto *lpSpoilerGrid = new QGridLayout; - auto *lpImageBackupGrid = new QGridLayout; mcDownloadSpoilersCheckBox.setChecked(SettingsCache::instance().getDownloadSpoilersStatus()); @@ -1057,75 +1054,11 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() urlListLayout->addWidget(urlToolBar); urlListLayout->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(" MB"); - - networkRedirectCacheTtlEdit.setMinimum(NETWORK_REDIRECT_CACHE_TTL_MIN); - networkRedirectCacheTtlEdit.setMaximum(NETWORK_REDIRECT_CACHE_TTL_MAX); - networkRedirectCacheTtlEdit.setSingleStep(1); - networkRedirectCacheTtlEdit.setValue(SettingsCache::instance().getRedirectCacheTtl()); - - // Image Backup - saveCardImagesToLocalStorageCheckBox.setChecked(SettingsCache::instance().getSaveCardImagesToLocalStorage()); - connect(&saveCardImagesToLocalStorageCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setSaveCardImagesToLocalStorage); - - localCardImageStorageNamingSchemeComboBox = new QComboBox; - for (const auto &scheme : CardPictureLoaderLocalSchemes::exportSchemes()) { - localCardImageStorageNamingSchemeComboBox->addItem(scheme.displayName, static_cast(scheme.id)); - } - - int current = static_cast(SettingsCache::instance().getLocalCardImageStorageNamingScheme()); - - int index = localCardImageStorageNamingSchemeComboBox->findData(current); - if (index >= 0) { - localCardImageStorageNamingSchemeComboBox->setCurrentIndex(index); - } - - connect(localCardImageStorageNamingSchemeComboBox, qOverload(&QComboBox::currentIndexChanged), this, - [this](int index) { - auto scheme = static_cast( - localCardImageStorageNamingSchemeComboBox->itemData(index).toInt()); - SettingsCache::instance().setLocalCardImageStorageNamingScheme(scheme); - }); - - connect(&clearBackupsButton, &QPushButton::clicked, this, &DeckEditorSettingsPage::clearImageBackupsButtonClicked); - - auto networkCacheLayout = new QHBoxLayout; - networkCacheLayout->addStretch(); - networkCacheLayout->addWidget(&networkCacheLabel); - networkCacheLayout->addWidget(&networkCacheEdit); - - auto networkRedirectCacheLayout = new QHBoxLayout; - networkRedirectCacheLayout->addStretch(); - networkRedirectCacheLayout->addWidget(&networkRedirectCacheTtlLabel); - networkRedirectCacheLayout->addWidget(&networkRedirectCacheTtlEdit); - - 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(urlListLayout, 1, 0, 1, 2); - lpGeneralGrid->addLayout(networkCacheLayout, 2, 1); - lpGeneralGrid->addLayout(networkRedirectCacheLayout, 3, 0); - lpGeneralGrid->addLayout(pixmapCacheLayout, 3, 1); lpGeneralGrid->addWidget(&urlLinkLabel, 4, 0); - lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 4, 1); // Spoiler Layout lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0); @@ -1136,22 +1069,10 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() lpSpoilerGrid->addWidget(updateNowButton, 2, 1); lpSpoilerGrid->addWidget(&infoOnSpoilersLabel, 3, 0, 1, 3, Qt::AlignTop); - // Image Backup Layout - lpImageBackupGrid->addWidget(&saveCardImagesToLocalStorageCheckBox, 0, 0, 1, 2); - lpImageBackupGrid->addWidget(&localCardImageStorageNamingSchemeLabel, 1, 0); - lpImageBackupGrid->addWidget(localCardImageStorageNamingSchemeComboBox, 1, 1); - lpImageBackupGrid->addWidget(&clearBackupsButton, 3, 1); - // On a change to the checkbox, hide/un-hide the other fields connect(&mcDownloadSpoilersCheckBox, &QCheckBox::toggled, &SettingsCache::instance(), &SettingsCache::setDownloadSpoilerStatus); connect(&mcDownloadSpoilersCheckBox, &QCheckBox::toggled, this, &DeckEditorSettingsPage::setSpoilersEnabled); - connect(&pixmapCacheEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), - &SettingsCache::setPixmapCacheSize); - connect(&networkCacheEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), - &SettingsCache::setNetworkCacheSizeInMB); - connect(&networkRedirectCacheTtlEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), - &SettingsCache::setNetworkRedirectCacheTtl); mpGeneralGroupBox = new QGroupBox; mpGeneralGroupBox->setLayout(lpGeneralGrid); @@ -1159,13 +1080,9 @@ DeckEditorSettingsPage::DeckEditorSettingsPage() mpSpoilerGroupBox = new QGroupBox; mpSpoilerGroupBox->setLayout(lpSpoilerGrid); - mpImageBackupGroupBox = new QGroupBox; - mpImageBackupGroupBox->setLayout(lpImageBackupGrid); - auto *lpMainLayout = new QVBoxLayout; lpMainLayout->addWidget(mpGeneralGroupBox); lpMainLayout->addWidget(mpSpoilerGroupBox); - lpMainLayout->addWidget(mpImageBackupGroupBox); setLayout(lpMainLayout); @@ -1181,26 +1098,6 @@ void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked() QMessageBox::information(this, tr("Success"), tr("Download URLs have been reset.")); } -void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked() -{ - CardPictureLoader::clearNetworkCache(); - QMessageBox::information(this, tr("Success"), tr("Cached card pictures have been reset.")); -} - -void DeckEditorSettingsPage::clearImageBackupsButtonClicked() -{ - QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics"; - - QDir dir(picsPath); - bool success = dir.removeRecursively(); - - if (success) { - QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset.")); - } else { - QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared.")); - } -} - void DeckEditorSettingsPage::actAddURL() { bool ok; @@ -1311,7 +1208,6 @@ void DeckEditorSettingsPage::retranslateUi() { mpGeneralGroupBox->setTitle(tr("URL Download Priority")); mpSpoilerGroupBox->setTitle(tr("Spoilers")); - mpImageBackupGroupBox->setTitle(tr("Image Backup")); mcDownloadSpoilersCheckBox.setText(tr("Download Spoilers Automatically")); mcSpoilerSaveLabel.setText(tr("Spoiler Location:")); lastUpdatedLabel.setText(tr("Last Change") + ": " + getLastUpdateTime()); @@ -1320,9 +1216,177 @@ void DeckEditorSettingsPage::retranslateUi() tr("Do not close settings until manual update is complete")); picDownloadCheckBox.setText(tr("Download card pictures on the fly")); urlLinkLabel.setText(QString("%2").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL"))); + resetDownloadURLs.setText(tr("Reset Download URLs")); + updateNowButton->setText(tr("Update Spoilers")); + aAdd->setText(tr("Add New URL")); + aEdit->setText(tr("Edit URL")); + aRemove->setText(tr("Remove URL")); +} + +StorageSettingsPage::StorageSettingsPage() +{ + auto *lpNetworkCacheGrid = new QGridLayout; + auto *lpImageBackupGrid = new QGridLayout; + auto *lpPixmapCacheGrid = new QGridLayout; + + networkCacheExplainerLabel.setWordWrap(true); + imageBackupExplainerLabel.setWordWrap(true); + pixmapCacheExplainerLabel.setWordWrap(true); + + connect(&clearDownloadedPicsButton, &QPushButton::clicked, this, + &StorageSettingsPage::clearDownloadedPicsButtonClicked); + + // 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(" MB"); + + networkRedirectCacheTtlEdit.setMinimum(NETWORK_REDIRECT_CACHE_TTL_MIN); + networkRedirectCacheTtlEdit.setMaximum(NETWORK_REDIRECT_CACHE_TTL_MAX); + networkRedirectCacheTtlEdit.setSingleStep(1); + networkRedirectCacheTtlEdit.setValue(SettingsCache::instance().getRedirectCacheTtl()); + + // Image Backup + saveCardImagesToLocalStorageCheckBox.setChecked(SettingsCache::instance().getSaveCardImagesToLocalStorage()); + connect(&saveCardImagesToLocalStorageCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), + &SettingsCache::setSaveCardImagesToLocalStorage); + + localCardImageStorageNamingSchemeComboBox = new QComboBox; + for (const auto &scheme : CardPictureLoaderLocalSchemes::exportSchemes()) { + localCardImageStorageNamingSchemeComboBox->addItem(scheme.displayName, static_cast(scheme.id)); + } + + int current = static_cast(SettingsCache::instance().getLocalCardImageStorageNamingScheme()); + + int index = localCardImageStorageNamingSchemeComboBox->findData(current); + if (index >= 0) { + localCardImageStorageNamingSchemeComboBox->setCurrentIndex(index); + } + + connect(localCardImageStorageNamingSchemeComboBox, qOverload(&QComboBox::currentIndexChanged), this, + [this](int index) { + auto scheme = static_cast( + localCardImageStorageNamingSchemeComboBox->itemData(index).toInt()); + SettingsCache::instance().setLocalCardImageStorageNamingScheme(scheme); + }); + + connect(&clearBackupsButton, &QPushButton::clicked, this, &StorageSettingsPage::clearImageBackupsButtonClicked); + + auto networkCacheLayout = new QHBoxLayout; + networkCacheLayout->addStretch(); + networkCacheLayout->addWidget(&networkCacheLabel); + networkCacheLayout->addWidget(&networkCacheEdit); + + auto networkRedirectCacheLayout = new QHBoxLayout; + networkRedirectCacheLayout->addStretch(); + networkRedirectCacheLayout->addWidget(&networkRedirectCacheTtlLabel); + networkRedirectCacheLayout->addWidget(&networkRedirectCacheTtlEdit); + + auto pixmapCacheLayout = new QHBoxLayout; + pixmapCacheLayout->addStretch(); + pixmapCacheLayout->addWidget(&pixmapCacheLabel); + pixmapCacheLayout->addWidget(&pixmapCacheEdit); + + lpNetworkCacheGrid->addWidget(&networkCacheExplainerLabel, 0, 0); + lpNetworkCacheGrid->addLayout(networkCacheLayout, 1, 0); + lpNetworkCacheGrid->addLayout(networkRedirectCacheLayout, 2, 0); + lpNetworkCacheGrid->addWidget(&clearDownloadedPicsButton, 3, 0); + + // Image Backup Layout + lpImageBackupGrid->addWidget(&imageBackupExplainerLabel, 0, 0, 1, 2); + lpImageBackupGrid->addWidget(&saveCardImagesToLocalStorageCheckBox, 1, 0); + lpImageBackupGrid->addWidget(&localCardImageStorageNamingSchemeLabel, 2, 0); + lpImageBackupGrid->addWidget(localCardImageStorageNamingSchemeComboBox, 2, 1); + lpImageBackupGrid->addWidget(&clearBackupsButton, 3, 1); + + lpPixmapCacheGrid->addWidget(&pixmapCacheExplainerLabel, 0, 0); + lpPixmapCacheGrid->addLayout(pixmapCacheLayout, 1, 0); + + connect(&pixmapCacheEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), + &SettingsCache::setPixmapCacheSize); + connect(&networkCacheEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), + &SettingsCache::setNetworkCacheSizeInMB); + connect(&networkRedirectCacheTtlEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), + &SettingsCache::setNetworkRedirectCacheTtl); + + mpNetworkCacheGroupBox = new QGroupBox; + mpNetworkCacheGroupBox->setLayout(lpNetworkCacheGrid); + + mpImageBackupGroupBox = new QGroupBox; + mpImageBackupGroupBox->setLayout(lpImageBackupGrid); + + mpPixmapCacheGroupBox = new QGroupBox; + mpPixmapCacheGroupBox->setLayout(lpPixmapCacheGrid); + + auto *lpMainLayout = new QVBoxLayout; + + lpMainLayout->addWidget(mpNetworkCacheGroupBox); + lpMainLayout->addWidget(mpImageBackupGroupBox); + lpMainLayout->addWidget(mpPixmapCacheGroupBox); + + setLayout(lpMainLayout); + + connect(&SettingsCache::instance(), &SettingsCache::langChanged, this, &StorageSettingsPage::retranslateUi); + retranslateUi(); +} + +void StorageSettingsPage::clearDownloadedPicsButtonClicked() +{ + CardPictureLoader::clearNetworkCache(); + QMessageBox::information(this, tr("Success"), tr("Cached card pictures have been reset.")); +} + +void StorageSettingsPage::clearImageBackupsButtonClicked() +{ + QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics"; + + QDir dir(picsPath); + bool success = dir.removeRecursively(); + + if (success) { + QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset.")); + } else { + QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared.")); + } +} + +void StorageSettingsPage::retranslateUi() +{ + networkCacheExplainerLabel.setText( + tr("The network cache is the preferred way of storing images. Downloaded images " + "are stored here until the size of the cache exceeds the configured size. Cockatrice automatically monitors " + "this cache and deletes the least recently seen card images to ensure the cache does not exceed the " + "configured size.")); + imageBackupExplainerLabel.setText( + tr("Writing card images directly to a folder on your hard drive is another way " + "of storing images. This does not change how Cockatrice accesses or downloads " + "images. Cockatrice will NOT automatically monitor and clear this folder, so if you enable this option, it " + "is up to you to ensure sufficient available space. It should also be noted that if a provider outage " + "causes you to download the wrong picture (i.e. wrong printing) you will be stuck with it until you " + "manually delete the file, as opposed to using the network cache, which automatically rotates and thus " + "correct errors after a while.")); + pixmapCacheExplainerLabel.setText( + tr("This is the in-memory picture cache used by the application at runtime. It determines how much memory " + "(RAM) Cockatrice can use before it has to fetch card images from the hard disk again. Increasing this will " + "allow more card images to be displayed at once but shouldn't be necessary. Clearing this will make " + "Cockatrice reload all images from the network cache or the disk.")); + clearDownloadedPicsButton.setText(tr("Delete Cached Images")); clearBackupsButton.setText(tr("Delete Saved Images")); - resetDownloadURLs.setText(tr("Reset Download URLs")); + + mpNetworkCacheGroupBox->setTitle(tr("Network Cache")); + mpImageBackupGroupBox->setTitle(tr("Image Backup")); + mpPixmapCacheGroupBox->setTitle(tr("In-Memory Picture Cache")); + networkCacheLabel.setText(tr("Network Cache Size:")); networkCacheEdit.setToolTip(tr("On-disk cache for downloaded pictures")); networkRedirectCacheTtlLabel.setText(tr("Redirect Cache TTL:")); @@ -1331,10 +1395,7 @@ void DeckEditorSettingsPage::retranslateUi() pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen")); saveCardImagesToLocalStorageCheckBox.setText(tr("Back up downloaded images to local storage")); localCardImageStorageNamingSchemeLabel.setText(tr("Naming scheme:")); - updateNowButton->setText(tr("Update Spoilers")); - aAdd->setText(tr("Add New URL")); - aEdit->setText(tr("Edit URL")); - aRemove->setText(tr("Remove URL")); + networkRedirectCacheTtlEdit.setSuffix(" " + tr("Day(s)")); } @@ -1810,6 +1871,7 @@ DlgSettings::DlgSettings(QWidget *parent) : QDialog(parent) pagesWidget->addWidget(makeScrollable(new AppearanceSettingsPage)); pagesWidget->addWidget(makeScrollable(new UserInterfaceSettingsPage)); pagesWidget->addWidget(new DeckEditorSettingsPage); + pagesWidget->addWidget(new StorageSettingsPage); pagesWidget->addWidget(new MessagesSettingsPage); pagesWidget->addWidget(new SoundSettingsPage); pagesWidget->addWidget(new ShortcutSettingsPage); @@ -1858,6 +1920,11 @@ void DlgSettings::createIcons() deckEditorButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); deckEditorButton->setIcon(QPixmap("theme:config/deckeditor")); + storageButton = new QListWidgetItem(contentsWidget); + storageButton->setTextAlignment(Qt::AlignHCenter); + storageButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + storageButton->setIcon(QPixmap("theme:config/deckeditor")); + messagesButton = new QListWidgetItem(contentsWidget); messagesButton->setTextAlignment(Qt::AlignHCenter); messagesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index 5ea7c780c..318311f8b 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -213,13 +213,9 @@ private slots: void actAddURL(); void actRemoveURL(); void actEditURL(); - void clearDownloadedPicsButtonClicked(); void resetDownloadedURLsButtonClicked(); - void clearImageBackupsButtonClicked(); private: - QPushButton clearDownloadedPicsButton; - QPushButton clearBackupsButton; QPushButton resetDownloadURLs; QLabel urlLinkLabel; QCheckBox picDownloadCheckBox; @@ -229,7 +225,6 @@ private: QLabel msDownloadSpoilersLabel; QGroupBox *mpGeneralGroupBox; QGroupBox *mpSpoilerGroupBox; - QGroupBox *mpImageBackupGroupBox; QLineEdit *mpSpoilerSavePathLineEdit; QLabel mcSpoilerSaveLabel; @@ -237,6 +232,31 @@ private: QLabel infoOnSpoilersLabel; QPushButton *mpSpoilerPathButton; QPushButton *updateNowButton; +}; + +class StorageSettingsPage : public AbstractSettingsPage +{ + Q_OBJECT +public: + StorageSettingsPage(); + void retranslateUi() override; + +private slots: + void clearDownloadedPicsButtonClicked(); + void clearImageBackupsButtonClicked(); + +private: + QPushButton clearDownloadedPicsButton; + QPushButton clearBackupsButton; + + QGroupBox *mpNetworkCacheGroupBox; + QGroupBox *mpImageBackupGroupBox; + QGroupBox *mpPixmapCacheGroupBox; + + QLabel networkCacheExplainerLabel; + QLabel imageBackupExplainerLabel; + QLabel pixmapCacheExplainerLabel; + QLabel networkCacheLabel; QSpinBox networkCacheEdit; QLabel networkRedirectCacheTtlLabel; @@ -360,8 +380,8 @@ private slots: private: QListWidget *contentsWidget; QStackedWidget *pagesWidget; - QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *deckEditorButton, *messagesButton, - *soundButton, *shortcutsButton; + QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *deckEditorButton, *storageButton, + *messagesButton, *soundButton, *shortcutsButton; void createIcons(); void retranslateUi(); From c8c7dcba5f9d2d786a88414f72dd1178bb91ad31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Mon, 13 Apr 2026 14:42:47 +0200 Subject: [PATCH 6/9] Allow toggling between caching methods. Took 1 hour 30 minutes Took 9 seconds --- .../src/client/settings/cache_settings.cpp | 21 ++++--- .../src/client/settings/cache_settings.h | 15 ++--- .../card_picture_loader.cpp | 3 +- .../card_picture_loader_cache_method.h | 30 +++++++++ .../card_picture_loader_worker.cpp | 38 +++++++---- .../widgets/dialogs/dlg_settings.cpp | 63 +++++++++++++++++-- .../interface/widgets/dialogs/dlg_settings.h | 3 + 7 files changed, 138 insertions(+), 35 deletions(-) create mode 100644 cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp index e7840e61b..910f82535 100644 --- a/cockatrice/src/client/settings/cache_settings.cpp +++ b/cockatrice/src/client/settings/cache_settings.cpp @@ -1,5 +1,6 @@ #include "cache_settings.h" +#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h" #include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h" #include "../network/update/client/release_channel.h" #include "card_counter_settings.h" @@ -265,7 +266,11 @@ SettingsCache::SettingsCache() networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt(); redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt(); - saveCardImagesToLocalStorage = settings->value("personal/saveCardImagesToLocalStorage", true).toBool(); + cardPictureLoaderCacheMethod = + settings + ->value("personal/cardPictureLoaderCacheMethod", + static_cast(CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE)) + .toInt(); localCardImageStorageNamingScheme = settings ->value("personal/localCardImageStorageNamingScheme", @@ -1104,6 +1109,13 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize) emit pixmapCacheSizeChanged(pixmapCacheSize); } +void SettingsCache::setCardImageCacheMethod(const CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod) +{ + cardPictureLoaderCacheMethod = static_cast(_cardImageCachingMethod); + settings->setValue("personal/cardPictureLoaderCacheMethod", cardPictureLoaderCacheMethod); + emit cardPictureLoaderCacheMethodChanged(cardPictureLoaderCacheMethod); +} + void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize) { networkCacheSize = _networkCacheSize; @@ -1118,13 +1130,6 @@ void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl) emit redirectCacheTtlChanged(redirectCacheTtl); } -void SettingsCache::setSaveCardImagesToLocalStorage(QT_STATE_CHANGED_T _saveCardImagesToLocalStorage) -{ - saveCardImagesToLocalStorage = _saveCardImagesToLocalStorage; - settings->setValue("personal/saveCardImagesToLocalStorage", saveCardImagesToLocalStorage); - emit saveCardImagesToLocalStorageChanged(saveCardImagesToLocalStorage); -} - void SettingsCache::setLocalCardImageStorageNamingScheme( const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme) { diff --git a/cockatrice/src/client/settings/cache_settings.h b/cockatrice/src/client/settings/cache_settings.h index bbd1aaf98..6cb89bb1c 100644 --- a/cockatrice/src/client/settings/cache_settings.h +++ b/cockatrice/src/client/settings/cache_settings.h @@ -7,6 +7,7 @@ #ifndef SETTINGSCACHE_H #define SETTINGSCACHE_H +#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h" #include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h" #include "shortcuts_settings.h" @@ -185,7 +186,7 @@ signals: void pixmapCacheSizeChanged(int newSizeInMBs); void networkCacheSizeChanged(int newSizeInMBs); void redirectCacheTtlChanged(int newTtl); - void saveCardImagesToLocalStorageChanged(bool saveCardImagesToLocalStorage); + void cardPictureLoaderCacheMethodChanged(int cardPictureLoaderCacheMethod); void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme); void masterVolumeChanged(int value); void chatMentionCompleterChanged(); @@ -305,7 +306,7 @@ private: int pixmapCacheSize; int networkCacheSize; int redirectCacheTtl; - bool saveCardImagesToLocalStorage; + int cardPictureLoaderCacheMethod; int localCardImageStorageNamingScheme; bool scaleCards; int verticalCardOverlapPercent; @@ -786,6 +787,10 @@ public: { return pixmapCacheSize; } + [[nodiscard]] CardPictureLoaderCacheMethod::CacheMethod getCardPictureLoaderCacheMethod() const + { + return static_cast(cardPictureLoaderCacheMethod); + } [[nodiscard]] int getNetworkCacheSizeInMB() const { return networkCacheSize; @@ -794,10 +799,6 @@ public: { return redirectCacheTtl; } - [[nodiscard]] bool getSaveCardImagesToLocalStorage() const - { - return saveCardImagesToLocalStorage; - } [[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const { return static_cast(localCardImageStorageNamingScheme); @@ -1106,9 +1107,9 @@ public slots: void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers); void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages); void setPixmapCacheSize(const int _pixmapCacheSize); + void setCardImageCacheMethod(CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod); void setNetworkCacheSizeInMB(const int _networkCacheSize); void setNetworkRedirectCacheTtl(const int _redirectCacheTtl); - void setSaveCardImagesToLocalStorage(QT_STATE_CHANGED_T _saveCardImagesToLocalStorage); void setLocalCardImageStorageNamingScheme( const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme); void setCardScaling(const QT_STATE_CHANGED_T _scaleCards); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp index 6a9bc0806..0285b306e 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp @@ -169,7 +169,8 @@ void CardPictureLoader::imageLoaded(const ExactCard &card, const QImage &image) QPixmapCache::insert(card.getPixmapCacheKey(), finalPixmap); - if (SettingsCache::instance().getSaveCardImagesToLocalStorage()) { + if (SettingsCache::instance().getCardPictureLoaderCacheMethod() == + CardPictureLoaderCacheMethod::CacheMethod::FILESYSTEM_CACHE) { saveCardImageToLocalStorage(card, finalPixmap); } diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h new file mode 100644 index 000000000..ead77fea2 --- /dev/null +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h @@ -0,0 +1,30 @@ +#ifndef COCKATRICE_CARD_PICTURE_LOADER_CACHE_METHOD_H +#define COCKATRICE_CARD_PICTURE_LOADER_CACHE_METHOD_H +#include +#include + +namespace CardPictureLoaderCacheMethod +{ +enum class CacheMethod +{ + NETWORK_CACHE, + FILESYSTEM_CACHE +}; + +struct CacheMethodInfo +{ + CacheMethod id; + QString displayName; +}; + +static inline const QList methods() +{ + static QList all = { + {CacheMethod::NETWORK_CACHE, "Network Cache"}, + {CacheMethod::FILESYSTEM_CACHE, "Filesystem Cache"}, + }; + return all; +} +} // namespace CardPictureLoaderCacheMethod + +#endif // COCKATRICE_CARD_PICTURE_LOADER_CACHE_METHOD_H diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp index a246d74f2..a0f000139 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp @@ -26,10 +26,14 @@ CardPictureLoaderWorker::CardPictureLoaderWorker() cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath()); cache->setMaximumCacheSize(1024L * 1024L * static_cast(SettingsCache::instance().getNetworkCacheSizeInMB())); - // Note: the settings is in MB, but QNetworkDiskCache uses bytes - connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, this, - [this](int newSizeInMB) { cache->setMaximumCacheSize(1024L * 1024L * static_cast(newSizeInMB)); }); + + connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, cache, [this](int newSizeInMB) { + if (cache) + 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); @@ -65,14 +69,19 @@ void CardPictureLoaderWorker::queueRequest(const QUrl &url, CardPictureLoaderWor QUrl cachedRedirect = getCachedRedirect(url); if (!cachedRedirect.isEmpty()) { queueRequest(cachedRedirect, worker); - } else if (cache->metaData(url).isValid()) { - // If we hit a cached url, we get to make the request for free, since it won't contribute towards the rate-limit - makeRequest(url, worker); - } else { - requestLoadQueue.append(qMakePair(url, worker)); - emit imageRequestQueued(url, worker->cardToDownload.getCard(), worker->cardToDownload.getSetName()); - processQueuedRequests(); + return; } + if (SettingsCache::instance().getCardPictureLoaderCacheMethod() == + CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE && + cache->metaData(url).isValid()) { + // If we hit a cached url, we get to make the request for free, since it won't contribute towards the + // rate-limit + makeRequest(url, worker); + return; + } + requestLoadQueue.append(qMakePair(url, worker)); + emit imageRequestQueued(url, worker->cardToDownload.getCard(), worker->cardToDownload.getSetName()); + processQueuedRequests(); } QNetworkReply *CardPictureLoaderWorker::makeRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker) @@ -87,9 +96,12 @@ QNetworkReply *CardPictureLoaderWorker::makeRequest(const QUrl &url, CardPicture QNetworkRequest req(url); req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); req.setRawHeader("Accept", "image/avif,image/webp,image/apng,image/,/*;q=0.8"); - if (!picDownload) { - req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache); - } + + bool useNetworkCache = !picDownload && SettingsCache::instance().getCardPictureLoaderCacheMethod() == + CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE; + + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, + useNetworkCache ? QNetworkRequest::AlwaysCache : QNetworkRequest::AlwaysNetwork); QNetworkReply *reply = networkManager->get(req); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index b5b404246..7f270365e 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1244,6 +1244,41 @@ StorageSettingsPage::StorageSettingsPage() pixmapCacheEdit.setValue(SettingsCache::instance().getPixmapCacheSize()); pixmapCacheEdit.setSuffix(" MB"); + // Caching method + + cardPictureLoaderCacheMethodComboBox = new QComboBox; + for (auto method : CardPictureLoaderCacheMethod::methods()) { + cardPictureLoaderCacheMethodComboBox->addItem(method.displayName, static_cast(method.id)); + } + + int currentCacheMethod = static_cast(SettingsCache::instance().getCardPictureLoaderCacheMethod()); + + int currentIndex = cardPictureLoaderCacheMethodComboBox->findData(currentCacheMethod); + if (currentIndex >= 0) { + cardPictureLoaderCacheMethodComboBox->setCurrentIndex(currentIndex); + } + + connect(cardPictureLoaderCacheMethodComboBox, qOverload(&QComboBox::currentIndexChanged), this, + [this](int index) { + auto cacheMethod = static_cast( + cardPictureLoaderCacheMethodComboBox->itemData(index).toInt()); + + bool useNetworkCache = (cacheMethod == CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE); + + if (useNetworkCache) { + clearImageBackupsButtonClicked(); + } else { + clearDownloadedPicsButtonClicked(); + } + + mpNetworkCacheGroupBox->setEnabled(useNetworkCache); + mpImageBackupGroupBox->setEnabled(!useNetworkCache); + + SettingsCache::instance().setCardImageCacheMethod(cacheMethod); + }); + + // Network Cache + networkCacheEdit.setMinimum(NETWORK_CACHE_SIZE_MIN); networkCacheEdit.setMaximum(NETWORK_CACHE_SIZE_MAX); networkCacheEdit.setSingleStep(1); @@ -1256,10 +1291,6 @@ StorageSettingsPage::StorageSettingsPage() networkRedirectCacheTtlEdit.setValue(SettingsCache::instance().getRedirectCacheTtl()); // Image Backup - saveCardImagesToLocalStorageCheckBox.setChecked(SettingsCache::instance().getSaveCardImagesToLocalStorage()); - connect(&saveCardImagesToLocalStorageCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setSaveCardImagesToLocalStorage); - localCardImageStorageNamingSchemeComboBox = new QComboBox; for (const auto &scheme : CardPictureLoaderLocalSchemes::exportSchemes()) { localCardImageStorageNamingSchemeComboBox->addItem(scheme.displayName, static_cast(scheme.id)); @@ -1281,7 +1312,12 @@ StorageSettingsPage::StorageSettingsPage() connect(&clearBackupsButton, &QPushButton::clicked, this, &StorageSettingsPage::clearImageBackupsButtonClicked); + auto cacheMethodLayout = new QHBoxLayout; + cacheMethodLayout->addWidget(&cardPictureLoaderCacheMethodLabel); + cacheMethodLayout->addWidget(cardPictureLoaderCacheMethodComboBox); + auto networkCacheLayout = new QHBoxLayout; + networkCacheLayout->addWidget(&clearDownloadedPicsButton); networkCacheLayout->addStretch(); networkCacheLayout->addWidget(&networkCacheLabel); networkCacheLayout->addWidget(&networkCacheEdit); @@ -1299,7 +1335,6 @@ StorageSettingsPage::StorageSettingsPage() lpNetworkCacheGrid->addWidget(&networkCacheExplainerLabel, 0, 0); lpNetworkCacheGrid->addLayout(networkCacheLayout, 1, 0); lpNetworkCacheGrid->addLayout(networkRedirectCacheLayout, 2, 0); - lpNetworkCacheGrid->addWidget(&clearDownloadedPicsButton, 3, 0); // Image Backup Layout lpImageBackupGrid->addWidget(&imageBackupExplainerLabel, 0, 0, 1, 2); @@ -1309,7 +1344,7 @@ StorageSettingsPage::StorageSettingsPage() lpImageBackupGrid->addWidget(&clearBackupsButton, 3, 1); lpPixmapCacheGrid->addWidget(&pixmapCacheExplainerLabel, 0, 0); - lpPixmapCacheGrid->addLayout(pixmapCacheLayout, 1, 0); + lpPixmapCacheGrid->addLayout(pixmapCacheLayout, 1, 1); connect(&pixmapCacheEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), &SettingsCache::setPixmapCacheSize); @@ -1318,6 +1353,9 @@ StorageSettingsPage::StorageSettingsPage() connect(&networkRedirectCacheTtlEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), &SettingsCache::setNetworkRedirectCacheTtl); + mpCacheMethodGroupBox = new QGroupBox; + mpCacheMethodGroupBox->setLayout(cacheMethodLayout); + mpNetworkCacheGroupBox = new QGroupBox; mpNetworkCacheGroupBox->setLayout(lpNetworkCacheGrid); @@ -1329,12 +1367,19 @@ StorageSettingsPage::StorageSettingsPage() auto *lpMainLayout = new QVBoxLayout; + lpMainLayout->addWidget(mpCacheMethodGroupBox); lpMainLayout->addWidget(mpNetworkCacheGroupBox); lpMainLayout->addWidget(mpImageBackupGroupBox); lpMainLayout->addWidget(mpPixmapCacheGroupBox); setLayout(lpMainLayout); + bool useNetworkCache = SettingsCache::instance().getCardPictureLoaderCacheMethod() == + CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE; + + mpNetworkCacheGroupBox->setEnabled(useNetworkCache); + mpImageBackupGroupBox->setEnabled(!useNetworkCache); + connect(&SettingsCache::instance(), &SettingsCache::langChanged, this, &StorageSettingsPage::retranslateUi); retranslateUi(); } @@ -1342,6 +1387,7 @@ StorageSettingsPage::StorageSettingsPage() void StorageSettingsPage::clearDownloadedPicsButtonClicked() { CardPictureLoader::clearNetworkCache(); + CardPictureLoader::clearPixmapCache(); QMessageBox::information(this, tr("Success"), tr("Cached card pictures have been reset.")); } @@ -1352,6 +1398,8 @@ void StorageSettingsPage::clearImageBackupsButtonClicked() QDir dir(picsPath); bool success = dir.removeRecursively(); + CardPictureLoader::clearPixmapCache(); + if (success) { QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset.")); } else { @@ -1361,6 +1409,8 @@ void StorageSettingsPage::clearImageBackupsButtonClicked() void StorageSettingsPage::retranslateUi() { + cardPictureLoaderCacheMethodLabel.setText(tr("Card Picture Loader Caching Method:")); + networkCacheExplainerLabel.setText( tr("The network cache is the preferred way of storing images. Downloaded images " "are stored here until the size of the cache exceeds the configured size. Cockatrice automatically monitors " @@ -1383,6 +1433,7 @@ void StorageSettingsPage::retranslateUi() clearDownloadedPicsButton.setText(tr("Delete Cached Images")); clearBackupsButton.setText(tr("Delete Saved Images")); + mpCacheMethodGroupBox->setTitle(tr("Card Picture Loader Cache Method")); mpNetworkCacheGroupBox->setTitle(tr("Network Cache")); mpImageBackupGroupBox->setTitle(tr("Image Backup")); mpPixmapCacheGroupBox->setTitle(tr("In-Memory Picture Cache")); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index 318311f8b..829f21869 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -249,6 +249,7 @@ private: QPushButton clearDownloadedPicsButton; QPushButton clearBackupsButton; + QGroupBox *mpCacheMethodGroupBox; QGroupBox *mpNetworkCacheGroupBox; QGroupBox *mpImageBackupGroupBox; QGroupBox *mpPixmapCacheGroupBox; @@ -257,6 +258,8 @@ private: QLabel imageBackupExplainerLabel; QLabel pixmapCacheExplainerLabel; + QLabel cardPictureLoaderCacheMethodLabel; + QComboBox *cardPictureLoaderCacheMethodComboBox; QLabel networkCacheLabel; QSpinBox networkCacheEdit; QLabel networkRedirectCacheTtlLabel; From c4627bda324d2890f2f030a3f19eed0af1a8b417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 14 Apr 2026 07:49:14 +0200 Subject: [PATCH 7/9] Adjust settings dialog. Took 5 minutes Took 59 seconds Took 22 seconds Took 6 seconds --- .../interface/widgets/dialogs/dlg_settings.cpp | 18 +++++++++++++----- .../interface/widgets/dialogs/dlg_settings.h | 3 ++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 7f270365e..818908706 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1236,6 +1236,8 @@ StorageSettingsPage::StorageSettingsPage() connect(&clearDownloadedPicsButton, &QPushButton::clicked, this, &StorageSettingsPage::clearDownloadedPicsButtonClicked); + connect(&clearPixmapCacheButton, &QPushButton::clicked, this, &StorageSettingsPage::clearPixmapCacheButtonClicked); + // pixmap cache pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN); // 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size) @@ -1328,6 +1330,7 @@ StorageSettingsPage::StorageSettingsPage() networkRedirectCacheLayout->addWidget(&networkRedirectCacheTtlEdit); auto pixmapCacheLayout = new QHBoxLayout; + pixmapCacheLayout->addWidget(&clearPixmapCacheButton); pixmapCacheLayout->addStretch(); pixmapCacheLayout->addWidget(&pixmapCacheLabel); pixmapCacheLayout->addWidget(&pixmapCacheEdit); @@ -1338,10 +1341,9 @@ StorageSettingsPage::StorageSettingsPage() // Image Backup Layout lpImageBackupGrid->addWidget(&imageBackupExplainerLabel, 0, 0, 1, 2); - lpImageBackupGrid->addWidget(&saveCardImagesToLocalStorageCheckBox, 1, 0); - lpImageBackupGrid->addWidget(&localCardImageStorageNamingSchemeLabel, 2, 0); - lpImageBackupGrid->addWidget(localCardImageStorageNamingSchemeComboBox, 2, 1); - lpImageBackupGrid->addWidget(&clearBackupsButton, 3, 1); + lpImageBackupGrid->addWidget(&localCardImageStorageNamingSchemeLabel, 1, 0); + lpImageBackupGrid->addWidget(localCardImageStorageNamingSchemeComboBox, 1, 1); + lpImageBackupGrid->addWidget(&clearBackupsButton, 2, 1); lpPixmapCacheGrid->addWidget(&pixmapCacheExplainerLabel, 0, 0); lpPixmapCacheGrid->addLayout(pixmapCacheLayout, 1, 1); @@ -1407,6 +1409,12 @@ void StorageSettingsPage::clearImageBackupsButtonClicked() } } +void StorageSettingsPage::clearPixmapCacheButtonClicked() +{ + CardPictureLoader::clearPixmapCache(); + QMessageBox::information(this, tr("Success"), tr("In-memory (currently loaded) card pictures have been reset.")); +} + void StorageSettingsPage::retranslateUi() { cardPictureLoaderCacheMethodLabel.setText(tr("Card Picture Loader Caching Method:")); @@ -1432,6 +1440,7 @@ void StorageSettingsPage::retranslateUi() clearDownloadedPicsButton.setText(tr("Delete Cached Images")); clearBackupsButton.setText(tr("Delete Saved Images")); + clearPixmapCacheButton.setText(tr("Clear In-Memory Images")); mpCacheMethodGroupBox->setTitle(tr("Card Picture Loader Cache Method")); mpNetworkCacheGroupBox->setTitle(tr("Network Cache")); @@ -1444,7 +1453,6 @@ void StorageSettingsPage::retranslateUi() networkRedirectCacheTtlEdit.setToolTip(tr("How long cached redirects for urls are valid for.")); pixmapCacheLabel.setText(tr("Picture Cache Size:")); pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen")); - saveCardImagesToLocalStorageCheckBox.setText(tr("Back up downloaded images to local storage")); localCardImageStorageNamingSchemeLabel.setText(tr("Naming scheme:")); networkRedirectCacheTtlEdit.setSuffix(" " + tr("Day(s)")); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index 829f21869..42268e997 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -244,10 +244,12 @@ public: private slots: void clearDownloadedPicsButtonClicked(); void clearImageBackupsButtonClicked(); + void clearPixmapCacheButtonClicked(); private: QPushButton clearDownloadedPicsButton; QPushButton clearBackupsButton; + QPushButton clearPixmapCacheButton; QGroupBox *mpCacheMethodGroupBox; QGroupBox *mpNetworkCacheGroupBox; @@ -266,7 +268,6 @@ private: QSpinBox networkRedirectCacheTtlEdit; QSpinBox pixmapCacheEdit; QLabel pixmapCacheLabel; - QCheckBox saveCardImagesToLocalStorageCheckBox; QLabel localCardImageStorageNamingSchemeLabel; QComboBox *localCardImageStorageNamingSchemeComboBox; }; From 9314d4ab5cf9d0e2859bcef73a039dd65f3ebcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 14 Apr 2026 07:52:09 +0200 Subject: [PATCH 8/9] tr() strings Took 1 minute Took 6 seconds --- .../card_picture_loader/card_picture_loader_cache_method.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h index ead77fea2..43f42ff12 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_cache_method.h @@ -1,5 +1,6 @@ #ifndef COCKATRICE_CARD_PICTURE_LOADER_CACHE_METHOD_H #define COCKATRICE_CARD_PICTURE_LOADER_CACHE_METHOD_H +#include #include #include @@ -20,8 +21,9 @@ struct CacheMethodInfo static inline const QList methods() { static QList all = { - {CacheMethod::NETWORK_CACHE, "Network Cache"}, - {CacheMethod::FILESYSTEM_CACHE, "Filesystem Cache"}, + {CacheMethod::NETWORK_CACHE, QCoreApplication::translate("CardPictureLoaderCacheMethod", "Network Cache")}, + {CacheMethod::FILESYSTEM_CACHE, + QCoreApplication::translate("CardPictureLoaderCacheMethod", "Filesystem Cache")}, }; return all; } From 8bbcac708fb92fdd53251a0bf22d1de97fe6b026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 14 Apr 2026 07:56:54 +0200 Subject: [PATCH 9/9] Readjust layout, default naming scheme. Took 5 minutes --- cockatrice/src/client/settings/cache_settings.cpp | 2 +- cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp index 910f82535..fc3f7ce31 100644 --- a/cockatrice/src/client/settings/cache_settings.cpp +++ b/cockatrice/src/client/settings/cache_settings.cpp @@ -274,7 +274,7 @@ SettingsCache::SettingsCache() localCardImageStorageNamingScheme = settings ->value("personal/localCardImageStorageNamingScheme", - static_cast(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_ProviderId)) + static_cast(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_Set_Collector)) .toInt(); picDownload = settings->value("personal/picturedownload", true).toBool(); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 818908706..eed9acf39 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -1343,10 +1343,10 @@ StorageSettingsPage::StorageSettingsPage() lpImageBackupGrid->addWidget(&imageBackupExplainerLabel, 0, 0, 1, 2); lpImageBackupGrid->addWidget(&localCardImageStorageNamingSchemeLabel, 1, 0); lpImageBackupGrid->addWidget(localCardImageStorageNamingSchemeComboBox, 1, 1); - lpImageBackupGrid->addWidget(&clearBackupsButton, 2, 1); + lpImageBackupGrid->addWidget(&clearBackupsButton, 2, 0); lpPixmapCacheGrid->addWidget(&pixmapCacheExplainerLabel, 0, 0); - lpPixmapCacheGrid->addLayout(pixmapCacheLayout, 1, 1); + lpPixmapCacheGrid->addLayout(pixmapCacheLayout, 1, 0); connect(&pixmapCacheEdit, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), &SettingsCache::setPixmapCacheSize);