Cockatrice/cockatrice/src/interface/card_picture_loader/card_picture_loader.h
BruebachL cca4af0ec7
[PictureLoader] Add local override storage and resolution with matcher tests (#7311)
* [PictureLoader] Add local override storage and resolution with matcher tests

* [PictureLoader] Address review comments

- Make deleteAllLocalOverrides static; it does not touch instance state
- Drop the now-unused hasCustomArt dead code
- Rename the override install methods to installPrintingOverride /
  installPrintingOverrideOnLoad

* [Tests] Give loader matcher tests a writable HOME in CI

Under GitHub's docker runner the process uid has no passwd entry, so HOME
resolves to '/' and the test-mode qttest data dir cannot be created.
SettingsCache's QSettings then drops every write, getPicsPath() comes back
empty, and the loader searches a blank path. Point HOME at a QTemporaryDir
for the duration of the run.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-09-18 15:03:08 +02:00

154 lines
5.4 KiB
C++

#ifndef CARD_PICTURE_LOADER_H
#define CARD_PICTURE_LOADER_H
#include "card_picture_loader_status_bar.h"
#include "card_picture_loader_worker.h"
#include <QDateTime>
#include <QHash>
#include <QLoggingCategory>
inline Q_LOGGING_CATEGORY(CardPictureLoaderLog, "card_picture_loader");
inline Q_LOGGING_CATEGORY(CardPictureLoaderCardBackCacheFailLog, "card_picture_loader.card_back_cache_fail");
/**
* @class CardPictureLoader
* @ingroup PictureLoader
* @brief Singleton class to manage card image loading and caching. Provides functionality to asynchronously load,
* cache, and manage card images for the client.
*
* This class is a singleton and handles:
* - Loading card images from disk or network.
* - Caching images in QPixmapCache for fast reuse.
* - Providing themed card backs, including fallback and in-progress/failed states.
* - Emitting updates when pixmaps are loaded.
*
* It interacts with CardPictureLoaderWorker for background loading and
* CardPictureLoaderStatusBar to display loading progress in the main window.
*
* Provides static accessors for:
* - Card images by ExactCard.
* - Card back images (normal, in-progress, failed).
* - Cache management (clearPixmapCache(), clearNetworkCache(), cacheCardPixmaps(const QList<ExactCard> &cards)).
*
* Uses a worker thread for asynchronous image loading and a status bar widget
* to track load progress.
*/
class CardPictureLoader : public QObject
{
Q_OBJECT
public:
/**
* @brief Access the singleton instance of CardPictureLoader.
* @return Reference to the singleton.
*/
static CardPictureLoader &getInstance()
{
static CardPictureLoader instance;
return instance;
}
private:
explicit CardPictureLoader();
~CardPictureLoader() override;
// Disable copy and assignment for singleton
CardPictureLoader(CardPictureLoader const &) = delete;
void operator=(CardPictureLoader const &) = delete;
CardPictureLoaderWorker *worker; ///< Worker thread for async image loading
CardPictureLoaderStatusBar *statusBar; ///< Status bar widget showing load progress
QHash<QString, QDateTime> failedAt; ///< Timestamp of the last failed load attempt per pixmap cache key
public:
/**
* @brief Retrieve a card pixmap, either from cache or enqueued for loading.
* @param pixmap Reference to QPixmap where result will be stored.
* @param card ExactCard to load.
* @param size Desired size of pixmap.
*/
static void getPixmap(QPixmap &pixmap, const ExactCard &card, QSize size);
/**
* @brief Retrieve a generic card back pixmap.
* @param pixmap Reference to QPixmap where result will be stored.
* @param size Desired size of pixmap.
*/
static void getCardBackPixmap(QPixmap &pixmap, QSize size);
/**
* @brief Retrieve a card back pixmap for the loading-in-progress state.
* @param pixmap Reference to QPixmap where result will be stored.
* @param size Desired size of pixmap.
*/
static void getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSize size);
/**
* @brief Retrieve a card back pixmap for the loading-failed state.
* @param pixmap Reference to QPixmap where result will be stored.
* @param size Desired size of pixmap.
*/
static void getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize size);
/**
* @brief Preload a list of cards into the pixmap cache (limited to CACHED_CARD_PER_DECK_MAX).
* @param cards List of ExactCard objects to preload.
*/
static void cacheCardPixmaps(const QList<ExactCard> &cards);
/**
* @brief Check if a local override image already exists for the card.
* @param card The card to check.
* @return True if the card has at least one locally stored override image.
*/
static bool hasLocalOverrides(const ExactCard &card);
/**
* @brief Removes all locally stored override images for the card.
* @param card The card to remove the override images of.
*/
static void deleteAllLocalOverrides(const ExactCard &card);
/**
* @brief Clears the in-memory QPixmap cache for all cards.
*/
static void clearPixmapCache();
public slots:
/**
* @brief Clears the network disk cache of the worker.
*/
static void clearNetworkCache();
/**
* @brief Slot called by the worker when an image is loaded.
* Inserts the pixmap into the cache and emits pixmap updated signals.
* @param card ExactCard that was loaded.
* @param image Loaded QImage.
*/
void imageLoaded(const ExactCard &card, const QImage &image);
void saveCardImageToLocalStorage(const ExactCard &card, const QPixmap &pixmap, bool allowOverwrite = false);
void installPrintingOverride(const ExactCard &originalCard, const ExactCard &overrideCard);
void installPrintingOverrideOnLoad(const ExactCard &originalCard, const ExactCard &overrideCard);
private slots:
/**
* @brief Triggered when the user changes the picture download settings.
* Clears the QPixmap cache to reload images.
*/
void picDownloadChanged();
/**
* @brief Triggered when the pictures path changes.
* Clears the QPixmap cache to reload images.
*/
void picsPathChanged();
/**
* @brief Triggered when the card language setting changes.
* Clears the in-memory picture caches so images reload in the new language.
*/
void cardLangChanged();
};
#endif