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