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 }