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