ORE Studio 0.0.4
Loading...
Searching...
No Matches
ImageCache.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2025 Marco Craveiro <marco.craveiro@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20#ifndef ORES_QT_IMAGE_CACHE_HPP
21#define ORES_QT_IMAGE_CACHE_HPP
22
23#include <unordered_map>
24#include <unordered_set>
25#include <QObject>
26#include <QIcon>
27#include <QFutureWatcher>
28#include "ores.qt/ClientManager.hpp"
29#include "ores.logging/make_logger.hpp"
30#include "ores.assets/domain/image.hpp"
31#include "ores.assets/messaging/assets_protocol.hpp"
32
33namespace ores::qt {
34
52class ImageCache final : public QObject {
53 Q_OBJECT
54
55private:
56 inline static std::string_view logger_name = "ores.qt.image_cache";
57
58 [[nodiscard]] static auto& lg() {
59 using namespace ores::logging;
60 static auto instance = make_logger(logger_name);
61 return instance;
62 }
63
64public:
65 explicit ImageCache(ClientManager* clientManager, QObject* parent = nullptr);
66 ~ImageCache() override = default;
67
75 void loadAll();
76
83 void reload();
84
95 QIcon getIcon(const std::string& image_id);
96
103 bool hasIcon(const std::string& image_id) const;
104
108 std::size_t cachedIconCount() const { return image_icons_.size(); }
109
113 bool isLoading() const { return is_loading_images_; }
114
121 void loadImageList();
122
128 const std::vector<assets::messaging::image_info>& availableImages() const {
129 return available_images_;
130 }
131
135 bool hasImageList() const { return !available_images_.empty(); }
136
144
152 void setCurrencyImage(const std::string& iso_code, const std::string& image_id,
153 const std::string& assigned_by);
154
162 void setCountryImage(const std::string& alpha2_code, const std::string& image_id,
163 const std::string& assigned_by);
164
170 std::string getNoFlagImageId() const;
171
177 QIcon getNoFlagIcon() const;
178
179signals:
184
188 void allLoaded();
189
193 void loadError(const QString& error_message);
194
199
205 void imageLoaded(const QString& image_id);
206
211
215 void currencyImageSet(const QString& iso_code, bool success, const QString& message);
216
220 void countryImageSet(const QString& alpha2_code, bool success, const QString& message);
221
222private slots:
223 void onCurrencyImageIdsLoaded();
224 void onCountryImageIdsLoaded();
225 void onImagesLoaded();
226 void onImageListLoaded();
227 void onSingleImageLoaded();
228 void onCurrencyImageSet();
229 void onCountryImageSet();
230 void onAllAvailableImagesLoaded();
231 void onIncrementalChangesLoaded();
232
233private:
240 static QIcon svgToIcon(const std::string& svg_data);
241
247 void loadImageById(const std::string& image_id);
248
252 void loadCurrencyImageIds();
253
257 void loadCountryImageIds();
258
262 void loadImagesByIds(const std::vector<std::string>& image_ids);
263
269 void loadIncrementalChanges();
270
271 struct ImageIdsResult {
272 bool success;
273 std::vector<std::string> image_ids;
274 };
275
276 struct ImagesResult {
277 bool success;
278 std::vector<assets::domain::image> images;
279 int failed_batches{0};
280 };
281
289 static ImagesResult fetchImagesInBatches(
290 ClientManager* clientManager,
291 const std::vector<std::string>& image_ids);
292
293 struct ImageListResult {
294 bool success;
295 std::vector<assets::messaging::image_info> images;
296 };
297
298 struct SingleImageResult {
299 bool success;
300 std::string image_id;
302 };
303
304 struct SetCurrencyImageResult {
305 bool success;
306 std::string iso_code;
307 std::string message;
308 };
309
310 struct SetCountryImageResult {
311 bool success;
312 std::string alpha2_code;
313 std::string message;
314 };
315
316 ClientManager* clientManager_;
317
318 // image_id -> cached SVG data
319 std::unordered_map<std::string, std::string> image_svg_cache_;
320
321 // image_id -> QIcon (rendered from SVG)
322 std::unordered_map<std::string, QIcon> image_icons_;
323
324 // Loading state
325 bool is_loading_images_{false};
326 bool is_loading_all_available_{false};
327 bool load_all_in_progress_{false};
328
329 // Image IDs collected during loadAll() for preloading
330 std::vector<std::string> pending_image_ids_;
331
332 QFutureWatcher<ImageIdsResult>* currency_ids_watcher_;
333 QFutureWatcher<ImageIdsResult>* country_ids_watcher_;
334 QFutureWatcher<ImageIdsResult>* incremental_changes_watcher_;
335 QFutureWatcher<ImagesResult>* images_watcher_;
336 QFutureWatcher<ImageListResult>* image_list_watcher_;
337 QFutureWatcher<SingleImageResult>* single_image_watcher_;
338 QFutureWatcher<SetCurrencyImageResult>* set_currency_image_watcher_;
339 QFutureWatcher<SetCountryImageResult>* set_country_image_watcher_;
340 QFutureWatcher<ImagesResult>* all_available_watcher_;
341
342 // List of all available images (metadata only)
343 std::vector<assets::messaging::image_info> available_images_;
344
345 // Track image IDs currently being loaded to prevent duplicate requests
346 std::unordered_set<std::string> pending_image_requests_;
347
348 // Timestamp of last successful load (for incremental loading)
349 std::optional<std::chrono::system_clock::time_point> last_load_time_;
350};
351
352}
353
354#endif
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28
Qt-based graphical user interface for ORE Studio.
Definition AboutDialog.hpp:35
Represents a dynamically loaded image (typically SVG).
Definition image.hpp:32
Manages the lifecycle of the network client and IO context.
Definition ClientManager.hpp:90
Cache for dynamically loaded images (flags, icons) from the server.
Definition ImageCache.hpp:52
QIcon getNoFlagIcon() const
Get the icon for the "no-flag" placeholder.
Definition ImageCache.cpp:827
void loadImageList()
Load list of all available images from the server.
Definition ImageCache.cpp:677
void imageLoaded(const QString &image_id)
Emitted when a single image has been loaded.
std::size_t cachedIconCount() const
Get the number of cached images.
Definition ImageCache.hpp:108
void countryImageSet(const QString &alpha2_code, bool success, const QString &message)
Emitted when country image assignment is complete.
void allLoaded()
Emitted when all data has been loaded (after loadAll()).
bool hasIcon(const std::string &image_id) const
Check if an image is cached.
Definition ImageCache.cpp:509
void setCountryImage(const std::string &alpha2_code, const std::string &image_id, const std::string &assigned_by)
Set or remove a country's image association.
Definition ImageCache.cpp:954
const std::vector< assets::messaging::image_info > & availableImages() const
Get the list of available images.
Definition ImageCache.hpp:128
bool isLoading() const
Check if images are currently being loaded.
Definition ImageCache.hpp:113
bool hasImageList() const
Check if image list has been loaded.
Definition ImageCache.hpp:135
std::string getNoFlagImageId() const
Get the image ID for the "no-flag" placeholder.
Definition ImageCache.cpp:817
void loadAllAvailableImages()
Load all available images from the image list.
Definition ImageCache.cpp:741
void setCurrencyImage(const std::string &iso_code, const std::string &image_id, const std::string &assigned_by)
Set or remove a currency's image association.
Definition ImageCache.cpp:839
void imageListLoaded()
Emitted when image list has been loaded.
void loadAll()
Preload images for current currencies and countries.
Definition ImageCache.cpp:77
void loadError(const QString &error_message)
Emitted when an error occurs during loading.
void imagesLoaded()
Emitted when images have been loaded.
void currencyImageSet(const QString &iso_code, bool success, const QString &message)
Emitted when currency image assignment is complete.
QIcon getIcon(const std::string &image_id)
Get icon for an image by its UUID.
Definition ImageCache.cpp:489
void allAvailableImagesLoaded()
Emitted when all available images have been loaded.
void reload()
Clear all caches and reload images.
Definition ImageCache.cpp:92