Warning, file /office/calligra/libs/flake/KoShapeSavingContext.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) 2004-2006 David Faure <faure@kde.org>
0003    Copyright (C) 2007-2009, 2011 Thorsten Zachmann <zachmann@kde.org>
0004    Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
0005    Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "KoShapeSavingContext.h"
0024 #include "KoDataCenterBase.h"
0025 
0026 #include "KoShapeLayer.h"
0027 #include "KoImageData.h"
0028 #include "KoMarker.h"
0029 
0030 #include <KoXmlWriter.h>
0031 #include <KoStore.h>
0032 #include <KoStoreDevice.h>
0033 #include <KoSharedSavingData.h>
0034 #include <KoElementReference.h>
0035 
0036 
0037 #include <FlakeDebug.h>
0038 #include <QUuid>
0039 #include <QImage>
0040 #include <QMimeDatabase>
0041 #include <QMimeType>
0042 
0043 class KoShapeSavingContextPrivate {
0044 public:
0045     KoShapeSavingContextPrivate(KoXmlWriter&, KoGenStyles&, KoEmbeddedDocumentSaver&);
0046     ~KoShapeSavingContextPrivate();
0047 
0048     KoXmlWriter *xmlWriter;
0049     KoShapeSavingContext::ShapeSavingOptions savingOptions;
0050 
0051     QList<const KoShapeLayer*> layers;
0052     QSet<KoDataCenterBase *> dataCenters;
0053     QMap<QString, KoSharedSavingData*> sharedData;
0054 
0055     QMap<qint64, QString> imageNames;
0056     int imageId;
0057     QMap<QString, QImage> images;
0058 
0059     QHash<const KoShape *, QTransform> shapeOffsets;
0060     QMap<const KoMarker *, QString> markerRefs;
0061 
0062     KoGenStyles& mainStyles;
0063     KoEmbeddedDocumentSaver& embeddedSaver;
0064 
0065     QMap<const void*, KoElementReference> references;
0066     QMap<QString, int> referenceCounters;
0067     QMap<QString, QList<const void*> > prefixedReferences;
0068     QString styleFamily;
0069 };
0070 
0071 KoShapeSavingContextPrivate::KoShapeSavingContextPrivate(KoXmlWriter &w,
0072         KoGenStyles &s, KoEmbeddedDocumentSaver &e)
0073         : xmlWriter(&w),
0074         savingOptions(0),
0075         imageId(0),
0076         mainStyles(s),
0077         embeddedSaver(e)
0078 {
0079 }
0080 
0081 KoShapeSavingContextPrivate::~KoShapeSavingContextPrivate()
0082 {
0083     foreach(KoSharedSavingData * data, sharedData) {
0084         delete data;
0085     }
0086 }
0087 
0088 KoShapeSavingContext::KoShapeSavingContext(KoXmlWriter &xmlWriter, KoGenStyles &mainStyles,
0089         KoEmbeddedDocumentSaver &embeddedSaver)
0090     : d(new KoShapeSavingContextPrivate(xmlWriter, mainStyles, embeddedSaver))
0091 {
0092     // by default allow saving of draw:id + xml:id
0093     addOption(KoShapeSavingContext::DrawId);
0094 }
0095 
0096 KoShapeSavingContext::~KoShapeSavingContext()
0097 {
0098     delete d;
0099 }
0100 
0101 KoXmlWriter & KoShapeSavingContext::xmlWriter()
0102 {
0103     return *d->xmlWriter;
0104 }
0105 
0106 void KoShapeSavingContext::setXmlWriter(KoXmlWriter &xmlWriter)
0107 {
0108     d->xmlWriter = &xmlWriter;
0109 }
0110 
0111 KoGenStyles & KoShapeSavingContext::mainStyles()
0112 {
0113     return d->mainStyles;
0114 }
0115 
0116 KoEmbeddedDocumentSaver &KoShapeSavingContext::embeddedSaver()
0117 {
0118     return d->embeddedSaver;
0119 }
0120 
0121 bool KoShapeSavingContext::isSet(ShapeSavingOption option) const
0122 {
0123     return d->savingOptions & option;
0124 }
0125 
0126 void KoShapeSavingContext::setOptions(ShapeSavingOptions options)
0127 {
0128     d->savingOptions = options;
0129 }
0130 
0131 KoShapeSavingContext::ShapeSavingOptions KoShapeSavingContext::options() const
0132 {
0133     return d->savingOptions;
0134 }
0135 
0136 void KoShapeSavingContext::addOption(ShapeSavingOption option)
0137 {
0138     d->savingOptions = d->savingOptions | option;
0139 }
0140 
0141 void KoShapeSavingContext::removeOption(ShapeSavingOption option)
0142 {
0143     if (isSet(option))
0144         d->savingOptions = d->savingOptions ^ option; // xor to remove it.
0145 }
0146 
0147 KoElementReference KoShapeSavingContext::xmlid(const void *referent, const QString& prefix, KoElementReference::GenerationOption counter)
0148 {
0149     Q_ASSERT(counter == KoElementReference::UUID || (counter == KoElementReference::Counter && !prefix.isEmpty()));
0150 
0151     if (d->references.contains(referent)) {
0152         return d->references[referent];
0153     }
0154 
0155     KoElementReference ref;
0156 
0157     if (counter == KoElementReference::Counter) {
0158         int referenceCounter = d->referenceCounters[prefix];
0159         referenceCounter++;
0160         ref = KoElementReference(prefix, referenceCounter);
0161         d->references.insert(referent, ref);
0162         d->referenceCounters[prefix] = referenceCounter;
0163     }
0164     else {
0165         if (!prefix.isEmpty()) {
0166             ref = KoElementReference(prefix);
0167             d->references.insert(referent, ref);
0168         }
0169         else {
0170             d->references.insert(referent, ref);
0171         }
0172     }
0173 
0174     if (!prefix.isNull()) {
0175         d->prefixedReferences[prefix].append(referent);
0176     }
0177     return ref;
0178 }
0179 
0180 KoElementReference KoShapeSavingContext::existingXmlid(const void *referent)
0181 {
0182     if (d->references.contains(referent)) {
0183         return d->references[referent];
0184     }
0185     else {
0186         KoElementReference ref;
0187         ref.invalidate();
0188         return ref;
0189     }
0190 }
0191 
0192 void KoShapeSavingContext::clearXmlIds(const QString &prefix)
0193 {
0194 
0195     if (d->prefixedReferences.contains(prefix)) {
0196         foreach(const void* ptr, d->prefixedReferences[prefix]) {
0197             d->references.remove(ptr);
0198         }
0199         d->prefixedReferences.remove(prefix);
0200     }
0201 
0202     if (d->referenceCounters.contains(prefix)) {
0203         d->referenceCounters[prefix] = 0;
0204     }
0205 }
0206 
0207 void KoShapeSavingContext::addLayerForSaving(const KoShapeLayer *layer)
0208 {
0209     if (layer && ! d->layers.contains(layer))
0210         d->layers.append(layer);
0211 }
0212 
0213 void KoShapeSavingContext::saveLayerSet(KoXmlWriter &xmlWriter) const
0214 {
0215     xmlWriter.startElement("draw:layer-set");
0216     foreach(const KoShapeLayer * layer, d->layers) {
0217         xmlWriter.startElement("draw:layer");
0218         xmlWriter.addAttribute("draw:name", layer->name());
0219         if (layer->isGeometryProtected())
0220             xmlWriter.addAttribute("draw:protected", "true");
0221         if (! layer->isVisible())
0222             xmlWriter.addAttribute("draw:display", "none");
0223         xmlWriter.endElement();  // draw:layer
0224     }
0225     xmlWriter.endElement();  // draw:layer-set
0226 }
0227 
0228 void KoShapeSavingContext::clearLayers()
0229 {
0230     d->layers.clear();
0231 }
0232 
0233 QString KoShapeSavingContext::imageHref(const KoImageData *image)
0234 {
0235     QMap<qint64, QString>::iterator it(d->imageNames.find(image->key()));
0236     if (it == d->imageNames.end()) {
0237         QString suffix = image->suffix();
0238         if (suffix.isEmpty()) {
0239             it = d->imageNames.insert(image->key(), QString("Pictures/image%1").arg(++d->imageId));
0240         }
0241         else {
0242             it = d->imageNames.insert(image->key(), QString("Pictures/image%1.%2").arg(++d->imageId).arg(suffix));
0243         }
0244     }
0245     return it.value();
0246 }
0247 
0248 QString KoShapeSavingContext::imageHref(const QImage &image)
0249 {
0250     // TODO this can be optimized to recognize images which have the same content
0251     // Also this can use quite a lot of memeory as the qimage are all kept until
0252     // they are saved to the store in memory
0253     QString href = QString("Pictures/image%1.png").arg(++d->imageId);
0254     d->images.insert(href, image);
0255     return href;
0256 }
0257 
0258 QMap<qint64, QString> KoShapeSavingContext::imagesToSave()
0259 {
0260     return d->imageNames;
0261 }
0262 
0263 QString KoShapeSavingContext::markerRef(const KoMarker *marker)
0264 {
0265     QMap<const KoMarker *, QString>::iterator it = d->markerRefs.find(marker);
0266     if (it == d->markerRefs.end()) {
0267         it = d->markerRefs.insert(marker, marker->saveOdf(*this));
0268     }
0269 
0270     return it.value();
0271 }
0272 
0273 void KoShapeSavingContext::addDataCenter(KoDataCenterBase * dataCenter)
0274 {
0275     if (dataCenter) {
0276         d->dataCenters.insert(dataCenter);
0277     }
0278 }
0279 
0280 bool KoShapeSavingContext::saveDataCenter(KoStore *store, KoXmlWriter* manifestWriter)
0281 {
0282     bool ok = true;
0283     foreach(KoDataCenterBase *dataCenter, d->dataCenters) {
0284         ok = ok && dataCenter->completeSaving(store, manifestWriter, this);
0285         //debugFlake << "ok" << ok;
0286     }
0287 
0288     // Save images
0289     for (QMap<QString, QImage>::ConstIterator it(d->images.constBegin()); it != d->images.constEnd(); ++it) {
0290         if (store->open(it.key())) {
0291             KoStoreDevice device(store);
0292             ok = ok && it.value().save(&device, "PNG");
0293             store->close();
0294             // TODO error handling
0295             if (ok) {
0296                 QMimeDatabase db;
0297                 const QString mimetype(db.mimeTypeForFile(it.key(), QMimeDatabase::MatchExtension).name());
0298                 manifestWriter->addManifestEntry(it.key(), mimetype);
0299             }
0300             else {
0301                 warnFlake << "saving image failed";
0302             }
0303         }
0304         else {
0305             ok = false;
0306             warnFlake << "saving image failed: open store failed";
0307         }
0308     }
0309     return ok;
0310 }
0311 
0312 void KoShapeSavingContext::addSharedData(const QString &id, KoSharedSavingData * data)
0313 {
0314     QMap<QString, KoSharedSavingData*>::iterator it(d->sharedData.find(id));
0315     // data will not be overwritten
0316     if (it == d->sharedData.end()) {
0317         d->sharedData.insert(id, data);
0318     } else {
0319         warnFlake << "The id" << id << "is already registered. Data not inserted";
0320         Q_ASSERT(it == d->sharedData.end());
0321     }
0322 }
0323 
0324 KoSharedSavingData * KoShapeSavingContext::sharedData(const QString &id) const
0325 {
0326     KoSharedSavingData * data = 0;
0327     QMap<QString, KoSharedSavingData*>::const_iterator it(d->sharedData.constFind(id));
0328     if (it != d->sharedData.constEnd()) {
0329         data = it.value();
0330     }
0331     return data;
0332 }
0333 
0334 void KoShapeSavingContext::addShapeOffset(const KoShape *shape, const QTransform &m)
0335 {
0336     d->shapeOffsets.insert(shape, m);
0337 }
0338 
0339 void KoShapeSavingContext::removeShapeOffset(const KoShape *shape)
0340 {
0341     d->shapeOffsets.remove(shape);
0342 }
0343 
0344 QTransform KoShapeSavingContext::shapeOffset(const KoShape *shape) const
0345 {
0346     return d->shapeOffsets.value(shape, QTransform());
0347 }
0348 
0349 void KoShapeSavingContext::setStyleFamily(const QString &name)
0350 {
0351     d->styleFamily = name;
0352 }
0353 
0354 QString KoShapeSavingContext::styleFamily() const
0355 {
0356     if (isSet(PresentationShape)) {
0357         return "pr";
0358     }
0359     if (!d->styleFamily.isEmpty()) {
0360         return d->styleFamily;
0361     }
0362     return "gr";
0363 }