Krita Source Code Documentation
Loading...
Searching...
No Matches
KisMemoryStorage.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "KisMemoryStorage.h"
8
9#include <QVector>
10
11#include <KisMimeDatabase.h>
12#include <kis_debug.h>
13#include <KisTag.h>
14#include <KisResourceStorage.h>
15#include <QBuffer>
17#include <kis_pointer_utils.h>
18#include <KoMD5Generator.h>
19#include <kis_assert.h>
20
21
28
30{
31public:
32
33 MemoryTagIterator(QVector<KisTagSP> /*tags*/, const QString &resourceType)
34 : m_resourceType(resourceType)
35 {
36 }
37
38 bool hasNext() const override
39 {
40 return false;
41 }
42
43 void next() override
44 {
45 }
46
47 KisTagSP tag() const override
48 {
49 return nullptr;
50 }
51
52private:
54};
55
56
58{
59public:
60 ~MemoryItem() override {}
61};
62
63
65public:
66 QHash<QString, QHash<QString, StoredResource>> resourcesNew;
67 QHash<QString, QVector<KisTagSP>> tags;
68 QMap<QString, QVariant> metadata;
69};
70
71
72KisMemoryStorage::KisMemoryStorage(const QString &location)
73 : KisStoragePlugin(location)
74 , d(new Private)
75{
76}
77
81
83 : KisStoragePlugin(rhs.location())
84 , d(new Private)
85{
86 *this = rhs;
87 d->resourcesNew = rhs.d->resourcesNew;
88 d->tags = rhs.d->tags;
89 d->metadata = rhs.d->metadata;
90}
91
93{
94 if (this != &rhs) {
95 d->resourcesNew = rhs.d->resourcesNew;
96
97 Q_FOREACH(const QString &key, rhs.d->tags.keys()) {
98 Q_FOREACH(const KisTagSP tag, rhs.d->tags[key]) {
99 if (!d->tags.contains(key)) {
100 d->tags[key] = QVector<KisTagSP>();
101 }
102 d->tags[key] << tag->clone();
103 }
104 }
105 }
106 return *this;
107}
108
109bool KisMemoryStorage::saveAsNewVersion(const QString &resourceType, KoResourceSP resource)
110{
111 QHash<QString, StoredResource> &typedResources =
112 d->resourcesNew[resourceType];
113
114 auto checkExists =
115 [&typedResources] (const QString &filename) {
116 return typedResources.contains(filename);
117 };
118
119 const QString newFilename =
121
122 if (newFilename.isEmpty()) return false;
123
124 resource->setFilename(newFilename);
125
126 StoredResource storedResource;
127 storedResource.timestamp = QDateTime::currentDateTime();
128 storedResource.data.reset(new QByteArray());
129 QBuffer buffer(storedResource.data.data());
130 buffer.open(QIODevice::WriteOnly);
131 bool result = resource->saveToDevice(&buffer);
132 buffer.close();
133 if (!result) {
134 storedResource.resource = resource;
135 }
136
137 typedResources.insert(newFilename, storedResource);
138
139 return true;
140}
141
143{
144 MemoryItem item;
145 item.url = url;
146 item.folder = QString();
147 item.lastModified = QDateTime::fromMSecsSinceEpoch(0);
148 return item;
149}
150
152{
153 const QString resourceType = resource->resourceType().first;
154 const QString resourceFilename = resource->filename();
155
156 bool retval = false;
157
158 if (d->resourcesNew.contains(resourceType) &&
159 d->resourcesNew[resourceType].contains(resourceFilename)) {
160
161 const StoredResource &storedResource =
162 d->resourcesNew[resourceType][resourceFilename];
163
164 if (storedResource.data->size() > 0) {
165 QBuffer buffer(storedResource.data.data());
166 buffer.open(QIODevice::ReadOnly);
167 resource->loadFromDevice(&buffer, KisGlobalResourcesInterface::instance());
168 } else {
169 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(storedResource.data->size() > 0, false);
170 qWarning() << "Cannot load resource from device in KisMemoryStorage::loadVersionedResource";
171 return false;
172 }
173 retval = true;
174 }
175
176 return retval;
177}
178
179bool KisMemoryStorage::importResource(const QString &url, QIODevice *device)
180{
181
182 QStringList parts = url.split('/', Qt::SkipEmptyParts);
183
184 Q_ASSERT(parts.size() == 2);
185
186 const QString resourceType = parts[0];
187 const QString resourceFilename = parts[1];
188
189 // we cannot overwrite existing file by API convention
190 if (d->resourcesNew.contains(resourceType) &&
191 d->resourcesNew[resourceType].contains(resourceFilename)) {
192 return false;
193 }
194
195 StoredResource storedResource;
196 storedResource.timestamp = QDateTime::currentDateTime();
197 storedResource.data.reset(new QByteArray(device->readAll()));
198
199 QHash<QString, StoredResource> &typedResources =
200 d->resourcesNew[resourceType];
201 typedResources.insert(resourceFilename, storedResource);
202
203 return true;
204}
205
206bool KisMemoryStorage::exportResource(const QString &url, QIODevice *device)
207{
208 QStringList parts = url.split('/', Qt::SkipEmptyParts);
209 Q_ASSERT(parts.size() == 2);
210
211 const QString resourceType = parts[0];
212 const QString resourceFilename = parts[1];
213
214 if (!d->resourcesNew.contains(resourceType) ||
215 !d->resourcesNew[resourceType].contains(resourceFilename)) {
216 return false;
217 }
218
219 const StoredResource &storedResource =
220 d->resourcesNew[resourceType][resourceFilename];
221
222 if (!storedResource.data) {
223 qWarning() << "Stored resource doesn't have a serialized representation!";
224 return false;
225 }
226
227 device->write(*storedResource.data);
228 return true;
229}
230
231bool KisMemoryStorage::addResource(const QString &resourceType, KoResourceSP resource)
232{
233 QHash<QString, StoredResource> &typedResources = d->resourcesNew[resourceType];
234
235 if (typedResources.contains(resource->filename())) {
236 return true;
237 };
238
239 StoredResource storedResource;
240 storedResource.timestamp = QDateTime::currentDateTime();
241 storedResource.data.reset(new QByteArray());
242 if (resource->isSerializable()) {
243 QBuffer buffer(storedResource.data.data());
244 buffer.open(QIODevice::WriteOnly);
245 if (!resource->saveToDevice(&buffer)) {
246 storedResource.resource = resource;
247 }
248 buffer.close();
249 } else {
250 storedResource.resource = resource;
251 }
252
253 typedResources.insert(resource->filename(), storedResource);
254
255 return true;
256}
257
259{
260 QStringList parts = url.split('/', Qt::SkipEmptyParts);
261
262 Q_ASSERT(parts.size() == 2);
263
264 const QString resourceType = parts[0];
265 const QString resourceFilename = parts[1];
266
267 if (d->resourcesNew.contains(resourceType)) {
268 return d->resourcesNew[resourceType].remove(resourceFilename) > 0;
269 }
270
271 return false;
272}
273
274QString KisMemoryStorage::resourceMd5(const QString &url)
275{
276 QStringList parts = url.split('/', Qt::SkipEmptyParts);
277
278 Q_ASSERT(parts.size() == 2);
279
280 const QString resourceType = parts[0];
281 const QString resourceFilename = parts[1];
282
283 QString result;
284
285 if (d->resourcesNew.contains(resourceType) &&
286 d->resourcesNew[resourceType].contains(resourceFilename)) {
287
288 const StoredResource &storedResource =
289 d->resourcesNew[resourceType][resourceFilename];
290
291 if (storedResource.data->size() > 0 || storedResource.resource.isNull()) {
292 result = KoMD5Generator::generateHash(*storedResource.data);
293 } else {
294 result = storedResource.resource->md5Sum();
295 }
296 }
297
298 return result;
299}
300
302{
304
305
306 QHash<QString, StoredResource> &typedResources =
307 d->resourcesNew[resourceType];
308
309 for (auto it = typedResources.begin(); it != typedResources.end(); ++it) {
311 entry.filename = it.key();
312 entry.lastModified = it.value().timestamp;
313 entry.tagList = {}; // TODO
314 entry.resourceType = resourceType;
315 entries.append(entry);
316
317 }
318
320
321 return toQShared(new KisVersionedStorageIterator(entries, this));
322}
323
325{
326 return QSharedPointer<KisResourceStorage::TagIterator>(new MemoryTagIterator(d->tags[resourceType], resourceType));
327}
328
329void KisMemoryStorage::setMetaData(const QString &key, const QVariant &value)
330{
331 d->metadata[key] = value;
332}
333
335{
336 QStringList keys = d->metadata.keys();
337
338 if (!keys.contains(KisResourceStorage::s_meta_name)) {
340 }
341
342 return keys;
343}
344
345QVariant KisMemoryStorage::metaData(const QString &key) const
346{
347 QVariant r;
348 if (d->metadata.contains(key)) {
349 r = d->metadata[key];
350 }
351 return r;
352}
float value(const T *src, size_t ch)
static KisResourcesInterfaceSP instance()
QHash< QString, QHash< QString, StoredResource > > resourcesNew
QMap< QString, QVariant > metadata
QHash< QString, QVector< KisTagSP > > tags
The KisMemoryStorage class stores the temporary resources that are not saved to disk or bundle....
QSharedPointer< KisResourceStorage::TagIterator > tags(const QString &resourceType) override
bool saveAsNewVersion(const QString &resourceType, KoResourceSP resource) override
bool exportResource(const QString &url, QIODevice *device) override
bool importResource(const QString &url, QIODevice *device) override
void setMetaData(const QString &key, const QVariant &value) override
KisMemoryStorage & operator=(const KisMemoryStorage &rhs)
This clones all contained resources and tags from rhs.
KisMemoryStorage(const QString &location=QString("memory"))
bool loadVersionedResource(KoResourceSP resource) override
bool testingRemoveResource(const QString &url)
KisResourceStorage::ResourceItem resourceItem(const QString &url) override
QSharedPointer< KisResourceStorage::ResourceIterator > resources(const QString &resourceType) override
bool addResource(const QString &resourceType, KoResourceSP resource) override
QStringList metaDataKeys() const override
QString resourceMd5(const QString &url) override
QVariant metaData(const QString &key) const override
QScopedPointer< Private > d
static const QString s_meta_name
virtual KoResourceSP resource(const QString &url)
static void detectFileVersions(QVector< VersionedResourceEntry > &allFiles)
static QString chooseUniqueName(KoResourceSP resource, int minVersion, std::function< bool(QString)> checkExists)
static QString generateHash(const QString &filename)
generateHash reads the given file and generates a hex-encoded md5sum for the file.
~MemoryItem() override
bool hasNext() const override
MemoryTagIterator(QVector< KisTagSP >, const QString &resourceType)
void next() override
The iterator is only valid if next() has been called at least once.
KisTagSP tag() const override
A tag object on which we can set properties and which we can save.
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
QSharedPointer< T > toQShared(T *ptr)
A resource item is simply an entry in the storage,.
KoResourceSP resource
QSharedPointer< QByteArray > data