Cockatrice/cockatrice/src/settingscache.h
Basile Clement c14936c63c
PictureLoader: Replace downloadedPics cache with QNetworkCache (#4756)
* PictureLoader: Replace downloadedPics cache with QNetworkCache

Currently when the "Download card pictures on the fly" option is
enabled, Cockatrice stores downloaded pictures into a downloadedPics
sub-folder, keyed on set and card name. If a picture is found in that
folder, we never try to download a picture for that card ever again
(until it is reprinted in a more recent set, I guess).

This has the unfortunate consequence that if you change the URLs for
downloading card images, the changes are not applied to cards that
already have their picture downloaded. In particular, if you use
localized card pictures (through !sflang!), you get a mix of cards in
different languages depending on the currently configured language at
the time each card was downloaded.

This patch removes that mechanism in favor of setting a
QNetworkDiskCache on the QNetworkAccessManager used by the PictureLoader
to download pictures. The QNetworkDiskCache caches the picture keyed on
their URL: if the URL changes, a new request will be made. In
particular, if you use picture URLs with !sflang! and change the
language, pictures for the current language will be downloaded even for
cards that already have a picture. The QNetworkDiskCache is configured
with a maximum size of 4GB, which should be enough to hold one
high-quality JPEG for each M:TG card in existence.

Note that this does not affect the existing mechanism for defining
custom card art, either through the CUSTOM directory or the set-based
one.  Cockatrice will still read existing cards in the downloadedPics
directory as before, it will just no longer write into that directory
(since pictures are cached by the QNetworkDiskCache instead). To fully
switch to the new cache, users should use the "Delete Downloaded Images"
button in the settings: it will clear the QNetworkDiskCache but also
remove the downloadedPics directory.

* Do not use system cache dir for portable installs

* Add settings for network cache size

* Delete corrupted cache entries

* Use old-style connect() syntax (Qt5 build failure)

* Add setNetworkCacheSizeInMB to test mocks

* setTransferTimeout was added in Qt 5.15

* Improve logging messages

We now have the following messages

 - "Trying to download picture from url: URL" before loading a picture
   when picture download is enabled
 - "Trying to load picture from cache: URL" before loading a picture
   when picture download is disabled (i.e. cache-only offline mode)
 - "Removing corrupted cache file for url URL and retrying (ERR)" when
   when we fail to load a picture from the cache. Usually, this should
   be due to the timeout, in which case ERR will be "Operation
   Canceled".
 - "Download failed for url URL (ERR)" when there was an error
   downloading a picture from the network (ERR is the error message)
 - "Following redirect to URL" and "Following cached redirect to URL"
   when following a redirect (from network/from cache)
 - "Image successfully downloaded from URL" and "Image successfully
   loaded from cached url at URL" on success
 - "Possible cached/downloaded picture at URL could not be loaded" on
   ImageReader error

* Clarify that network cache is on disk

Also migrate "Delete Downloaded Image" to a "Clear" button right next to
the network cache size.

* Remove qPrintable

* Move pixmap cache settings to card sources

* qDebug().nospace()

* some formatting on debug messages

* format

* inverted condition

---------

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2023-03-03 16:55:17 +01:00

562 lines
16 KiB
C++

#ifndef SETTINGSCACHE_H
#define SETTINGSCACHE_H
#include "settings/carddatabasesettings.h"
#include "settings/downloadsettings.h"
#include "settings/gamefilterssettings.h"
#include "settings/layoutssettings.h"
#include "settings/messagesettings.h"
#include "settings/serverssettings.h"
#include "shortcutssettings.h"
#include <QObject>
#include <QSize>
#include <QStringList>
class ReleaseChannel;
// size should be a multiple of 64
#define PIXMAPCACHE_SIZE_DEFAULT 2047
#define PIXMAPCACHE_SIZE_MIN 64
#define PIXMAPCACHE_SIZE_MAX 2047
// In MB
constexpr int NETWORK_CACHE_SIZE_DEFAULT = 1024 * 4; // 4 GB
constexpr int NETWORK_CACHE_SIZE_MIN = 1; // 1 MB
constexpr int NETWORK_CACHE_SIZE_MAX = 1024 * 1024; // 1 TB
#define DEFAULT_LANG_NAME "English"
#define CLIENT_INFO_NOT_SET "notset"
#define DEFAULT_FONT_SIZE 12
class QSettings;
class SettingsCache : public QObject
{
Q_OBJECT
signals:
void langChanged();
void picsPathChanged();
void cardDatabasePathChanged();
void themeChanged();
void picDownloadChanged();
void displayCardNamesChanged();
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
void minPlayersForMultiColumnLayoutChanged();
void soundEnabledChanged();
void soundThemeChanged();
void ignoreUnregisteredUsersChanged();
void ignoreUnregisteredUserMessagesChanged();
void pixmapCacheSizeChanged(int newSizeInMBs);
void networkCacheSizeChanged(int newSizeInMBs);
void masterVolumeChanged(int value);
void chatMentionCompleterChanged();
void downloadSpoilerTimeIndexChanged();
void downloadSpoilerStatusChanged();
void useTearOffMenusChanged(bool state);
private:
QSettings *settings;
ShortcutsSettings *shortcutsSettings;
CardDatabaseSettings *cardDatabaseSettings;
ServersSettings *serversSettings;
MessageSettings *messageSettings;
GameFiltersSettings *gameFiltersSettings;
LayoutsSettings *layoutsSettings;
DownloadSettings *downloadSettings;
QByteArray mainWindowGeometry;
QByteArray tokenDialogGeometry;
QString lang;
QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath, themesPath,
spoilerDatabasePath, tokenDatabasePath, themeName;
bool notifyAboutUpdates;
bool notifyAboutNewVersion;
bool showTipsOnStartup;
QList<int> seenTips;
bool mbDownloadSpoilers;
int updateReleaseChannel;
int maxFontSize;
bool picDownload;
bool notificationsEnabled;
bool spectatorNotificationsEnabled;
bool buddyConnectNotificationsEnabled;
bool doubleClickToPlay;
bool playToStack;
int startingHandSize;
bool annotateTokens;
QByteArray tabGameSplitterSizes;
bool displayCardNames;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
bool tapAnimation;
bool chatMention;
bool chatMentionCompleter;
QString chatMentionColor;
QString chatHighlightColor;
bool chatMentionForeground;
bool chatHighlightForeground;
bool zoneViewSortByName, zoneViewSortByType, zoneViewPileView;
bool soundEnabled;
QString soundThemeName;
bool ignoreUnregisteredUsers;
bool ignoreUnregisteredUserMessages;
QString picUrl;
QString picUrlFallback;
QString clientID;
QString clientVersion;
QString knownMissingFeatures;
bool useTearOffMenus;
int pixmapCacheSize;
int networkCacheSize;
bool scaleCards;
bool showMessagePopups;
bool showMentionPopups;
bool roomHistory;
bool leftJustified;
int masterVolume;
int cardInfoViewMode;
QString highlightWords;
QString gameDescription;
int maxPlayers;
QString gameTypes;
bool onlyBuddies;
bool onlyRegistered;
bool spectatorsAllowed;
bool spectatorsNeedPassword;
bool spectatorsCanTalk;
bool spectatorsCanSeeEverything;
bool createGameAsSpectator;
int keepalive;
void translateLegacySettings();
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
void loadPaths();
bool rememberGameSettings;
QList<ReleaseChannel *> releaseChannels;
bool isPortableBuild;
public:
SettingsCache();
QString getDataPath();
QString getSettingsPath();
QString getCachePath() const;
QString getNetworkCachePath() const;
const QByteArray &getMainWindowGeometry() const
{
return mainWindowGeometry;
}
const QByteArray &getTokenDialogGeometry() const
{
return tokenDialogGeometry;
}
QString getLang() const
{
return lang;
}
QString getDeckPath() const
{
return deckPath;
}
QString getReplaysPath() const
{
return replaysPath;
}
QString getThemesPath() const
{
return themesPath;
}
QString getPicsPath() const
{
return picsPath;
}
QString getCustomPicsPath() const
{
return customPicsPath;
}
QString getCustomCardDatabasePath() const
{
return customCardDatabasePath;
}
QString getCardDatabasePath() const
{
return cardDatabasePath;
}
QString getSpoilerCardDatabasePath() const
{
return spoilerDatabasePath;
}
QString getTokenDatabasePath() const
{
return tokenDatabasePath;
}
QString getThemeName() const
{
return themeName;
}
QString getChatMentionColor() const
{
return chatMentionColor;
}
QString getChatHighlightColor() const
{
return chatHighlightColor;
}
bool getPicDownload() const
{
return picDownload;
}
bool getNotificationsEnabled() const
{
return notificationsEnabled;
}
bool getSpectatorNotificationsEnabled() const
{
return spectatorNotificationsEnabled;
}
bool getBuddyConnectNotificationsEnabled() const
{
return buddyConnectNotificationsEnabled;
}
bool getNotifyAboutUpdates() const
{
return notifyAboutUpdates;
}
bool getNotifyAboutNewVersion() const
{
return notifyAboutNewVersion;
}
bool getShowTipsOnStartup() const
{
return showTipsOnStartup;
}
QList<int> getSeenTips() const
{
return seenTips;
}
ReleaseChannel *getUpdateReleaseChannel() const
{
return releaseChannels.at(updateReleaseChannel);
}
QList<ReleaseChannel *> getUpdateReleaseChannels() const
{
return releaseChannels;
}
bool getDoubleClickToPlay() const
{
return doubleClickToPlay;
}
bool getPlayToStack() const
{
return playToStack;
}
int getStartingHandSize() const
{
return startingHandSize;
}
bool getAnnotateTokens() const
{
return annotateTokens;
}
QByteArray getTabGameSplitterSizes() const
{
return tabGameSplitterSizes;
}
bool getDisplayCardNames() const
{
return displayCardNames;
}
bool getHorizontalHand() const
{
return horizontalHand;
}
bool getInvertVerticalCoordinate() const
{
return invertVerticalCoordinate;
}
int getMinPlayersForMultiColumnLayout() const
{
return minPlayersForMultiColumnLayout;
}
bool getTapAnimation() const
{
return tapAnimation;
}
bool getChatMention() const
{
return chatMention;
}
bool getChatMentionCompleter() const
{
return chatMentionCompleter;
}
bool getChatMentionForeground() const
{
return chatMentionForeground;
}
bool getChatHighlightForeground() const
{
return chatHighlightForeground;
}
bool getZoneViewSortByName() const
{
return zoneViewSortByName;
}
bool getZoneViewSortByType() const
{
return zoneViewSortByType;
}
/**
Returns if the view should be sorted into pile view.
@return zoneViewPileView if the view should be sorted into pile view.
*/
bool getZoneViewPileView() const
{
return zoneViewPileView;
}
bool getSoundEnabled() const
{
return soundEnabled;
}
QString getSoundThemeName() const
{
return soundThemeName;
}
bool getIgnoreUnregisteredUsers() const
{
return ignoreUnregisteredUsers;
}
bool getIgnoreUnregisteredUserMessages() const
{
return ignoreUnregisteredUserMessages;
}
int getPixmapCacheSize() const
{
return pixmapCacheSize;
}
int getNetworkCacheSizeInMB() const
{
return networkCacheSize;
}
bool getScaleCards() const
{
return scaleCards;
}
bool getShowMessagePopup() const
{
return showMessagePopups;
}
bool getShowMentionPopup() const
{
return showMentionPopups;
}
bool getRoomHistory() const
{
return roomHistory;
}
bool getLeftJustified() const
{
return leftJustified;
}
int getMasterVolume() const
{
return masterVolume;
}
int getCardInfoViewMode() const
{
return cardInfoViewMode;
}
QStringList getCountries() const;
QString getHighlightWords() const
{
return highlightWords;
}
QString getGameDescription() const
{
return gameDescription;
}
int getMaxPlayers() const
{
return maxPlayers;
}
QString getGameTypes() const
{
return gameTypes;
}
bool getOnlyBuddies() const
{
return onlyBuddies;
}
bool getOnlyRegistered() const
{
return onlyRegistered;
}
bool getSpectatorsAllowed() const
{
return spectatorsAllowed;
}
bool getSpectatorsNeedPassword() const
{
return spectatorsNeedPassword;
}
bool getSpectatorsCanTalk() const
{
return spectatorsCanTalk;
}
bool getSpectatorsCanSeeEverything() const
{
return spectatorsCanSeeEverything;
}
bool getCreateGameAsSpectator() const
{
return createGameAsSpectator;
}
bool getRememberGameSettings() const
{
return rememberGameSettings;
}
int getKeepAlive() const
{
return keepalive;
}
int getMaxFontSize() const
{
return maxFontSize;
}
void setClientID(const QString &clientID);
void setClientVersion(const QString &clientVersion);
void setKnownMissingFeatures(const QString &_knownMissingFeatures);
void setUseTearOffMenus(bool _useTearOffMenus);
QString getClientID()
{
return clientID;
}
QString getClientVersion()
{
return clientVersion;
}
QString getKnownMissingFeatures()
{
return knownMissingFeatures;
}
bool getUseTearOffMenus()
{
return useTearOffMenus;
}
ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
}
CardDatabaseSettings &cardDatabase() const
{
return *cardDatabaseSettings;
}
ServersSettings &servers() const
{
return *serversSettings;
}
MessageSettings &messages() const
{
return *messageSettings;
}
GameFiltersSettings &gameFilters() const
{
return *gameFiltersSettings;
}
LayoutsSettings &layouts() const
{
return *layoutsSettings;
}
DownloadSettings &downloads() const
{
return *downloadSettings;
}
bool getIsPortableBuild() const
{
return isPortableBuild;
}
bool getDownloadSpoilersStatus() const
{
return mbDownloadSpoilers;
}
static SettingsCache &instance();
void resetPaths();
public slots:
void setDownloadSpoilerStatus(bool _spoilerStatus);
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
void setTokenDialogGeometry(const QByteArray &_tokenDialog);
void setLang(const QString &_lang);
void setShowTipsOnStartup(bool _showTipsOnStartup);
void setSeenTips(const QList<int> &_seenTips);
void setDeckPath(const QString &_deckPath);
void setReplaysPath(const QString &_replaysPath);
void setThemesPath(const QString &_themesPath);
void setCustomCardDatabasePath(const QString &_customCardDatabasePath);
void setPicsPath(const QString &_picsPath);
void setCardDatabasePath(const QString &_cardDatabasePath);
void setSpoilerDatabasePath(const QString &_spoilerDatabasePath);
void setTokenDatabasePath(const QString &_tokenDatabasePath);
void setThemeName(const QString &_themeName);
void setChatMentionColor(const QString &_chatMentionColor);
void setChatHighlightColor(const QString &_chatHighlightColor);
void setPicDownload(int _picDownload);
void setNotificationsEnabled(int _notificationsEnabled);
void setSpectatorNotificationsEnabled(int _spectatorNotificationsEnabled);
void setBuddyConnectNotificationsEnabled(int _buddyConnectNotificationsEnabled);
void setDoubleClickToPlay(int _doubleClickToPlay);
void setPlayToStack(int _playToStack);
void setStartingHandSize(int _startingHandSize);
void setAnnotateTokens(int _annotateTokens);
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
void setDisplayCardNames(int _displayCardNames);
void setHorizontalHand(int _horizontalHand);
void setInvertVerticalCoordinate(int _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
void setTapAnimation(int _tapAnimation);
void setChatMention(int _chatMention);
void setChatMentionCompleter(int _chatMentionCompleter);
void setChatMentionForeground(int _chatMentionForeground);
void setChatHighlightForeground(int _chatHighlightForeground);
void setZoneViewSortByName(int _zoneViewSortByName);
void setZoneViewSortByType(int _zoneViewSortByType);
void setZoneViewPileView(int _zoneViewPileView);
void setSoundEnabled(int _soundEnabled);
void setSoundThemeName(const QString &_soundThemeName);
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
void setPixmapCacheSize(const int _pixmapCacheSize);
void setNetworkCacheSizeInMB(const int _networkCacheSize);
void setCardScaling(const int _scaleCards);
void setShowMessagePopups(const int _showMessagePopups);
void setShowMentionPopups(const int _showMentionPopups);
void setRoomHistory(const int _roomHistory);
void setLeftJustified(const int _leftJustified);
void setMasterVolume(const int _masterVolume);
void setCardInfoViewMode(const int _viewMode);
void setHighlightWords(const QString &_highlightWords);
void setGameDescription(const QString _gameDescription);
void setMaxPlayers(const int _maxPlayers);
void setGameTypes(const QString _gameTypes);
void setOnlyBuddies(const bool _onlyBuddies);
void setOnlyRegistered(const bool _onlyRegistered);
void setSpectatorsAllowed(const bool _spectatorsAllowed);
void setSpectatorsNeedPassword(const bool _spectatorsNeedPassword);
void setSpectatorsCanTalk(const bool _spectatorsCanTalk);
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
void setCreateGameAsSpectator(const bool _createGameAsSpectator);
void setRememberGameSettings(const bool _rememberGameSettings);
void setNotifyAboutUpdate(int _notifyaboutupdate);
void setNotifyAboutNewVersion(int _notifyaboutnewversion);
void setUpdateReleaseChannel(int _updateReleaseChannel);
void setMaxFontSize(int _max);
};
#endif