[Doxygen] Card Picture Loader (#6315)

* [Doxygen] Card Picture Loader

Took 25 minutes

Took 16 minutes

# Commit time for manual adjustment:
# Took 12 seconds


Took 14 seconds

* Remove placeholder file description.

Took 1 minute

* ... but do group PictureLoader again

Took 28 seconds

* Link to methods directly.

Took 6 minutes

* Forward declaration.

Took 49 seconds

* Remove redundant .cpp function documentation.

Took 15 minutes

* More fixes.

Took 7 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL
2025-11-15 17:26:32 +01:00
committed by GitHub
parent ace4063371
commit 827f22ed37
11 changed files with 435 additions and 152 deletions

View File

@@ -1,9 +1,3 @@
/**
* @file card_picture_loader.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef CARD_PICTURE_LOADER_H
#define CARD_PICTURE_LOADER_H
@@ -16,10 +10,37 @@
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;
@@ -29,30 +50,87 @@ public:
private:
explicit CardPictureLoader();
~CardPictureLoader() override;
// Singleton - Don't implement copy constructor and assign operator
CardPictureLoader(CardPictureLoader const &);
void operator=(CardPictureLoader const &);
CardPictureLoaderWorker *worker;
CardPictureLoaderStatusBar *statusBar;
// 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
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);
static void clearPixmapCache();
/**
* @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 the user has custom card art in the picsPath directory.
* @return True if any custom art exists.
*/
static bool hasCustomArt();
/**
* @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();
private slots:
void picDownloadChanged();
void picsPathChanged();
public slots:
/**
* @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);
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();
};
#endif

View File

@@ -47,12 +47,6 @@ void CardPictureLoaderLocal::refreshIndex()
<< customFolderIndex.size() << "entries.";
}
/**
* Tries to load the card image from the local images.
*
* @param toLoad The card to load
* @return The loaded image, or an empty QImage if loading failed.
*/
QImage CardPictureLoaderLocal::tryLoad(const ExactCard &toLoad) const
{
PrintingInfo setInstance = toLoad.getPrinting();

View File

@@ -1,9 +1,3 @@
/**
* @file card_picture_loader_local.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef PICTURE_LOADER_LOCAL_H
#define PICTURE_LOADER_LOCAL_H
@@ -15,32 +9,80 @@
inline Q_LOGGING_CATEGORY(CardPictureLoaderLocalLog, "card_picture_loader.local");
/**
* Handles searching for and loading card images from the local pics and custom image folders.
* This class maintains an index of the CUSTOM folder, to avoid repeatedly searching the entire directory.
* @class CardPictureLoaderLocal
* @ingroup PictureLoader
* @brief Handles searching for and loading card images from local and custom image folders.
*
* This class maintains an index of the CUSTOM folder to avoid repeatedly scanning
* directories, and supports periodic refreshes to update the index.
*
* Responsibilities:
* - Load images for ExactCard objects from local disk or custom folders.
* - Maintain an index for fast lookup of images in the CUSTOM folder.
* - Refresh the index periodically to account for changes in local image directories.
*/
class CardPictureLoaderLocal : public QObject
{
Q_OBJECT
public:
/**
* @brief Constructs a CardPictureLoaderLocal object.
* @param parent Optional parent QObject.
*
* Initializes paths from SettingsCache, connects to settings change signals,
* builds the initial folder index, and starts a periodic refresh timer.
*/
explicit CardPictureLoaderLocal(QObject *parent);
/**
* @brief Attempts to load a card image from local disk or custom folders.
* @param toLoad ExactCard object representing the card to load.
* @return Loaded QImage if found; otherwise, an empty QImage.
*
* Uses a set of name variants and folder paths to attempt to locate the correct image.
*/
QImage tryLoad(const ExactCard &toLoad) const;
private:
QString picsPath, customPicsPath;
QString picsPath; ///< Path to standard card image folder
QString customPicsPath; ///< Path to custom card image folder
QMultiHash<QString, QString> customFolderIndex; // multimap of cardName to picPaths
QTimer *refreshTimer;
QMultiHash<QString, QString> customFolderIndex; ///< Multimap from cardName to file paths in CUSTOM folder
QTimer *refreshTimer; ///< Timer for periodic folder index refresh
/**
* @brief Rebuilds the index of the custom image folder.
*
* Iterates through all subdirectories of the CUSTOM folder and populates
* `customFolderIndex` with all discovered image files keyed by base name
* and complete base name.
*/
void refreshIndex();
/**
* @brief Attempts to load a card image from disk given its set and name info.
* @param setName Corrected short name of the card's set.
* @param correctedCardName Corrected card name (e.g., normalized name).
* @param collectorNumber Collector number of the card.
* @param providerId Optional provider UUID of the card.
* @return Loaded QImage if found; otherwise, an empty QImage.
*
* Searches in both the custom folder index and standard pictures paths.
* Uses several filename patterns to match card images, in order from
* most-specific to least-specific.
*/
QImage tryLoadCardImageFromDisk(const QString &setName,
const QString &correctedCardName,
const QString &collectorNumber,
const QString &providerId) const;
private slots:
/**
* @brief Updates internal paths when the user changes picture settings.
*
* Triggered by `SettingsCache::picsPathChanged`.
*/
void picsPathChanged();
};

View File

@@ -1,26 +1,43 @@
/**
* @file card_picture_loader_request_status_display_widget.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
#include "card_picture_loader_worker_work.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QWidget>
/**
* @class CardPictureLoaderRequestStatusDisplayWidget
* @ingroup PictureLoader
* @brief A small widget to display the status of a single card image request.
*
* Displays:
* - Card name
* - Set short name
* - Provider ID
* - Start time of request
* - Elapsed time since start
* - Finished status
* - URL of the requested image
*/
class CardPictureLoaderRequestStatusDisplayWidget : public QWidget
{
Q_OBJECT
public:
/**
* @brief Constructs a new status widget for a specific card image request.
* @param parent Parent widget
* @param url URL of the image being requested
* @param card The ExactCard being downloaded
* @param setName Set name for the card
*/
CardPictureLoaderRequestStatusDisplayWidget(QWidget *parent,
const QUrl &url,
const ExactCard &card,
const QString &setName);
/** Marks the request as finished */
void setFinished()
{
finished->setText("True");
@@ -28,19 +45,25 @@ public:
repaint();
}
/** Returns whether the request has finished */
bool getFinished() const
{
return finished->text() == "True";
}
/** Updates the elapsed time display */
void setElapsedTime(const QString &_elapsedTime) const
{
elapsedTime->setText(_elapsedTime);
}
/**
* @brief Queries the elapsed time in seconds since the request started
* @return Elapsed time in seconds
*/
int queryElapsedSeconds()
{
if (!finished) {
if (!getFinished()) {
int elapsedSeconds = QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime());
elapsedTime->setText(QString::number(elapsedSeconds));
update();
@@ -50,25 +73,27 @@ public:
return elapsedTime->text().toInt();
}
/** Returns the start time as a string */
QString getStartTime() const
{
return startTime->text();
}
/** Returns the URL of the request */
QString getUrl() const
{
return url->text();
}
private:
QHBoxLayout *layout;
QLabel *name;
QLabel *setShortname;
QLabel *providerId;
QLabel *startTime;
QLabel *elapsedTime;
QLabel *finished;
QLabel *url;
QHBoxLayout *layout; ///< Horizontal layout for arranging labels
QLabel *name; ///< Card name
QLabel *setShortname; ///< Set short name
QLabel *providerId; ///< Provider ID for the card
QLabel *startTime; ///< Start time of the request
QLabel *elapsedTime; ///< Elapsed time since start
QLabel *finished; ///< Whether the request has finished
QLabel *url; ///< URL of the requested image
};
#endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H

View File

@@ -1,9 +1,3 @@
/**
* @file card_picture_loader_status_bar.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef PICTURE_LOADER_STATUS_BAR_H
#define PICTURE_LOADER_STATUS_BAR_H
@@ -12,24 +6,56 @@
#include <QHBoxLayout>
#include <QProgressBar>
#include <QTimer>
#include <QWidget>
/**
* @class CardPictureLoaderStatusBar
* @ingroup PictureLoader
* @brief Displays the status of card image downloads in a horizontal progress bar with a log popup.
*
* Responsibilities:
* - Shows overall progress of image downloads.
* - Maintains a log of individual requests via a popup (SettingsButtonWidget).
* - Cleans up finished request entries automatically after a delay.
*/
class CardPictureLoaderStatusBar : public QWidget
{
Q_OBJECT
public:
/**
* @brief Constructs a status bar with progress bar and log button.
* @param parent Parent widget
*/
explicit CardPictureLoaderStatusBar(QWidget *parent);
public slots:
/**
* @brief Adds a queued image download to the log and increments the progress bar maximum.
* @param url URL of the image
* @param card The card being loaded
* @param setName The set name of the card
*/
void addQueuedImageLoad(const QUrl &url, const ExactCard &card, const QString &setName);
/**
* @brief Marks an image as successfully loaded.
* Updates the progress bar and marks the corresponding log entry as finished.
* @param url URL of the successfully loaded image
*/
void addSuccessfulImageLoad(const QUrl &url);
/**
* @brief Cleans up old entries from the log that have finished more than 10 seconds ago.
* Adjusts the progress bar accordingly.
*/
void cleanOldEntries();
private:
QHBoxLayout *layout;
QProgressBar *progressBar;
SettingsButtonWidget *loadLog;
QTimer *cleaner;
QHBoxLayout *layout; ///< Horizontal layout containing progress bar and log button
QProgressBar *progressBar; ///< Progress bar showing overall download progress
SettingsButtonWidget *loadLog; ///< Popup log showing individual request statuses
QTimer *cleaner; ///< Timer for periodically cleaning old log entries
};
#endif // PICTURE_LOADER_STATUS_BAR_H

View File

@@ -105,9 +105,6 @@ void CardPictureLoaderWorker::resetRequestQuota()
processQueuedRequests();
}
/**
* Keeps processing requests from the queue until it is empty or until the quota runs out.
*/
void CardPictureLoaderWorker::processQueuedRequests()
{
while (requestQuota > 0 && processSingleRequest()) {
@@ -115,10 +112,6 @@ void CardPictureLoaderWorker::processQueuedRequests()
}
}
/**
* Immediately processes a single queued request. No-ops if the load queue is empty
* @return If a request was processed
*/
bool CardPictureLoaderWorker::processSingleRequest()
{
if (!requestLoadQueue.isEmpty()) {

View File

@@ -1,9 +1,3 @@
/**
* @file card_picture_loader_worker.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef PICTURE_LOADER_WORKER_H
#define PICTURE_LOADER_WORKER_H
@@ -27,57 +21,131 @@
#define REDIRECT_TIMESTAMP "timestamp"
#define REDIRECT_CACHE_FILENAME "cache.ini"
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerLog, "card_picture_loader.worker");
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerLog, "card_picture_loader.worker")
class CardPictureLoaderWorkerWork;
class CardPictureLoaderWorkerWork;
/**
* @class CardPictureLoaderWorker
* @ingroup PictureLoader
* @brief Handles asynchronous loading of card images, both locally and via network.
*
* Responsibilities:
* - Maintain a queue of network image requests with rate-limiting.
* - Load images from local cache first via CardPictureLoaderLocal.
* - Handle network redirects and persistent caching of redirects.
* - Deduplicate simultaneous requests for the same card.
* - Emit signals for status updates and loaded images.
*/
class CardPictureLoaderWorker : public QObject
{
Q_OBJECT
public:
/**
* @brief Constructs a CardPictureLoaderWorker.
*
* Initializes network manager, cache, redirect cache, local loader, and request quota timer.
*/
explicit CardPictureLoaderWorker();
~CardPictureLoaderWorker() override;
void enqueueImageLoad(const ExactCard &card); // Starts a thread for the image to be loaded
void queueRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker); // Queues network requests for load threads
/**
* @brief Enqueues an ExactCard for loading.
* @param card ExactCard to load
*
* This will first try to load the image locally; if that fails, it will enqueue a network request.
*/
void enqueueImageLoad(const ExactCard &card);
/**
* @brief Queues a network request for a given URL and worker thread.
* @param url URL to load
* @param worker Worker handling this request
*/
void queueRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker);
/** @brief Clears the network cache and redirect cache. */
void clearNetworkCache();
public slots:
/**
* @brief Makes a network request for the given URL using the specified worker.
* @param url URL to load
* @param workThread Worker handling the request
* @return The QNetworkReply object representing the request
*/
QNetworkReply *makeRequest(const QUrl &url, CardPictureLoaderWorkerWork *workThread);
/** @brief Processes all queued requests respecting the request quota. */
void processQueuedRequests();
/**
* @brief Processes a single queued request.
* @return true if a request was processed, false if queue is empty.
*/
bool processSingleRequest();
/**
* @brief Handles an image that has finished loading.
* @param card The ExactCard that was loaded
* @param image The loaded QImage; empty if loading failed
*/
void handleImageLoaded(const ExactCard &card, const QImage &image);
/** @brief Caches a redirect mapping between original and redirected URL. */
void cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl);
/** @brief Removes a URL from the network cache. */
void removedCachedUrl(const QUrl &url);
private:
QThread *pictureLoaderThread;
QNetworkAccessManager *networkManager;
QNetworkDiskCache *cache;
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; // Stores redirect and timestamp
QString cacheFilePath; // Path to persistent storage
static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable
bool picDownload;
QQueue<QPair<QUrl, CardPictureLoaderWorkerWork *>> requestLoadQueue;
QThread *pictureLoaderThread; ///< Thread for executing worker tasks
QNetworkAccessManager *networkManager; ///< Network manager for HTTP requests
QNetworkDiskCache *cache; ///< Disk cache for downloaded images
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; ///< Maps original URLs to redirects with timestamp
QString cacheFilePath; ///< Path to persistent redirect cache file
static constexpr int CacheTTLInDays = 30; ///< Time-to-live for redirect cache entries (days)
bool picDownload; ///< Whether downloading images from network is enabled
QQueue<QPair<QUrl, CardPictureLoaderWorkerWork *>> requestLoadQueue; ///< Queue of pending network requests
int requestQuota;
QTimer requestTimer; // Timer for refreshing request quota
int requestQuota; ///< Remaining requests allowed per second
QTimer requestTimer; ///< Timer to reset the request quota
CardPictureLoaderLocal *localLoader;
QSet<QString> currentlyLoading; // for deduplication purposes. Contains pixmapCacheKey
CardPictureLoaderLocal *localLoader; ///< Loader for local images
QSet<QString> currentlyLoading; ///< Deduplication: contains pixmapCacheKey currently being loaded
/** @brief Returns cached redirect URL for the given original URL, if available. */
QUrl getCachedRedirect(const QUrl &originalUrl) const;
/** @brief Loads redirect cache from disk. */
void loadRedirectCache();
/** @brief Saves redirect cache to disk. */
void saveRedirectCache() const;
/** @brief Removes stale redirect entries older than TTL. */
void cleanStaleEntries();
private slots:
/** @brief Resets the request quota for rate-limiting. */
void resetRequestQuota();
/** @brief Handles image load requests enqueued on this worker. */
void handleImageLoadEnqueued(const ExactCard &card);
signals:
/** @brief Emitted when an image load is enqueued. */
void imageLoadEnqueued(const ExactCard &card);
/** @brief Emitted when an image has finished loading. */
void imageLoaded(const ExactCard &card, const QImage &image);
/** @brief Emitted when a request is added to the network queue. */
void imageRequestQueued(const QUrl &url, const ExactCard &card, const QString &setName);
/** @brief Emitted when a network request successfully completes. */
void imageRequestSucceeded(const QUrl &url);
};

View File

@@ -51,10 +51,6 @@ void CardPictureLoaderWorkerWork::startNextPicDownload()
}
}
/**
* Starts another pic download using the next possible url combination for the card.
* If all possibilities are exhausted, then concludes the image loading with an empty QImage.
*/
void CardPictureLoaderWorkerWork::picDownloadFailed()
{
/* Take advantage of short-circuiting here to call the nextUrl until one
@@ -73,10 +69,6 @@ void CardPictureLoaderWorkerWork::picDownloadFailed()
}
}
/**
*
* @param reply The reply. Takes ownership of the object
*/
void CardPictureLoaderWorkerWork::handleNetworkReply(QNetworkReply *reply)
{
QVariant redirectTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
@@ -180,10 +172,6 @@ void CardPictureLoaderWorkerWork::handleSuccessfulReply(QNetworkReply *reply)
}
}
/**
* @param reply The reply to load the image from
* @return The loaded image, or an empty QImage if loading failed
*/
QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply)
{
static constexpr int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h
@@ -207,10 +195,6 @@ QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply)
return imgReader.read();
}
/**
* Call this method when the image has finished being loaded.
* @param image The image that was loaded. Empty QImage indicates failure.
*/
void CardPictureLoaderWorkerWork::concludeImageLoad(const QImage &image)
{
emit imageLoaded(cardToDownload.getCard(), image);

View File

@@ -1,9 +1,3 @@
/**
* @file picture_loader_worker_work.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef PICTURE_LOADER_WORKER_WORK_H
#define PICTURE_LOADER_WORKER_WORK_H
@@ -17,55 +11,96 @@
#include <QThread>
#include <libcockatrice/card/database/card_database.h>
#define REDIRECT_HEADER_NAME "redirects"
#define REDIRECT_ORIGINAL_URL "original"
#define REDIRECT_URL "redirect"
#define REDIRECT_TIMESTAMP "timestamp"
#define REDIRECT_CACHE_FILENAME "cache.ini"
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerWorkLog, "card_picture_loader.worker");
class CardPictureLoaderWorker;
/**
* @class CardPictureLoaderWorkerWork
* @ingroup PictureLoader
* @brief Handles downloading a single card image from network or local sources.
*
* Responsibilities:
* - Try to load images from all possible URLs and sets for a given ExactCard.
* - Handle network redirects and cache invalidation.
* - Check for blacklisted images and discard them.
* - Emit signals when image is successfully loaded or all attempts fail.
* - Delete itself after loading completes.
*/
class CardPictureLoaderWorkerWork : public QObject
{
Q_OBJECT
public:
/**
* @brief Constructs a worker for downloading a specific card image.
* @param worker The orchestrating CardPictureLoaderWorker
* @param toLoad The ExactCard to download
*/
explicit CardPictureLoaderWorkerWork(const CardPictureLoaderWorker *worker, const ExactCard &toLoad);
CardPictureToLoad cardToDownload;
CardPictureToLoad cardToDownload; ///< The card and associated URLs to try downloading
public slots:
/**
* @brief Handles a finished network reply for the card image.
* @param reply The QNetworkReply object to process. Ownership is transferred.
*/
void handleNetworkReply(QNetworkReply *reply);
private:
bool picDownload;
bool picDownload; ///< Whether network downloading is enabled
/** @brief Starts downloading the next URL for this card. */
void startNextPicDownload();
/** @brief Called when all URLs have been exhausted or download failed. */
void picDownloadFailed();
/** @brief Processes a failed network reply. */
void handleFailedReply(const QNetworkReply *reply);
/** @brief Processes a successful network reply. */
void handleSuccessfulReply(QNetworkReply *reply);
/**
* @brief Attempts to read an image from a network reply.
* @param reply The network reply
* @return The loaded QImage or an empty image if reading failed
*/
QImage tryLoadImageFromReply(QNetworkReply *reply);
/**
* @brief Finalizes the image loading process.
* @param image The loaded image (empty if failed)
*
* Emits imageLoaded() and deletes this object.
*/
void concludeImageLoad(const QImage &image);
private slots:
/** @brief Updates the picDownload setting when it changes. */
void picDownloadChanged();
signals:
/**
* Emitted when this worker has successfully loaded the image or has exhausted all attempts at loading the image.
* Failures are represented by an empty QImage.
* Note that this object will delete itself as this signal is emitted.
* @brief Emitted when the image has been loaded or all attempts failed.
* @param card The card corresponding to the image
* @param image The loaded image (empty if failed)
*
* The worker deletes itself after emitting this signal.
*/
void imageLoaded(const ExactCard &card, const QImage &image);
/**
* Emitted when a request did not return a 400 or 500 response
*/
/** @brief Emitted when a network request completes successfully. */
void requestSucceeded(const QUrl &url);
/** @brief Request that a URL be downloaded. */
void requestImageDownload(const QUrl &url, CardPictureLoaderWorkerWork *instance);
/** @brief Emitted when a URL has been redirected. */
void urlRedirected(const QUrl &originalUrl, const QUrl &redirectUrl);
/** @brief Emitted when a cached URL is invalid and must be removed. */
void cachedUrlInvalidated(const QUrl &url);
};

View File

@@ -20,12 +20,6 @@ CardPictureToLoad::CardPictureToLoad(const ExactCard &_card)
}
}
/**
* Extracts a list of all the sets from the card, sorted in priority order.
* If the card does not contain any sets, then a dummy set will be inserted into the list.
*
* @return A list of sets. Will not be empty.
*/
QList<CardSetPtr> CardPictureToLoad::extractSetsSorted(const ExactCard &card)
{
QList<CardSetPtr> sortedSets;
@@ -109,11 +103,6 @@ void CardPictureToLoad::populateSetUrls()
(void)nextUrl();
}
/**
* Advances the currentSet to the next set in the list. Then repopulates the url list with the urls from that set.
* If we are already at the end of the list, then currentSet is set to empty.
* @return If we are already at the end of the list
*/
bool CardPictureToLoad::nextSet()
{
if (!sortedSets.isEmpty()) {
@@ -125,11 +114,6 @@ bool CardPictureToLoad::nextSet()
return false;
}
/**
* Advances the currentUrl to the next url in the list.
* If we are already at the end of the list, then currentUrl is set to empty.
* @return If we are already at the end of the list
*/
bool CardPictureToLoad::nextUrl()
{
if (!currentSetUrls.isEmpty()) {

View File

@@ -1,9 +1,3 @@
/**
* @file card_picture_to_load.h
* @ingroup PictureLoader
* @brief TODO: Document this.
*/
#ifndef PICTURE_TO_LOAD_H
#define PICTURE_TO_LOAD_H
@@ -12,37 +6,97 @@
inline Q_LOGGING_CATEGORY(CardPictureToLoadLog, "card_picture_loader.picture_to_load");
/**
* @class CardPictureToLoad
* @ingroup PictureLoader
* @brief Manages all URLs and sets for downloading a specific card image.
*
* Responsibilities:
* - Maintains a sorted list of sets for a card.
* - Generates URLs to download images from, including custom URLs and URL templates.
* - Tracks which URL and set is currently being attempted.
* - Provides helper methods to advance to next URL or set.
*/
class CardPictureToLoad
{
private:
ExactCard card;
QList<CardSetPtr> sortedSets;
QList<QString> urlTemplates;
QList<QString> currentSetUrls;
QString currentUrl;
CardSetPtr currentSet;
ExactCard card; ///< The ExactCard being downloaded
QList<CardSetPtr> sortedSets; ///< All sets for this card, sorted by priority
QList<QString> urlTemplates; ///< URL templates from settings
QList<QString> currentSetUrls; ///< URLs for the current set being attempted
QString currentUrl; ///< Currently active URL to download
CardSetPtr currentSet; ///< Currently active set
public:
/**
* @brief Constructs a CardPictureToLoad for a given ExactCard.
* @param _card The card to download
*
* Initializes URL templates and pre-populates the first set URLs.
*/
explicit CardPictureToLoad(const ExactCard &_card);
/** @return The card being loaded. */
const ExactCard &getCard() const
{
return card;
}
/** @return The current URL being attempted. */
QString getCurrentUrl() const
{
return currentUrl;
}
/** @return The current set being attempted. */
CardSetPtr getCurrentSet() const
{
return currentSet;
}
/** @return The short name of the current set, or empty string if no set. */
QString getSetName() const;
/**
* @brief Transforms a URL template into a concrete URL for this card/set.
* @param urlTemplate The URL template to transform
* @return The transformed URL or empty string if the template cannot be fulfilled
*/
QString transformUrl(const QString &urlTemplate) const;
/**
* @brief Advance to the next set in the list.
* @return True if a next set exists and was selected, false if at the end.
*
* Updates currentSet and repopulates currentSetUrls.
* If we are already at the end of the list, then currentSet is set to empty.
*/
bool nextSet();
/**
* @brief Advance to the next URL in the current set's list.
* @return True if a next URL exists, false if at the end.
*
* Updates currentUrl.
* If we are already at the end of the list, then currentUrl is set to empty.
*/
bool nextUrl();
/**
* @brief Populates the currentSetUrls list with URLs for the current set.
*
* Includes custom URLs first, followed by template-based URLs.
*/
void populateSetUrls();
/**
* @brief Extract all sets from the card and sort them by priority.
* @param card The card to extract sets from
* @return A non-empty list of CardSetPtr, sorted by priority
*
* If the card has no sets, a dummy set is inserted. Also ensures
* the printing corresponding to the ExactCard is first in the list.
*/
static QList<CardSetPtr> extractSetsSorted(const ExactCard &card);
};