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 213231cd9..29bdf26c8 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h @@ -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 &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 &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 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 33a78ddaf..dd00e6e1d 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 @@ -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(); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h index 1d4325412..84f16cc38 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h @@ -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 customFolderIndex; // multimap of cardName to picPaths - QTimer *refreshTimer; + QMultiHash 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(); }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h index be032ae64..6e9b6a6e2 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h @@ -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 #include #include +/** + * @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 diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h index b44d2cc20..cb469269c 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h @@ -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 #include +#include #include +/** + * @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 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 4a831c24a..a2da3c953 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 @@ -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()) { diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h index cdee37db3..3468ce86a 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h @@ -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> redirectCache; // Stores redirect and timestamp - QString cacheFilePath; // Path to persistent storage - static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable - bool picDownload; - QQueue> requestLoadQueue; + QThread *pictureLoaderThread; ///< Thread for executing worker tasks + QNetworkAccessManager *networkManager; ///< Network manager for HTTP requests + QNetworkDiskCache *cache; ///< Disk cache for downloaded images + QHash> 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> 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 currentlyLoading; // for deduplication purposes. Contains pixmapCacheKey + CardPictureLoaderLocal *localLoader; ///< Loader for local images + QSet 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); }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp index 07478ee70..e74103419 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp @@ -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); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h index c7ccf7566..cdffc1dff 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h @@ -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 #include -#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); }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp index 3727988ad..d72226aab 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp @@ -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 CardPictureToLoad::extractSetsSorted(const ExactCard &card) { QList 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()) { diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h index b7c0e6a53..99407b4bb 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h @@ -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 sortedSets; - QList urlTemplates; - QList currentSetUrls; - QString currentUrl; - CardSetPtr currentSet; + ExactCard card; ///< The ExactCard being downloaded + QList sortedSets; ///< All sets for this card, sorted by priority + QList urlTemplates; ///< URL templates from settings + QList 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 extractSetsSorted(const ExactCard &card); };