Warning, file /office/calligra/libs/flake/KoImageCollection.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2007, 2009 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 #include "KoImageCollection.h"
0021 #include "KoImageData.h"
0022 #include "KoImageData_p.h"
0023 #include "KoShapeSavingContext.h"
0024 
0025 #include <KoStoreDevice.h>
0026 #include <QCryptographicHash>
0027 #include <KoXmlWriter.h>
0028 
0029 #include <QMap>
0030 #include <FlakeDebug.h>
0031 #include <QMimeDatabase>
0032 #include <QMimeType>
0033 
0034 
0035 class Q_DECL_HIDDEN KoImageCollection::Private
0036 {
0037 public:
0038     ~Private()
0039     {
0040         foreach(KoImageDataPrivate *id, images)
0041             id->collection = 0;
0042     }
0043 
0044     QMap<qint64, KoImageDataPrivate*> images;
0045     // an extra map to find all dataObjects based on the key of a store.
0046     QMap<QByteArray, KoImageDataPrivate*> storeImages;
0047 };
0048 
0049 KoImageCollection::KoImageCollection(QObject *parent)
0050     : QObject(parent),
0051     d(new Private())
0052 {
0053 }
0054 
0055 KoImageCollection::~KoImageCollection()
0056 {
0057     delete d;
0058 }
0059 
0060 bool KoImageCollection::completeLoading(KoStore *store)
0061 {
0062     Q_UNUSED(store);
0063     d->storeImages.clear();
0064     return true;
0065 }
0066 
0067 bool KoImageCollection::completeSaving(KoStore *store, KoXmlWriter *manifestWriter, KoShapeSavingContext *context)
0068 {
0069     const QMap<qint64, QString> imagesToSave(context->imagesToSave());
0070     QMap<qint64, QString>::ConstIterator imagesToSaveIter(imagesToSave.begin());
0071 
0072     QMap<qint64, KoImageDataPrivate *>::ConstIterator knownImagesIter(d->images.constBegin());
0073 
0074     while (imagesToSaveIter != imagesToSave.constEnd()) {
0075         if (knownImagesIter == d->images.constEnd()) {
0076             // this should not happen
0077             warnFlake << "image not found";
0078             Q_ASSERT(0);
0079             break;
0080         }
0081         else if (knownImagesIter.key() == imagesToSaveIter.key()) {
0082             KoImageDataPrivate *imageData = knownImagesIter.value();
0083             if (store->open(imagesToSaveIter.value())) {
0084                 KoStoreDevice device(store);
0085                 bool ok = imageData->saveData(device);
0086                 store->close();
0087                 // TODO error handling
0088                 if (ok) {
0089                     QMimeDatabase db;
0090                     const QString mimetype(db.mimeTypeForFile(imagesToSaveIter.value(), QMimeDatabase::MatchExtension).name());
0091                     manifestWriter->addManifestEntry(imagesToSaveIter.value(), mimetype);
0092                 } else {
0093                     warnFlake << "saving image" << imagesToSaveIter.value() << "failed";
0094                 }
0095             } else {
0096                 warnFlake << "saving image failed: open store failed";
0097             }
0098             ++knownImagesIter;
0099             ++imagesToSaveIter;
0100         } else if (knownImagesIter.key() < imagesToSaveIter.key()) {
0101             ++knownImagesIter;
0102         } else {
0103             // this should not happen
0104             warnFlake << "image not found";
0105             abort();
0106             Q_ASSERT(0);
0107         }
0108     }
0109     return true;
0110 }
0111 
0112 KoImageData *KoImageCollection::createImageData(const QImage &image)
0113 {
0114     Q_ASSERT(!image.isNull());
0115     KoImageData *data = new KoImageData();
0116     data->setImage(image);
0117 
0118     data = cacheImage(data);
0119     return data;
0120 }
0121 
0122 KoImageData *KoImageCollection::createImageData(const QString &href, KoStore *store)
0123 {
0124     // the tricky thing with a 'store' is that we need to read the data now
0125     // as the store will no longer be readable after the loading completed.
0126     //
0127     // The solution we use is to read the data, store it in a QTemporaryFile
0128     // and read and parse it on demand when the image data is actually needed.
0129     // This leads to having two keys, one for the store and one for the
0130     // actual image data. We need the latter so if someone else gets the same
0131     // image data they can find this data and share (insert warm fuzzy feeling here).
0132     //
0133     QByteArray storeKey = (QString::number((qint64) store) + href).toLatin1();
0134     if (d->storeImages.contains(storeKey))
0135         return new KoImageData(d->storeImages.value(storeKey));
0136 
0137     KoImageData *data = new KoImageData();
0138     data->setImage(href, store);
0139 
0140     data = cacheImage(data);
0141     d->storeImages.insert(storeKey, data->priv());
0142     return data;
0143 }
0144 
0145 KoImageData *KoImageCollection::createImageData(const QByteArray &imageData)
0146 {
0147     QCryptographicHash md5(QCryptographicHash::Md5);
0148     md5.addData(imageData);
0149     qint64 key = KoImageDataPrivate::generateKey(md5.result());
0150     if (d->images.contains(key))
0151         return new KoImageData(d->images.value(key));
0152     KoImageData *data = new KoImageData();
0153     data->setImage(imageData);
0154     data->priv()->collection = this;
0155     Q_ASSERT(data->key() == key);
0156     d->images.insert(key, data->priv());
0157     return data;
0158 }
0159 
0160 KoImageData *KoImageCollection::cacheImage(KoImageData *data)
0161 {
0162     QMap<qint64, KoImageDataPrivate*>::const_iterator it(d->images.constFind(data->key()));
0163     if (it == d->images.constEnd()) {
0164         d->images.insert(data->key(), data->priv());
0165         data->priv()->collection = this;
0166     }
0167     else {
0168         delete data;
0169         data = new KoImageData(it.value());
0170     }
0171     return data;
0172 }
0173 
0174 bool KoImageCollection::fillFromKey(KoImageData &idata, qint64 key)
0175 {
0176     if (d->images.contains(key)) {
0177         idata = KoImageData(d->images.value(key));
0178         return true;
0179     }
0180     return false;
0181 }
0182 
0183 int KoImageCollection::size() const
0184 {
0185     return d->images.count();
0186 }
0187 
0188 int KoImageCollection::count() const
0189 {
0190     return d->images.count();
0191 }
0192 
0193 void KoImageCollection::update(qint64 oldKey, qint64 newKey)
0194 {
0195     if (oldKey == newKey) {
0196         return;
0197     }
0198     if (d->images.contains(oldKey)) {
0199         KoImageDataPrivate *imageData = d->images[oldKey];
0200         d->images.remove(oldKey);
0201         d->images.insert(newKey, imageData);
0202     }
0203 }
0204 
0205 void KoImageCollection::removeOnKey(qint64 imageDataKey)
0206 {
0207     d->images.remove(imageDataKey);
0208 }