KSvg

imageset.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "imageset.h"
8#include "private/imageset_p.h"
9#include "private/svg_p.h"
10
11#include <QDebug>
12#include <QDir>
13#include <QFile>
14#include <QFileInfo>
15#include <QMutableListIterator>
16#include <QPair>
17#include <QStringBuilder>
18#include <QThread>
19#include <QTimer>
20
21#include <KConfigGroup>
22#include <KDirWatch>
23#include <KImageCache>
24
25#include "debug_p.h"
26
27namespace KSvg
28{
30 : QObject(parent)
31{
32 if (!ImageSetPrivate::globalImageSet) {
33 ImageSetPrivate::globalImageSet = new ImageSetPrivate;
35 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, ImageSetPrivate::globalImageSet, &ImageSetPrivate::onAppExitCleanup);
36 }
37 }
38 ImageSetPrivate::globalImageSet->ref.ref();
39 d = ImageSetPrivate::globalImageSet;
40
41 connect(d, &ImageSetPrivate::imageSetChanged, this, &ImageSet::imageSetChanged);
42}
43
44ImageSet::ImageSet(const QString &imageSetName, const QString &basePath, QObject *parent)
45 : QObject(parent)
46{
47 auto &priv = ImageSetPrivate::themes[imageSetName];
48 if (!priv) {
49 priv = new ImageSetPrivate;
51 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, priv, &ImageSetPrivate::onAppExitCleanup);
52 }
53 }
54
55 priv->ref.ref();
56 d = priv;
57
58 // turn off caching so we don't accidentally trigger unnecessary disk activity at this point
59 bool useCache = d->cacheImageSet;
60 d->cacheImageSet = false;
61 if (!basePath.isEmpty()) {
62 d->basePath = basePath;
63 if (!d->basePath.endsWith(QDir::separator())) {
64 d->basePath += QDir::separator();
65 }
66 }
67 d->setImageSetName(imageSetName, false);
68 d->cacheImageSet = useCache;
69 d->fixedName = true;
70 connect(d, &ImageSetPrivate::imageSetChanged, this, &ImageSet::imageSetChanged);
71}
72
73ImageSet::~ImageSet()
74{
75 if (d == ImageSetPrivate::globalImageSet) {
76 if (!d->ref.deref()) {
77 disconnect(ImageSetPrivate::globalImageSet, nullptr, this, nullptr);
78 delete ImageSetPrivate::globalImageSet;
79 ImageSetPrivate::globalImageSet = nullptr;
80 d = nullptr;
81 }
82 } else {
83 if (!d->ref.deref()) {
84 delete ImageSetPrivate::themes.take(d->imageSetName);
85 }
86 }
87}
88
89void ImageSet::setBasePath(const QString &basePath)
90{
91 if (d->basePath == basePath) {
92 return;
93 }
94
95 d->basePath = basePath;
96 if (!d->basePath.endsWith(QDir::separator())) {
97 d->basePath += QDir::separator();
98 }
99
100 // Don't use scheduleImageSetChangeNotification as we want things happening immediately there,
101 // we don't want in the client code to be setting things like the svg size right after thing just to
102 // be reset right after in an async fashion
103 d->discardCache(PixmapCache | SvgElementsCache);
104 d->cachesToDiscard = NoCache;
105
106 Q_EMIT basePathChanged(basePath);
107 Q_EMIT imageSetChanged(d->imageSetName);
108}
109
110QString ImageSet::basePath() const
111{
112 return d->basePath;
113}
114
115void ImageSet::setSelectors(const QStringList &selectors)
116{
117 d->selectors = selectors;
118 d->scheduleImageSetChangeNotification(PixmapCache | SvgElementsCache);
119}
120
121QStringList ImageSet::selectors() const
122{
123 return d->selectors;
124}
125
126void ImageSet::setImageSetName(const QString &imageSetName)
127{
128 if (d->imageSetName == imageSetName) {
129 return;
130 }
131
132 if (d != ImageSetPrivate::globalImageSet) {
133 disconnect(QCoreApplication::instance(), nullptr, d, nullptr);
134 if (!d->ref.deref()) {
135 delete ImageSetPrivate::themes.take(d->imageSetName);
136 }
137
138 auto &priv = ImageSetPrivate::themes[imageSetName];
139 if (!priv) {
140 priv = new ImageSetPrivate;
142 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, priv, &ImageSetPrivate::onAppExitCleanup);
143 }
144 }
145 priv->ref.ref();
146 d = priv;
147 connect(d, &ImageSetPrivate::imageSetChanged, this, &ImageSet::imageSetChanged);
148 }
149
150 d->setImageSetName(imageSetName, true);
151}
152
153QString ImageSet::imageSetName() const
154{
155 return d->imageSetName;
156}
157
158QString ImageSet::imagePath(const QString &name) const
159{
160 // look for a compressed svg file in the theme
161 if (name.contains(QLatin1String("../")) || name.isEmpty()) {
162 // we don't support relative paths
163 // qCDebug(LOG_KSVG) << "ImageSet says: bad image path " << name;
164 return QString();
165 }
166
167 const QString svgzName = name % QLatin1String(".svgz");
168 QString path = d->findInImageSet(svgzName, d->imageSetName);
169
170 if (path.isEmpty()) {
171 // try for an uncompressed svg file
172 const QString svgName = name % QLatin1String(".svg");
173 path = d->findInImageSet(svgName, d->imageSetName);
174
175 // search in fallback themes if necessary
176 for (int i = 0; path.isEmpty() && i < d->fallbackImageSets.count(); ++i) {
177 if (d->imageSetName == d->fallbackImageSets[i]) {
178 continue;
179 }
180
181 // try a compressed svg file in the fallback theme
182 path = d->findInImageSet(svgzName, d->fallbackImageSets[i]);
183
184 if (path.isEmpty()) {
185 // try an uncompressed svg file in the fallback theme
186 path = d->findInImageSet(svgName, d->fallbackImageSets[i]);
187 }
188 }
189 }
190
191 return path;
192}
193
194QString ImageSet::filePath(const QString &name) const
195{
196 // look for a compressed svg file in the theme
197 if (name.contains(QLatin1String("../")) || name.isEmpty()) {
198 // we don't support relative paths
199 // qCDebug(LOG_KSVG) << "ImageSet says: bad image path " << name;
200 return QString();
201 }
202
203 QString path = d->findInImageSet(name, d->imageSetName);
204
205 if (path.isEmpty()) {
206 // search in fallback themes if necessary
207 for (int i = 0; path.isEmpty() && i < d->fallbackImageSets.count(); ++i) {
208 if (d->imageSetName == d->fallbackImageSets[i]) {
209 continue;
210 }
211
212 path = d->findInImageSet(name, d->fallbackImageSets[i]);
213 }
214 }
215
216 return path;
217}
218
219bool ImageSet::currentImageSetHasImage(const QString &name) const
220{
221 if (name.contains(QLatin1String("../"))) {
222 // we don't support relative paths
223 return false;
224 }
225
226 QString path = d->findInImageSet(name % QLatin1String(".svgz"), d->imageSetName);
227 if (path.isEmpty()) {
228 path = d->findInImageSet(name % QLatin1String(".svg"), d->imageSetName);
229 }
230 return path.contains(d->basePath % d->imageSetName);
231}
232
233void ImageSet::setUseGlobalSettings(bool useGlobal)
234{
235 if (d->useGlobal == useGlobal) {
236 return;
237 }
238
239 d->useGlobal = useGlobal;
240 d->cfg = KConfigGroup();
241 d->imageSetName.clear();
242}
243
244bool ImageSet::useGlobalSettings() const
245{
246 return d->useGlobal;
247}
248
249void ImageSet::setCacheLimit(int kbytes)
250{
251 d->cacheSize = kbytes;
252 delete d->pixmapCache;
253 d->pixmapCache = nullptr;
254}
255
256KPluginMetaData ImageSet::metadata() const
257{
258 return d->pluginMetaData;
259}
260
261}
262
263#include "moc_imageset.cpp"
void imageSetChanged(const QString &basePath)
@brif This signal is emitted when the user makes changes to the theme.
ImageSet(QObject *parent=nullptr)
Default constructor.
Definition imageset.cpp:29
The KSvg namespace.
QCoreApplication * instance()
QChar separator()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:13:51 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.