Warning, file /office/calligra/libs/odf/KoEmbeddedDocumentSaver.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 Thorsten Zachmann <zachmann@kde.org> 0004 Copyright (C) 2010 Thomas Zander <zander@kde.org> 0005 Copyright (C) 2011 Inge Wallin <inge@lysator.liu.se> 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 "KoEmbeddedDocumentSaver.h" 0024 0025 #include <QList> 0026 0027 #include <OdfDebug.h> 0028 #include <QUrl> 0029 0030 #include <KoStore.h> 0031 #include <KoXmlWriter.h> 0032 #include <KoOdfWriteStore.h> 0033 0034 #include "KoDocumentBase.h" 0035 #include <KoOdfManifestEntry.h> 0036 0037 0038 #define INTERNAL_PROTOCOL "intern" 0039 0040 struct FileEntry { 0041 QString path; 0042 QByteArray mimeType; // QBA because this is what addManifestEntry wants 0043 QByteArray contents; 0044 }; 0045 0046 0047 class Q_DECL_HIDDEN KoEmbeddedDocumentSaver::Private 0048 { 0049 public: 0050 Private() {} 0051 0052 QHash<QString, int> prefixes; // Used in getFilename(); 0053 0054 // These will be saved when saveEmbeddedDocuments() is called. 0055 QList<KoDocumentBase*> documents; // Embedded documents 0056 QList<FileEntry*> files; // Embedded files. 0057 QList<KoOdfManifestEntry*> manifestEntries; 0058 }; 0059 0060 KoEmbeddedDocumentSaver::KoEmbeddedDocumentSaver() 0061 : d(new Private()) 0062 { 0063 } 0064 0065 KoEmbeddedDocumentSaver::~KoEmbeddedDocumentSaver() 0066 { 0067 qDeleteAll(d->files); 0068 qDeleteAll(d->manifestEntries); 0069 delete d; 0070 } 0071 0072 0073 QString KoEmbeddedDocumentSaver::getFilename(const QString &prefix) 0074 { 0075 int index = 1; 0076 if (d->prefixes.contains(prefix)) { 0077 index = d->prefixes.value(prefix); 0078 } 0079 0080 // This inserts prefix into the map if it's not there. 0081 d->prefixes[prefix] = index + 1; 0082 0083 //return prefix + QString("%1").arg(index, 4, 10, QChar('0')); 0084 return prefix + QString("%1").arg(index); 0085 } 0086 0087 void KoEmbeddedDocumentSaver::embedDocument(KoXmlWriter &writer, KoDocumentBase * doc) 0088 { 0089 Q_ASSERT(doc); 0090 d->documents.append(doc); 0091 0092 QString ref; 0093 if (!doc->isStoredExtern()) { 0094 const QString name = getFilename("Object "); 0095 0096 // set URL in document so that saveEmbeddedDocuments will save 0097 // the actual embedded object with the right name in the store. 0098 QUrl u; 0099 u.setScheme(INTERNAL_PROTOCOL); 0100 u.setPath(name); 0101 debugOdf << u; 0102 doc->setUrl(u); 0103 ref = "./" + name; 0104 } else { 0105 ref = doc->url().url(); 0106 } 0107 0108 debugOdf << "saving reference to embedded document as" << ref; 0109 writer.addAttribute("xlink:href", /*"#" + */ref); 0110 0111 //<draw:object xlink:type="simple" xlink:show="embed" 0112 // xlink:actuate="onLoad" xlink:href="#./Object 1"/> 0113 writer.addAttribute("xlink:type", "simple"); 0114 writer.addAttribute("xlink:show", "embed"); 0115 writer.addAttribute("xlink:actuate", "onLoad"); 0116 0117 } 0118 0119 // Examples: 0120 // Videos/Video1.mov ← the number is autogenerated 0121 // Videos/Video2.mov 0122 // Object1/foo ← the number is autogenerated 0123 // Object1/bar 0124 0125 // Note: The contents QByteArray is implicitly shared. It needs to be 0126 // copied since otherwise the actual array may disappear before 0127 // the real saving is done. 0128 // 0129 void KoEmbeddedDocumentSaver::embedFile(KoXmlWriter &writer, const char *element, 0130 const QString &path, const QByteArray &mimeType, 0131 const QByteArray &contents) 0132 { 0133 // Put the file in the list of files to be written to the store later. 0134 FileEntry *entry = new FileEntry; 0135 entry->mimeType = mimeType; 0136 entry->path = path; 0137 entry->contents = contents; 0138 d->files.append(entry); 0139 0140 writer.startElement(element); 0141 // Write the attributes that refer to the file. 0142 0143 //<draw:object xlink:href="#./Object 1" xlink:type="simple" xlink:show="embed" 0144 // xlink:actuate="onLoad"/> 0145 writer.addAttribute("xlink:type", "simple"); 0146 writer.addAttribute("xlink:show", "embed"); 0147 writer.addAttribute("xlink:actuate", "onLoad"); 0148 0149 debugOdf << "saving reference to embedded file as" << path; 0150 writer.addAttribute("xlink:href", path); 0151 writer.endElement(); 0152 } 0153 0154 void KoEmbeddedDocumentSaver::saveFile(const QString &path, const QByteArray &mimeType, 0155 const QByteArray &contents) 0156 { 0157 // Put the file in the list of files to be written to the store later. 0158 FileEntry *entry = new FileEntry; 0159 entry->mimeType = mimeType; 0160 entry->path = path; 0161 entry->contents = contents; 0162 d->files.append(entry); 0163 0164 debugOdf << "saving reference to embedded file as" << path; 0165 } 0166 0167 /** 0168 * 0169 */ 0170 void KoEmbeddedDocumentSaver::saveManifestEntry(const QString &fullPath, const QString &mediaType, 0171 const QString &version) 0172 { 0173 d->manifestEntries.append(new KoOdfManifestEntry(fullPath, mediaType, version)); 0174 } 0175 0176 0177 bool KoEmbeddedDocumentSaver::saveEmbeddedDocuments(KoDocumentBase::SavingContext & documentContext) 0178 { 0179 KoStore *store = documentContext.odfStore.store(); 0180 0181 // Write embedded documents. 0182 foreach(KoDocumentBase *doc, d->documents) { 0183 QString path; 0184 if (doc->isStoredExtern()) { 0185 debugOdf << " external (don't save) url:" << doc->url().url(); 0186 path = doc->url().url(); 0187 } else { 0188 // The name comes from addEmbeddedDocument (which was set while saving the document). 0189 Q_ASSERT(doc->url().scheme() == INTERNAL_PROTOCOL); 0190 const QString name = doc->url().path(); 0191 debugOdf << "saving" << name; 0192 0193 if (doc->nativeOasisMimeType().isEmpty()) { 0194 // Embedded object doesn't support OpenDocument, save in the old format. 0195 debugOdf << "Embedded object doesn't support OpenDocument, save in the old format."; 0196 0197 if (!doc->saveToStore(store, name)) { 0198 return false; 0199 } 0200 } else { 0201 // To make the children happy cd to the correct directory 0202 store->pushDirectory(); 0203 store->enterDirectory(name); 0204 0205 bool ok = doc->saveOdf(documentContext); 0206 0207 // Now that we're done leave the directory again 0208 store->popDirectory(); 0209 0210 if (!ok) { 0211 warnOdf << "KoEmbeddedDocumentSaver::saveEmbeddedDocuments failed"; 0212 return false; 0213 } 0214 } 0215 0216 Q_ASSERT(doc->url().scheme() == INTERNAL_PROTOCOL); 0217 path = store->currentPath(); 0218 if (!path.isEmpty()) { 0219 path += '/'; 0220 } 0221 path += doc->url().path(); 0222 if (path.startsWith(QLatin1Char('/'))) { 0223 path.remove(0, 1); // remove leading '/', no wanted in manifest 0224 } 0225 } 0226 0227 // OOo uses a trailing slash for the path to embedded objects (== directories) 0228 if (!path.endsWith('/')) { 0229 path += '/'; 0230 } 0231 QByteArray mimetype = doc->nativeOasisMimeType(); 0232 documentContext.odfStore.manifestWriter()->addManifestEntry(path, mimetype); 0233 } 0234 0235 // Write the embedded files. 0236 foreach(FileEntry *entry, d->files) { 0237 QString path = entry->path; 0238 debugOdf << "saving" << path; 0239 0240 // To make the children happy cd to the correct directory 0241 store->pushDirectory(); 0242 0243 int index = path.lastIndexOf('/'); 0244 const QString dirPath = path.left(index); 0245 const QString fileName = path.right(path.size() - index - 1); 0246 store->enterDirectory(dirPath); 0247 0248 if (!store->open(fileName)) { 0249 return false; 0250 } 0251 store->write(entry->contents); 0252 store->close(); 0253 0254 // Now that we're done leave the directory again 0255 store->popDirectory(); 0256 0257 // Create the manifest entry. 0258 if (path.startsWith(QLatin1String("./"))) { 0259 path.remove(0, 2); // remove leading './', not wanted in manifest 0260 } 0261 documentContext.odfStore.manifestWriter()->addManifestEntry(path, entry->mimeType); 0262 } 0263 0264 // Write the manifest entries. 0265 KoXmlWriter *manifestWriter = documentContext.odfStore.manifestWriter(); 0266 foreach(KoOdfManifestEntry *entry, d->manifestEntries) { 0267 manifestWriter->startElement("manifest:file-entry"); 0268 manifestWriter->addAttribute("manifest:version", entry->version()); 0269 manifestWriter->addAttribute("manifest:media-type", entry->mediaType()); 0270 manifestWriter->addAttribute("manifest:full-path", entry->fullPath()); 0271 manifestWriter->endElement(); // manifest:file-entry 0272 } 0273 0274 return true; 0275 }