Warning, file /office/calligra/libs/flake/KoUnavailShape.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 * 0003 * Copyright (C) 2010-2011 Inge Wallin <inge@lysator.liu.se> 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 0021 0022 // Own 0023 #include "KoUnavailShape.h" 0024 0025 // Qt 0026 #include <QPen> 0027 #include <QPainter> 0028 #include <QPainterPath> 0029 #include <QByteArray> 0030 #include <QBuffer> 0031 #include <QDataStream> 0032 #include <QPixmap> 0033 #include <QStringList> 0034 #include <QSvgRenderer> 0035 #include <QStandardPaths> 0036 0037 // Calligra 0038 #include <KoUnit.h> 0039 #include <KoStore.h> 0040 #include <KoXmlReader.h> 0041 #include <KoXmlWriter.h> 0042 #include <KoXmlNS.h> 0043 #include <KoOdfManifestEntry.h> 0044 #include <KoOdfLoadingContext.h> 0045 #include <KoEmbeddedDocumentSaver.h> 0046 #include "KoShapeLoadingContext.h" 0047 #include "KoShapeSavingContext.h" 0048 #include "KoShapeContainerDefaultModel.h" 0049 #include "KoShapeBackground.h" 0050 0051 #include <FlakeDebug.h> 0052 0053 0054 // The XML of a frame looks something like this: 0055 // 0056 // 1. <draw:frame ...attributes...> 0057 // 2. <draw:object xlink:href="./Object1" ...more attributes> 0058 // 3. <draw:image xlink:href="./ObjectReplacements/Object1" ...more attributes> 0059 // 4. </draw:frame> 0060 // 0061 // or 0062 // 0063 // 1. <draw:frame ...attributes...> 0064 // 2. <math:math>...inline xml here...</math:math> 0065 // 3. <draw:image xlink:href="./ObjectReplacements/Object1" ...more attributes> 0066 // 4. </draw:frame> 0067 // 0068 // We define each Xml statement on lines 2 and 3 above as an "object". 0069 // (Strictly only the first child element is an object in the ODF sense, 0070 // but we have to have some terminology here.) 0071 // 0072 // In an ODF frame, only the first line, i.e. the first object 0073 // contains the real contents. All the rest of the objects are used / 0074 // shown if we cannot handle the first one. The most common cases are 0075 // that there is only one object inside the frame OR that there are 2 0076 // and the 2nd is a picture. 0077 // 0078 // Sometimes, e.g. in the case of an embedded document, the reference 0079 // points not to a file but to a directory structure inside the ODF 0080 // store. 0081 // 0082 // When we load and save in the UnavailShape, we have to be general 0083 // enough to cover all possible cases of references and inline XML, 0084 // embedded files and embedded directory structures. 0085 // 0086 // We also have to be careful because we cannot reuse the object names 0087 // that are in the original files when saving. Instead we need to 0088 // create new object names because the ones that were used in the 0089 // original file may already be used by other embedded files/objects 0090 // that are saved by other shapes. 0091 // 0092 // FIXME: There should only be ONE place where new object / file names 0093 // are generated, not 2(?) like there are now: 0094 // KoEmbeddedDocumentSaver and the KoImageCollection. 0095 // 0096 0097 0098 // An ObjectEntry is used to store information about objects in the 0099 // frame, as defined above. 0100 struct ObjectEntry { 0101 QByteArray objectXmlContents; // the XML tree in the object 0102 QString objectName; // object name in the frame without "./" 0103 // This is extracted from objectXmlContents. 0104 bool isDir; 0105 KoOdfManifestEntry *manifestEntry; // manifest entry for the above. 0106 }; 0107 0108 // A FileEntry is used to store information about embedded files 0109 // inside (i.e. referred to by) an object. 0110 struct FileEntry { 0111 QString path; // Normalized filename, i.e. without "./". 0112 QString mimeType; 0113 bool isDir; 0114 QByteArray contents; 0115 }; 0116 0117 0118 class KoUnavailShape::Private 0119 { 0120 public: 0121 Private(KoUnavailShape* qq); 0122 ~Private(); 0123 0124 void draw(QPainter &painter) const; 0125 void drawNull(QPainter &painter) const; 0126 0127 void storeObjects(const KoXmlElement &element); 0128 void storeXmlRecursive(const KoXmlElement &el, KoXmlWriter &writer, 0129 ObjectEntry *object, QHash<QString, QString> &unknownNamespaces); 0130 void storeFile(const QString &filename, KoShapeLoadingContext &context); 0131 QByteArray loadFile(const QString &filename, KoShapeLoadingContext &context); 0132 0133 // Objects inside the frame. For each file, we store: 0134 // - The XML code for the object 0135 // - Any embedded files (names, contents) that are referenced by xlink:href 0136 // - Whether they are directories, i.e. if they contain a file tree and not just one file. 0137 // - The manifest entries 0138 QList<ObjectEntry*> objectEntries; 0139 0140 // Embedded files 0141 QList<FileEntry*> embeddedFiles; // List of embedded files. 0142 0143 // Some cached values. 0144 QPixmap questionMark; 0145 QPixmap pixmapPreview; 0146 QSvgRenderer *scalablePreview; 0147 0148 KoUnavailShape* q; 0149 }; 0150 0151 KoUnavailShape::Private::Private(KoUnavailShape* qq) 0152 : scalablePreview(new QSvgRenderer()) 0153 , q(qq) 0154 { 0155 // Get the question mark "icon". 0156 questionMark.load(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligra/pics/questionmark.png")); 0157 } 0158 0159 KoUnavailShape::Private::~Private() 0160 { 0161 qDeleteAll(objectEntries); 0162 qDeleteAll(embeddedFiles); 0163 0164 // It's a QObject, but we haven't parented it. 0165 delete(scalablePreview); 0166 } 0167 0168 0169 // ---------------------------------------------------------------- 0170 // The main class 0171 0172 0173 KoUnavailShape::KoUnavailShape() 0174 : KoFrameShape( "", "" ) 0175 , KoShapeContainer(new KoShapeContainerDefaultModel()) 0176 , d(new Private(this)) 0177 { 0178 setShapeId(KoUnavailShape_SHAPEID); 0179 0180 // Default size of the shape. 0181 KoShape::setSize( QSizeF( CM_TO_POINT( 5 ), CM_TO_POINT( 3 ) ) ); 0182 } 0183 0184 KoUnavailShape::~KoUnavailShape() 0185 { 0186 delete d; 0187 } 0188 0189 0190 void KoUnavailShape::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) 0191 { 0192 applyConversion(painter, converter); 0193 0194 // If the frame is empty, just draw a background. 0195 debugFlake << "Number of objects:" << d->objectEntries.size(); 0196 if (d->objectEntries.isEmpty()) { 0197 // But... only try to draw the background if there's one such 0198 if (background()) { 0199 QPainterPath p; 0200 p.addRect(QRectF(QPointF(), size())); 0201 background()->paint(painter, converter, paintContext, p); 0202 } 0203 } else { 0204 if(shapes().isEmpty()) { 0205 d->draw(painter); 0206 } 0207 } 0208 } 0209 0210 void KoUnavailShape::paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &) 0211 { 0212 Q_UNUSED(painter); 0213 Q_UNUSED(converter); 0214 } 0215 0216 void KoUnavailShape::Private::draw(QPainter &painter) const 0217 { 0218 painter.save(); 0219 painter.setRenderHint(QPainter::Antialiasing); 0220 // Run through the previews in order of preference. Draw a placeholder 0221 // questionmark if there is no preview available for rendering. 0222 if (scalablePreview->isValid()) { 0223 QRect bounds(0, 0, q->boundingRect().width(), q->boundingRect().height()); 0224 scalablePreview->render(&painter, bounds); 0225 } 0226 else if (!pixmapPreview.isNull()) { 0227 QRect bounds(0, 0, q->boundingRect().width(), q->boundingRect().height()); 0228 painter.setRenderHint(QPainter::SmoothPixmapTransform); 0229 painter.drawPixmap(bounds, pixmapPreview); 0230 } 0231 else if (q->shapes().isEmpty()) { 0232 // Draw a nice question mark with a frame around it if there 0233 // is no other preview image. If there is a contained image 0234 // shape, we don't need to draw anything. 0235 0236 // Get the question mark "icon". 0237 // FIXME: We should be able to use d->questionMark here. 0238 QPixmap questionMark; 0239 questionMark.load(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligra/pics/questionmark.png")); 0240 0241 // The size of the image is: 0242 // - the size of the shape if shapesize < 2cm 0243 // - 2 cm if 2cm <= shapesize <= 8cm 0244 // - shapesize / 4 if shapesize > 8cm 0245 qreal width = q->size().width(); 0246 qreal height = q->size().height(); 0247 qreal picSize = CM_TO_POINT(2); // Default size is 2 cm. 0248 if (width < CM_TO_POINT(2) || height < CM_TO_POINT(2)) 0249 picSize = qMin(width, height); 0250 else if (width > CM_TO_POINT(8) && height > CM_TO_POINT(8)) 0251 picSize = qMin(width, height) / qreal(4.0); 0252 0253 painter.drawPixmap((width - picSize) / qreal(2.0), (height - picSize) / qreal(2.0), 0254 picSize, picSize, questionMark); 0255 0256 // Draw a gray rectangle around the shape. 0257 painter.setPen(QPen(QColor(172, 196, 206), 0)); 0258 painter.drawRect(QRectF(QPointF(0,0), q->size())); 0259 0260 } 0261 painter.restore(); 0262 } 0263 0264 void KoUnavailShape::Private::drawNull(QPainter &painter) const 0265 { 0266 QRectF rect(QPointF(0,0), q->size()); 0267 painter.save(); 0268 0269 // Draw a simple cross in a rectangle just to indicate that there is something here. 0270 painter.drawLine(rect.topLeft(), rect.bottomRight()); 0271 painter.drawLine(rect.bottomLeft(), rect.topRight()); 0272 0273 painter.restore(); 0274 } 0275 0276 0277 // ---------------------------------------------------------------- 0278 // Loading and Saving 0279 0280 0281 void KoUnavailShape::saveOdf(KoShapeSavingContext & context) const 0282 { 0283 debugFlake << "START SAVING ##################################################"; 0284 0285 KoEmbeddedDocumentSaver &fileSaver = context.embeddedSaver(); 0286 KoXmlWriter &writer = context.xmlWriter(); 0287 0288 writer.startElement("draw:frame"); 0289 0290 // See also loadOdf() in loadOdfAttributes. 0291 saveOdfAttributes( context, OdfAllAttributes ); 0292 0293 // Write the stored XML to the file, but don't reuse object names. 0294 int lap = 0; 0295 QString newName; 0296 foreach (const ObjectEntry *object, d->objectEntries) { 0297 QByteArray xmlArray(object->objectXmlContents); 0298 QString objectName(object->objectName); // Possibly empty. 0299 KoOdfManifestEntry *manifestEntry(object->manifestEntry); 0300 0301 // Create a name for this object. If this is not the first 0302 // object, i.e. a replacement object (most likely a picture), 0303 // then reuse the name but put it in ReplacementObjects. 0304 if (++lap == 1) { 0305 // The first lap in the loop is the actual object. All 0306 // other laps are replacement objects. 0307 newName = fileSaver.getFilename("Object "); 0308 } 0309 else if (lap == 2) { 0310 newName = "ObjectReplacements/" + newName; 0311 } 0312 else 0313 // FIXME: what should replacement 2 and onwards be called? 0314 newName = newName + "_"; 0315 0316 // If there was a previous object name, replace it with the new one. 0317 if (!objectName.isEmpty() && manifestEntry) { 0318 // FIXME: We must make a copy of the byte array here because 0319 // otherwise we won't be able to save > 1 time. 0320 xmlArray.replace(objectName.toLatin1(), newName.toLatin1()); 0321 } 0322 0323 writer.addCompleteElement(xmlArray.data()); 0324 0325 // If the objectName is empty, this may be inline XML. 0326 // If so, we are done now. 0327 if (objectName.isEmpty() || !manifestEntry) { 0328 continue; 0329 } 0330 0331 // Save embedded files for this object. 0332 foreach (FileEntry *entry, d->embeddedFiles) { 0333 QString fileName(entry->path); 0334 0335 // If we found a file for this object, we need to write it 0336 // but with the new object name instead of the old one. 0337 if (!fileName.startsWith(objectName)) 0338 continue; 0339 0340 debugFlake << "Object name: " << objectName << "newName: " << newName 0341 << "filename: " << fileName << "isDir: " << entry->isDir; 0342 0343 fileName.replace(objectName, newName); 0344 fileName.prepend("./"); 0345 debugFlake << "New filename: " << fileName; 0346 0347 // FIXME: Check if we need special treatment of directories. 0348 fileSaver.saveFile(fileName, entry->mimeType.toLatin1(), entry->contents); 0349 } 0350 0351 // Write the manifest entry for the object itself. If it's a 0352 // file, the manifest is already written by saveFile, so skip 0353 // it here. 0354 if (object->isDir) { 0355 fileSaver.saveManifestEntry(newName + '/', manifestEntry->mediaType(), 0356 manifestEntry->version()); 0357 } 0358 } 0359 0360 writer.endElement(); // draw:frame 0361 } 0362 0363 0364 bool KoUnavailShape::loadOdf(const KoXmlElement &frameElement, KoShapeLoadingContext &context) 0365 { 0366 debugFlake << "START LOADING ##################################################"; 0367 //debugFlake << "Loading ODF frame in the KoUnavailShape. Element = " 0368 // << frameElement.tagName(); 0369 0370 loadOdfAttributes(frameElement, context, OdfAllAttributes); 0371 0372 // NOTE: We cannot use loadOdfFrame() because we want to save all 0373 // the things inside the frame, not just one of them, like 0374 // loadOdfFrame() provides. 0375 0376 // Get the manifest. 0377 QList<KoOdfManifestEntry*> manifest = context.odfLoadingContext().manifestEntries(); 0378 0379 #if 0 // Enable to show all manifest entries. 0380 debugFlake << "MANIFEST: "; 0381 foreach (KoOdfManifestEntry *entry, manifest) { 0382 debugFlake << entry->mediaType() << entry->fullPath() << entry->version(); 0383 } 0384 #endif 0385 0386 // 1. Get the XML contents of the objects from the draw:frame. As 0387 // a side effect, this extracts the object names from all 0388 // xlink:href and stores them into d->objectNames. The saved 0389 // xml contents itself is saved into d->objectXmlContents 0390 // (QByteArray) so we can save it back from saveOdf(). 0391 d->storeObjects(frameElement); 0392 0393 #if 1 0394 // Debug only 0395 debugFlake << "----------------------------------------------------------------"; 0396 debugFlake << "After storeObjects():"; 0397 foreach (ObjectEntry *object, d->objectEntries) { 0398 debugFlake << "objectXmlContents: " << object->objectXmlContents 0399 << "objectName: " << object->objectName; 0400 // Note: at this point, isDir and manifestEntry are not set. 0401 #endif 0402 } 0403 0404 // 2. Loop through the objects that were found in the frame and 0405 // save all the files associated with them. Some of the 0406 // objects are files, and some are directories. The 0407 // directories are searched and the files within are saved as 0408 // well. 0409 // 0410 // In this loop, isDir and manifestEntry of each ObjectEntry are set. 0411 bool foundPreview = false; 0412 foreach (ObjectEntry *object, d->objectEntries) { 0413 QString objectName = object->objectName; 0414 0415 if (objectName.isEmpty()) 0416 continue; 0417 0418 debugFlake << "Storing files for object named:" << objectName; 0419 0420 // Try to find out if the entry is a directory. 0421 // If the object is a directory, then save all the files 0422 // inside it, otherwise save the file as it is. 0423 QString dirName = objectName + '/'; 0424 bool isDir = !context.odfLoadingContext().mimeTypeForPath(dirName).isEmpty(); 0425 if (isDir) { 0426 // A directory: the files can be found in the manifest. 0427 foreach (KoOdfManifestEntry *entry, manifest) { 0428 if (entry->fullPath() == dirName) 0429 continue; 0430 0431 if (entry->fullPath().startsWith(dirName)) { 0432 d->storeFile(entry->fullPath(), context); 0433 } 0434 } 0435 } 0436 else { 0437 // A file: save it. 0438 d->storeFile(objectName, context); 0439 } 0440 0441 // Get the manifest entry for this object. 0442 KoOdfManifestEntry *entry = 0; 0443 QString entryName = isDir ? dirName : objectName; 0444 for (int j = 0; j < manifest.size(); ++j) { 0445 KoOdfManifestEntry *temp = manifest.value(j); 0446 0447 if (temp->fullPath() == entryName) { 0448 entry = new KoOdfManifestEntry(*temp); 0449 break; 0450 } 0451 } 0452 object->isDir = isDir; 0453 object->manifestEntry = entry; 0454 0455 // If we have not already found a preview in previous times 0456 // through the loop, then see if this one may be a preview. 0457 if (!foundPreview) { 0458 debugFlake << "Attempting to load preview from " << objectName; 0459 QByteArray previewData = d->loadFile(objectName, context); 0460 // Check to see if we know the mimetype for this entry. Specifically: 0461 // 1. Check to see if the item is a loadable SVG file 0462 0463 // FIXME: Perhaps check in the manifest first? But this 0464 // seems to work well. 0465 d->scalablePreview->load(previewData); 0466 if (d->scalablePreview->isValid()) { 0467 debugFlake << "Found scalable preview image!"; 0468 d->scalablePreview->setViewBox(d->scalablePreview->boundsOnElement("svg")); 0469 foundPreview = true; 0470 continue; 0471 } 0472 // 2. Otherwise check to see if it's a loadable pixmap file 0473 d->pixmapPreview.loadFromData(previewData); 0474 if (!d->pixmapPreview.isNull()) { 0475 debugFlake << "Found pixel based preview image!"; 0476 foundPreview = true; 0477 } 0478 } 0479 } 0480 0481 #if 0 // Enable to get more detailed debug messages 0482 debugFlake << "Object manifest entries:"; 0483 for (int i = 0; i < d->manifestEntries.size(); ++i) { 0484 KoOdfManifestEntry *entry = d->manifestEntries.value(i); 0485 debugFlake << i << ":" << entry; 0486 if (entry) 0487 debugFlake << entry->fullPath() << entry->mediaType() << entry->version(); 0488 else 0489 debugFlake << "--"; 0490 } 0491 debugFlake << "END LOADING ####################################################"; 0492 #endif 0493 0494 return true; 0495 } 0496 0497 0498 // Load the actual contents inside the frame. 0499 bool KoUnavailShape::loadOdfFrameElement(const KoXmlElement & /*element*/, 0500 KoShapeLoadingContext &/*context*/) 0501 { 0502 return true; 0503 } 0504 0505 0506 // ---------------------------------------------------------------- 0507 // Private functions 0508 0509 void KoUnavailShape::Private::storeObjects(const KoXmlElement &element) 0510 { 0511 // Loop through all the child elements of the draw:frame and save them. 0512 KoXmlNode n = element.firstChild(); 0513 for (; !n.isNull(); n = n.nextSibling()) { 0514 debugFlake << "In draw:frame, node =" << n.nodeName(); 0515 0516 // This disregards #text, but that's not in the spec anyway so 0517 // it doesn't need to be saved. 0518 if (!n.isElement()) 0519 continue; 0520 KoXmlElement el = n.toElement(); 0521 0522 ObjectEntry *object = new ObjectEntry; 0523 0524 QByteArray contentsTmp; 0525 QBuffer buffer(&contentsTmp); // the member 0526 KoXmlWriter writer(&buffer); 0527 0528 // 1. Find out the objectName 0529 // Save the normalized filename, i.e. without a starting "./". 0530 // An empty string is saved if no name is found. 0531 QString name = el.attributeNS(KoXmlNS::xlink, "href", QString()); 0532 if (name.startsWith(QLatin1String("./"))) 0533 name.remove(0, 2); 0534 object->objectName = name; 0535 0536 // 2. Copy the XML code. 0537 QHash<QString, QString> unknownNamespaces; 0538 storeXmlRecursive(el, writer, object, unknownNamespaces); 0539 object->objectXmlContents = contentsTmp; 0540 0541 // 3, 4: the isDir and manifestEntry members are not set here, 0542 // but initialize them anyway. . 0543 object->isDir = false; // Has to be initialized to something. 0544 object->manifestEntry = 0; 0545 0546 objectEntries.append(object); 0547 } 0548 } 0549 0550 void KoUnavailShape::Private::storeXmlRecursive(const KoXmlElement &el, KoXmlWriter &writer, 0551 ObjectEntry *object, QHash<QString, QString> &unknownNamespaces) 0552 { 0553 // Start the element; 0554 // keep the name in a QByteArray so that it stays valid until end element is called. 0555 const QByteArray name(el.nodeName().toLatin1()); 0556 writer.startElement(name.constData()); 0557 0558 // Copy all the attributes, including namespaces. 0559 QList< QPair<QString, QString> > attributeNames = el.attributeFullNames(); 0560 for (int i = 0; i < attributeNames.size(); ++i) { 0561 QPair<QString, QString> attrPair(attributeNames.value(i)); 0562 if (attrPair.first.isEmpty()) { 0563 writer.addAttribute(attrPair.second.toLatin1(), el.attribute(attrPair.second)); 0564 } 0565 else { 0566 // This somewhat convoluted code is because we need the 0567 // namespace, not the namespace URI. 0568 QString nsShort = KoXmlNS::nsURI2NS(attrPair.first.toLatin1()); 0569 // in case we don't find the namespace in our list create a own one and use that 0570 // so the document created on saving is valid. 0571 if (nsShort.isEmpty()) { 0572 nsShort = unknownNamespaces.value(attrPair.first); 0573 if (nsShort.isEmpty()) { 0574 nsShort = QString("ns%1").arg(unknownNamespaces.size() + 1); 0575 unknownNamespaces.insert(attrPair.first, nsShort); 0576 } 0577 QString name = QString("xmlns:") + nsShort; 0578 writer.addAttribute(name.toLatin1(), attrPair.first.toLatin1()); 0579 } 0580 QString attr(nsShort + ':' + attrPair.second); 0581 writer.addAttribute(attr.toLatin1(), el.attributeNS(attrPair.first, 0582 attrPair.second)); 0583 } 0584 } 0585 0586 // Child elements 0587 // Loop through all the child elements of the draw:frame. 0588 KoXmlNode n = el.firstChild(); 0589 for (; !n.isNull(); n = n.nextSibling()) { 0590 if (n.isElement()) { 0591 storeXmlRecursive(n.toElement(), writer, object, unknownNamespaces); 0592 } 0593 else if (n.isText()) { 0594 writer.addTextNode(n.toText().data()/*.toUtf8()*/); 0595 } 0596 } 0597 0598 // End the element 0599 writer.endElement(); 0600 } 0601 0602 /** 0603 * This function stores the embedded file in an internal store - it does not save files to disk, 0604 * and thus it is named in this manner, to avoid the function being confused with functions which 0605 * save files to disk. 0606 */ 0607 void KoUnavailShape::Private::storeFile(const QString &fileName, KoShapeLoadingContext &context) 0608 { 0609 debugFlake << "Saving file: " << fileName; 0610 0611 // Directories need to be saved too, but they don't have any file contents. 0612 if (fileName.endsWith('/')) { 0613 FileEntry *entry = new FileEntry; 0614 entry->path = fileName; 0615 entry->mimeType = context.odfLoadingContext().mimeTypeForPath(entry->path); 0616 entry->isDir = true; 0617 embeddedFiles.append(entry); 0618 } 0619 0620 QByteArray fileContent = loadFile(fileName, context); 0621 if (fileContent.isNull()) 0622 return; 0623 0624 // Actually store the file in the list. 0625 FileEntry *entry = new FileEntry; 0626 entry->path = fileName; 0627 if (entry->path.startsWith(QLatin1String("./"))) 0628 entry->path.remove(0, 2); 0629 entry->mimeType = context.odfLoadingContext().mimeTypeForPath(entry->path); 0630 entry->isDir = false; 0631 entry->contents = fileContent; 0632 embeddedFiles.append(entry); 0633 0634 debugFlake << "File length: " << fileContent.size(); 0635 } 0636 0637 QByteArray KoUnavailShape::Private::loadFile(const QString &fileName, KoShapeLoadingContext &context) 0638 { 0639 // Can't load a file which is a directory, return an invalid QByteArray 0640 if (fileName.endsWith('/')) 0641 return QByteArray(); 0642 0643 KoStore *store = context.odfLoadingContext().store(); 0644 QByteArray fileContent; 0645 0646 if (!store->open(fileName)) { 0647 store->close(); 0648 return QByteArray(); 0649 } 0650 0651 int fileSize = store->size(); 0652 fileContent = store->read(fileSize); 0653 store->close(); 0654 0655 //debugFlake << "File content: " << fileContent; 0656 return fileContent; 0657 }