1 /*
2 SPDX-FileCopyrightText: 2010 Daniel Laidig <laidig@kde.org>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "imagecache.h"
7
8 #include <QDataStream>
9 #include <QDir>
10 #include <QFileInfo>
11
12 #include <QDebug>
13
14 using namespace Practice;
15
16 const char *identifier = "parleyimagecache2";
17
setFilenames(const QStringList & filenames)18 void ImageCache::setFilenames(const QStringList &filenames)
19 {
20 m_timestamps.clear();
21 for (const QString &filename : filenames) {
22 QFileInfo info(filename);
23 m_timestamps.append(info.lastModified());
24 }
25 m_images.clear();
26 m_filenames = filenames;
27 if (!m_saveFilename.isNull()) {
28 openCache();
29 }
30 }
31
updateImage(const QString & id,const QImage & image)32 void ImageCache::updateImage(const QString &id, const QImage &image)
33 {
34 m_images[id] = image;
35 }
36
imageSize(const QString & id)37 QSize ImageCache::imageSize(const QString &id)
38 {
39 if (!m_images.contains(id)) {
40 return QSize();
41 }
42 return m_images.value(id).size();
43 }
44
getImage(const QString & id)45 QImage ImageCache::getImage(const QString &id)
46 {
47 if (!m_images.contains(id)) {
48 return QImage();
49 }
50 return m_images.value(id);
51 }
52
setSaveFilename(const QString & filename)53 void ImageCache::setSaveFilename(const QString &filename)
54 {
55 m_saveFilename = filename;
56 QDir fileDir = QFileInfo(filename).absoluteDir();
57 if (!fileDir.exists() && !fileDir.mkpath(QStringLiteral("."))) {
58 qWarning() << QStringLiteral("Couldn't create image cache path: ") << fileDir.absolutePath();
59 }
60 }
61
openCache()62 void ImageCache::openCache()
63 {
64 QFile file(m_saveFilename);
65 if (!file.open(QIODevice::ReadOnly)) {
66 // If cache is used for the first time it's normal to fail here,
67 // because cache file doesn't exist at this time.
68 return;
69 }
70 QDataStream stream(&file);
71 // check identifier
72 QString temp;
73 stream >> temp;
74 if (temp != QString(identifier)) {
75 // qDebug() << "not loading cache because the identifier doesn't match";
76 return;
77 }
78 // check filename and timestamp, no need to load images for the wrong file or outdated images
79 QStringList filenames;
80 QList<QDateTime> timestamps;
81 stream >> filenames >> timestamps;
82 if (filenames != m_filenames || timestamps != m_timestamps) {
83 // qDebug() << "not loading cache because it contains the wrong theme or the timestamp has changed";
84 return;
85 }
86 // finally load data
87 stream >> m_images;
88 QHashIterator<QString, QImage> i(m_images); // TODO: do on demand
89 while (i.hasNext()) {
90 i.next();
91 m_images[i.key()] = i.value().convertToFormat(QImage::Format_ARGB32_Premultiplied);
92 }
93 // qDebug() << "opened cache:" << m_saveFilename;
94 // qDebug() << *this;
95 }
96
saveCache()97 void ImageCache::saveCache()
98 {
99 // qDebug() << "save cache to:" << m_saveFilename;
100 // qDebug() << *this;
101 QFile file(m_saveFilename);
102 file.open(QIODevice::WriteOnly);
103 QDataStream stream(&file);
104 stream << QString(identifier) << m_filenames << m_timestamps << m_images;
105 }
106
operator <<(QDebug dbg,const ImageCache & c)107 QDebug Practice::operator<<(QDebug dbg, const ImageCache &c)
108 {
109 dbg.nospace() << "(ImageCache, " << c.m_filenames << ", " << c.m_timestamps << ")";
110 int pixels = 0;
111 QHashIterator<QString, QImage> i(c.m_images);
112 while (i.hasNext()) {
113 i.next();
114 dbg.nospace() << "\n\tcontains: " << qPrintable(i.key().leftJustified(35)) << ": " << i.value().size();
115 pixels += i.value().size().width() * i.value().height();
116 }
117
118 dbg.nospace() << "\n\ttotal pixel count: " << pixels << " (approx. " << double(pixels) * 4 / 1024 / 1024 << " MiB)";
119 return dbg.space();
120 }
121