File indexing completed on 2025-01-12 13:05:53
0001 /* This file is part of the KDE project 0002 Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> 0003 Copyright (c) 2003 Lukas Tinkl <lukas@kde.org> 0004 Copyright (c) 2003 David Faure <faure@kde.org> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 0022 #include "ooutils.h" 0023 #include <KoStyleStack.h> 0024 #include <KoXmlReader.h> 0025 #include <QDomDocument> 0026 #include <QColor> 0027 #include <QImage> 0028 #include <KoUnit.h> 0029 #include <QRegExp> 0030 #include <kdebug.h> 0031 #include <kzip.h> 0032 0033 const char ooNS::office[] = "http://openoffice.org/2000/office"; 0034 const char ooNS::style[] = "http://openoffice.org/2000/style"; 0035 const char ooNS::text[] = "http://openoffice.org/2000/text"; 0036 const char ooNS::table[] = "http://openoffice.org/2000/table"; 0037 const char ooNS::draw[] = "http://openoffice.org/2000/drawing"; 0038 const char ooNS::presentation[] = "http://openoffice.org/2000/presentation"; 0039 const char ooNS::fo[] = "http://www.w3.org/1999/XSL/Format"; 0040 const char ooNS::xlink[] = "http://www.w3.org/1999/xlink"; 0041 const char ooNS::number[] = "http://openoffice.org/2000/datastyle"; 0042 const char ooNS::svg[] = "http://www.w3.org/2000/svg"; 0043 const char ooNS::dc[] = "http://purl.org/dc/elements/1.1/"; 0044 const char ooNS::meta[] = "http://openoffice.org/2000/meta"; 0045 const char ooNS::config[] = "http://openoffice.org/2001/config"; 0046 0047 QString OoUtils::expandWhitespace(const KoXmlElement& tag) 0048 { 0049 //tags like <text:s text:c="4"> 0050 0051 int howmany = 1; 0052 if (tag.hasAttributeNS(ooNS::text, "c")) 0053 howmany = tag.attributeNS(ooNS::text, "c", QString()).toInt(); 0054 0055 QString result; 0056 return result.fill(32, howmany); 0057 } 0058 0059 bool OoUtils::parseBorder(const QString & tag, double * width, int * style, QColor * color) 0060 { 0061 //string like "0.088cm solid #800000" 0062 0063 if (tag.isEmpty() || tag == "none" || tag == "hidden") // in fact no border 0064 return false; 0065 0066 QString _width = tag.section(' ', 0, 0); 0067 QString _style = tag.section(' ', 1, 1); 0068 QString _color = tag.section(' ', 2, 2); 0069 0070 *width = KoUnit::parseValue(_width, 1.0); 0071 0072 if (_style == "dashed") 0073 *style = 1; 0074 else if (_style == "dotted") 0075 *style = 2; 0076 else if (_style == "dot-dash") // not in xsl/fo, but in OASIS (in other places) 0077 *style = 3; 0078 else if (_style == "dot-dot-dash") // not in xsl/fo, but in OASIS (in other places) 0079 *style = 4; 0080 else if (_style == "double") 0081 *style = 5; 0082 else 0083 *style = 0; 0084 0085 if (_color.isEmpty()) 0086 *color = QColor(); 0087 else 0088 color->setNamedColor(_color); 0089 0090 return true; 0091 } 0092 0093 void OoUtils::importIndents(QDomElement& parentElement, const KoStyleStack& styleStack) 0094 { 0095 if (styleStack.hasProperty(ooNS::fo, "margin-left") || // 3.11.19 0096 styleStack.hasProperty(ooNS::fo, "margin-right")) 0097 // *text-indent must always be bound to either margin-left or margin-right 0098 { 0099 double marginLeft = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-left")); 0100 double marginRight = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-right")); 0101 double first = 0; 0102 if (styleStack.property(ooNS::style, "auto-text-indent") == "true") // style:auto-text-indent takes precedence 0103 // ### "indented by a value that is based on the current font size" 0104 // ### and "requires margin-left and margin-right 0105 // ### but how much is the indent? 0106 first = 10; 0107 else if (styleStack.hasProperty(ooNS::fo, "text-indent")) 0108 first = KoUnit::parseValue(styleStack.property(ooNS::fo, "text-indent")); 0109 0110 if (marginLeft != 0 || marginRight != 0 || first != 0) { 0111 QDomElement indent = parentElement.ownerDocument().createElement("INDENTS"); 0112 if (marginLeft != 0) 0113 indent.setAttribute("left", QString::number(marginLeft)); 0114 if (marginRight != 0) 0115 indent.setAttribute("right", QString::number(marginRight)); 0116 if (first != 0) 0117 indent.setAttribute("first", QString::number(first)); 0118 parentElement.appendChild(indent); 0119 } 0120 } 0121 } 0122 0123 void OoUtils::importLineSpacing(QDomElement& parentElement, const KoStyleStack& styleStack) 0124 { 0125 if (styleStack.hasProperty(ooNS::fo, "line-height")) { 0126 // Fixed line height 0127 QString value = styleStack.property(ooNS::fo, "line-height"); // 3.11.1 0128 if (value != "normal") { 0129 QDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING"); 0130 if (value == "100%") 0131 lineSpacing.setAttribute("type", "single"); 0132 else if (value == "150%") 0133 lineSpacing.setAttribute("type", "oneandhalf"); 0134 else if (value == "200%") 0135 lineSpacing.setAttribute("type", "double"); 0136 else if (value.contains('%')) { 0137 double percent = value.toDouble(); 0138 lineSpacing.setAttribute("type", "multiple"); 0139 lineSpacing.setAttribute("spacingvalue", QString::number(percent / 100)); 0140 } else { // fixed value (use KoUnit::parseValue to get it in pt) 0141 kWarning(30519) << "Unhandled value for fo:line-height: " << value; 0142 } 0143 parentElement.appendChild(lineSpacing); 0144 } 0145 } 0146 // Line-height-at-least is mutually exclusive with line-height 0147 else if (styleStack.hasProperty(ooNS::style, "line-height-at-least")) { // 3.11.2 0148 QString value = styleStack.property(ooNS::style, "line-height-at-least"); 0149 // kotext has "at least" but that's for the linespacing, not for the entire line height! 0150 // Strange. kotext also has "at least" for the whole line height.... 0151 // Did we make the wrong choice in kotext? 0152 //kWarning(30519) << "Unimplemented support for style:line-height-at-least: " << value; 0153 // Well let's see if this makes a big difference. 0154 QDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING"); 0155 lineSpacing.setAttribute("type", "atleast"); 0156 lineSpacing.setAttribute("spacingvalue", QString::number(KoUnit::parseValue(value))); 0157 parentElement.appendChild(lineSpacing); 0158 } 0159 // Line-spacing is mutually exclusive with line-height and line-height-at-least 0160 else if (styleStack.hasProperty(ooNS::style, "line-spacing")) { // 3.11.3 0161 double value = KoUnit::parseValue(styleStack.property(ooNS::style, "line-spacing")); 0162 if (value != 0.0) { 0163 QDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING"); 0164 lineSpacing.setAttribute("type", "custom"); 0165 lineSpacing.setAttribute("spacingvalue", QString::number(value)); 0166 parentElement.appendChild(lineSpacing); 0167 } 0168 } 0169 0170 } 0171 0172 void OoUtils::importTopBottomMargin(QDomElement& parentElement, const KoStyleStack& styleStack) 0173 { 0174 if (styleStack.hasProperty(ooNS::fo, "margin-top") || // 3.11.22 0175 styleStack.hasProperty(ooNS::fo, "margin-bottom")) { 0176 double mtop = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-top")); 0177 double mbottom = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-bottom")); 0178 if (mtop != 0 || mbottom != 0) { 0179 QDomElement offset = parentElement.ownerDocument().createElement("OFFSETS"); 0180 if (mtop != 0) 0181 offset.setAttribute("before", QString::number(mtop)); 0182 if (mbottom != 0) 0183 offset.setAttribute("after", QString::number(mbottom)); 0184 parentElement.appendChild(offset); 0185 } 0186 } 0187 } 0188 0189 void OoUtils::importTabulators(QDomElement& parentElement, const KoStyleStack& styleStack) 0190 { 0191 if (!styleStack.hasChildNode(ooNS::style, "tab-stops")) // 3.11.10 0192 return; 0193 KoXmlElement tabStops = styleStack.childNode(ooNS::style, "tab-stops"); 0194 //kDebug(30519) << tabStops.childNodes().count() <<" tab stops in layout."; 0195 for (KoXmlNode it = tabStops.firstChild(); !it.isNull(); it = it.nextSibling()) { 0196 KoXmlElement tabStop = it.toElement(); 0197 Q_ASSERT(tabStop.prefix() == "style"); 0198 Q_ASSERT(tabStop.tagName() == "tab-stop"); 0199 QString type = tabStop.attributeNS(ooNS::style, "type", QString()); // left, right, center or char 0200 0201 QDomElement elem = parentElement.ownerDocument().createElement("TABULATOR"); 0202 int calligraType = 0; 0203 if (type == "left") 0204 calligraType = 0; 0205 else if (type == "center") 0206 calligraType = 1; 0207 else if (type == "right") 0208 calligraType = 2; 0209 else if (type == "char") { 0210 QString delimiterChar = tabStop.attributeNS(ooNS::style, "char", QString()); // single character 0211 elem.setAttribute("alignchar", delimiterChar); 0212 calligraType = 3; // "alignment on decimal point" 0213 } 0214 0215 elem.setAttribute("type", calligraType); 0216 0217 double pos = KoUnit::parseValue(tabStop.attributeNS(ooNS::style, "position", QString())); 0218 elem.setAttribute("ptpos", QString::number(pos)); 0219 0220 // TODO Convert leaderChar's unicode value to the Calligra enum 0221 // (blank/dots/line/dash/dash-dot/dash-dot-dot, 0 to 5) 0222 QString leaderChar = tabStop.attributeNS(ooNS::style, "leader-char", QString()); // single character 0223 if (!leaderChar.isEmpty()) { 0224 int filling = 0; 0225 QChar ch = leaderChar[0]; 0226 switch (ch.toLatin1()) { 0227 case '.': 0228 filling = 1; break; 0229 case '-': 0230 case '_': // TODO in Words: differentiate --- and ___ 0231 filling = 2; break; 0232 default: 0233 // Words doesn't have support for "any char" as filling. 0234 // Instead it has dash-dot and dash-dot-dot - but who uses that in a tabstop? 0235 break; 0236 } 0237 elem.setAttribute("filling", filling); 0238 } 0239 parentElement.appendChild(elem); 0240 } 0241 0242 } 0243 0244 void OoUtils::importBorders(QDomElement& parentElement, const KoStyleStack& styleStack) 0245 { 0246 if (styleStack.hasProperty(ooNS::fo, "border", "left")) { 0247 double width; 0248 int style; 0249 QColor color; 0250 if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "left"), &width, &style, &color)) { 0251 QDomElement lbElem = parentElement.ownerDocument().createElement("LEFTBORDER"); 0252 lbElem.setAttribute("width", QString::number(width)); 0253 lbElem.setAttribute("style", QString::number(style)); 0254 if (color.isValid()) { 0255 lbElem.setAttribute("red", color.red()); 0256 lbElem.setAttribute("green", color.green()); 0257 lbElem.setAttribute("blue", color.blue()); 0258 } 0259 parentElement.appendChild(lbElem); 0260 } 0261 } 0262 0263 if (styleStack.hasProperty(ooNS::fo, "border", "right")) { 0264 double width; 0265 int style; 0266 QColor color; 0267 if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "right"), &width, &style, &color)) { 0268 QDomElement lbElem = parentElement.ownerDocument().createElement("RIGHTBORDER"); 0269 lbElem.setAttribute("width", QString::number(width)); 0270 lbElem.setAttribute("style", QString::number(style)); 0271 if (color.isValid()) { 0272 lbElem.setAttribute("red", color.red()); 0273 lbElem.setAttribute("green", color.green()); 0274 lbElem.setAttribute("blue", color.blue()); 0275 } 0276 parentElement.appendChild(lbElem); 0277 } 0278 } 0279 0280 if (styleStack.hasProperty(ooNS::fo, "border", "top")) { 0281 double width; 0282 int style; 0283 QColor color; 0284 if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "top"), &width, &style, &color)) { 0285 QDomElement lbElem = parentElement.ownerDocument().createElement("TOPBORDER"); 0286 lbElem.setAttribute("width", QString::number(width)); 0287 lbElem.setAttribute("style", QString::number(style)); 0288 if (color.isValid()) { 0289 lbElem.setAttribute("red", color.red()); 0290 lbElem.setAttribute("green", color.green()); 0291 lbElem.setAttribute("blue", color.blue()); 0292 } 0293 parentElement.appendChild(lbElem); 0294 } 0295 } 0296 0297 if (styleStack.hasProperty(ooNS::fo, "border", "bottom")) { 0298 double width; 0299 int style; 0300 QColor color; 0301 if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "bottom"), &width, &style, &color)) { 0302 QDomElement lbElem = parentElement.ownerDocument().createElement("BOTTOMBORDER"); 0303 lbElem.setAttribute("width", QString::number(width)); 0304 lbElem.setAttribute("style", QString::number(style)); 0305 if (color.isValid()) { 0306 lbElem.setAttribute("red", color.red()); 0307 lbElem.setAttribute("green", color.green()); 0308 lbElem.setAttribute("blue", color.blue()); 0309 } 0310 parentElement.appendChild(lbElem); 0311 } 0312 } 0313 } 0314 0315 void OoUtils::importUnderline(const QString& in, QString& underline, QString& styleline) 0316 { 0317 underline = "single"; 0318 if (in == "none") 0319 underline = "0"; 0320 else if (in == "single") 0321 styleline = "solid"; 0322 else if (in == "double") { 0323 underline = in; 0324 styleline = "solid"; 0325 } else if (in == "dotted" || in == "bold-dotted") // bold-dotted not in libkotext 0326 styleline = "dot"; 0327 else if (in == "dash" 0328 // those are not in libkotext: 0329 || in == "long-dash" 0330 || in == "bold-dash" 0331 || in == "bold-long-dash" 0332 ) 0333 styleline = "dash"; 0334 else if (in == "dot-dash" 0335 || in == "bold-dot-dash") // not in libkotext 0336 styleline = "dashdot"; // tricky ;) 0337 else if (in == "dot-dot-dash" 0338 || in == "bold-dot-dot-dash") // not in libkotext 0339 styleline = "dashdotdot"; // this is getting fun... 0340 else if (in == "wave" 0341 || in == "bold-wave" // not in libkotext 0342 || in == "double-wave" // not in libkotext 0343 || in == "small-wave") { // not in libkotext 0344 underline = in; 0345 styleline = "solid"; 0346 } else if (in == "bold") { 0347 underline = "single-bold"; 0348 styleline = "solid"; 0349 } else 0350 kWarning(30519) << " unsupported text-underline value: " << in; 0351 } 0352 0353 void OoUtils::importTextPosition(const QString& text_position, QString& value, QString& relativetextsize) 0354 { 0355 //OO: <vertical position (% or sub or super)> [<size as %>] 0356 //Examples: "super" or "super 58%" or "82% 58%" (where 82% is the vertical position) 0357 // TODO in words: vertical positions other than sub/super 0358 QStringList lst = text_position.split(' '); 0359 if (!lst.isEmpty()) { 0360 QString textPos = lst.front().trimmed(); 0361 QString textSize; 0362 lst.pop_front(); 0363 if (!lst.isEmpty()) 0364 textSize = lst.front().trimmed(); 0365 if (!lst.isEmpty()) 0366 kWarning(30519) << "Strange text position: " << text_position; 0367 bool super = textPos == "super"; 0368 bool sub = textPos == "sub"; 0369 if (textPos.endsWith(QLatin1Char('%'))) { 0370 textPos.chop(1); 0371 // This is where we interpret the text position into kotext's simpler 0372 // "super" or "sub". 0373 double val = textPos.toDouble(); 0374 if (val > 0) 0375 super = true; 0376 else if (val < 0) 0377 sub = true; 0378 } 0379 if (super) 0380 value = "2"; 0381 else if (sub) 0382 value = "1"; 0383 else 0384 value = "0"; 0385 if (!textSize.isEmpty() && textSize.endsWith(QLatin1Char('%'))) { 0386 textSize.chop(1); 0387 double textSizeValue = textSize.toDouble() / 100; // e.g. 0.58 0388 relativetextsize = QString::number(textSizeValue); 0389 } 0390 } else 0391 value = "0"; 0392 } 0393 0394 void OoUtils::createDocumentInfo(KoXmlDocument &_meta, QDomDocument & docinfo) 0395 { 0396 KoXmlNode meta = KoXml::namedItemNS(_meta, ooNS::office, "document-meta"); 0397 KoXmlNode office = KoXml::namedItemNS(meta, ooNS::office, "meta"); 0398 0399 if (office.isNull()) 0400 return; 0401 QDomElement elementDocInfo = docinfo.documentElement(); 0402 0403 KoXmlElement e = KoXml::namedItemNS(office, ooNS::dc, "creator"); 0404 if (!e.isNull() && !e.text().isEmpty()) { 0405 QDomElement author = docinfo.createElement("author"); 0406 QDomElement t = docinfo.createElement("full-name"); 0407 author.appendChild(t); 0408 t.appendChild(docinfo.createTextNode(e.text())); 0409 elementDocInfo.appendChild(author); 0410 } 0411 0412 e = KoXml::namedItemNS(office, ooNS::dc, "title"); 0413 if (!e.isNull() && !e.text().isEmpty()) { 0414 QDomElement about = docinfo.createElement("about"); 0415 QDomElement title = docinfo.createElement("title"); 0416 about.appendChild(title); 0417 title.appendChild(docinfo.createTextNode(e.text())); 0418 elementDocInfo.appendChild(about); 0419 } 0420 0421 e = KoXml::namedItemNS(office, ooNS::dc, "description"); 0422 if (!e.isNull() && !e.text().isEmpty()) { 0423 QDomElement about = elementDocInfo.namedItem("about").toElement(); 0424 if (about.isNull()) { 0425 about = docinfo.createElement("about"); 0426 elementDocInfo.appendChild(about); 0427 } 0428 QDomElement title = docinfo.createElement("abstract"); 0429 about.appendChild(title); 0430 title.appendChild(docinfo.createTextNode(e.text())); 0431 } 0432 e = KoXml::namedItemNS(office, ooNS::dc, "subject"); 0433 if (!e.isNull() && !e.text().isEmpty()) { 0434 QDomElement about = elementDocInfo.namedItem("about").toElement(); 0435 if (about.isNull()) { 0436 about = docinfo.createElement("about"); 0437 elementDocInfo.appendChild(about); 0438 } 0439 QDomElement subject = docinfo.createElement("subject"); 0440 about.appendChild(subject); 0441 subject.appendChild(docinfo.createTextNode(e.text())); 0442 } 0443 e = KoXml::namedItemNS(office, ooNS::meta, "keywords"); 0444 if (!e.isNull()) { 0445 QDomElement about = elementDocInfo.namedItem("about").toElement(); 0446 if (about.isNull()) { 0447 about = docinfo.createElement("about"); 0448 elementDocInfo.appendChild(about); 0449 } 0450 KoXmlElement tmp = KoXml::namedItemNS(e, ooNS::meta, "keyword"); 0451 if (!tmp.isNull() && !tmp.text().isEmpty()) { 0452 QDomElement keyword = docinfo.createElement("keyword"); 0453 about.appendChild(keyword); 0454 keyword.appendChild(docinfo.createTextNode(tmp.text())); 0455 } 0456 } 0457 } 0458 0459 KoFilter::ConversionStatus OoUtils::loadAndParse(const QString& fileName, KoXmlDocument& doc, KoStore* store) 0460 { 0461 kDebug(30518) << "loadAndParse: Trying to open" << fileName; 0462 0463 if (!store->open(fileName)) { 0464 kWarning(30519) << "Entry " << fileName << " not found!"; 0465 return KoFilter::FileNotFound; 0466 } 0467 KoFilter::ConversionStatus convertStatus = loadAndParse(store->device(), doc, fileName); 0468 store->close(); 0469 return convertStatus; 0470 0471 } 0472 0473 KoFilter::ConversionStatus OoUtils::loadAndParse(QIODevice* io, KoXmlDocument& doc, const QString & fileName) 0474 { 0475 // Error variables for QDomDocument::setContent 0476 QString errorMsg; 0477 int errorLine, errorColumn; 0478 if (!doc.setContent(io, &errorMsg, &errorLine, &errorColumn)) { 0479 kError(30519) << "Parsing error in " << fileName << "! Aborting!" << endl 0480 << " In line: " << errorLine << ", column: " << errorColumn << endl 0481 << " Error message: " << errorMsg << endl; 0482 return KoFilter::ParsingError; 0483 } 0484 0485 kDebug(30519) << "File" << fileName << " loaded and parsed!"; 0486 0487 return KoFilter::OK; 0488 } 0489 0490 KoFilter::ConversionStatus OoUtils::loadAndParse(const QString& filename, KoXmlDocument& doc, KZip* zip) 0491 { 0492 kDebug(30519) << "Trying to open" << filename; 0493 0494 if (!zip) { 0495 kError(30519) << "No ZIP file!" << endl; 0496 return KoFilter::CreationError; // Should not happen 0497 } 0498 0499 const KArchiveEntry* entry = zip->directory()->entry(filename); 0500 if (!entry) { 0501 kWarning(30519) << "Entry " << filename << " not found!"; 0502 return KoFilter::FileNotFound; 0503 } 0504 if (entry->isDirectory()) { 0505 kWarning(30519) << "Entry " << filename << " is a directory!"; 0506 return KoFilter::WrongFormat; 0507 } 0508 const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry); 0509 kDebug(30519) << "Entry" << filename << " has size" << f->size(); 0510 QIODevice* io = f->createDevice(); 0511 KoFilter::ConversionStatus convertStatus = loadAndParse(io, doc, filename); 0512 delete io; 0513 return convertStatus; 0514 } 0515 0516 KoFilter::ConversionStatus OoUtils::loadThumbnail(QImage& thumbnail, KZip* zip) 0517 { 0518 const QString filename("Thumbnails/thumbnail.png"); 0519 kDebug(30519) << "Trying to open thumbnail" << filename; 0520 0521 if (!zip) { 0522 kError(30519) << "No ZIP file!" << endl; 0523 return KoFilter::CreationError; // Should not happen 0524 } 0525 0526 const KArchiveEntry* entry = zip->directory()->entry(filename); 0527 if (!entry) { 0528 kWarning(30519) << "Entry " << filename << " not found!"; 0529 return KoFilter::FileNotFound; 0530 } 0531 if (entry->isDirectory()) { 0532 kWarning(30519) << "Entry " << filename << " is a directory!"; 0533 return KoFilter::WrongFormat; 0534 } 0535 const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry); 0536 QIODevice* io = f->createDevice(); 0537 kDebug(30519) << "Entry" << filename << " has size" << f->size(); 0538 0539 if (! io->open(QIODevice::ReadOnly)) { 0540 kWarning(30519) << "Thumbnail could not be opened!"; 0541 delete io; 0542 return KoFilter::StupidError; 0543 } 0544 0545 if (! thumbnail.load(io, "PNG")) { 0546 kWarning(30519) << "Thumbnail could not be read!"; 0547 delete io; 0548 return KoFilter::StupidError; 0549 } 0550 0551 io->close(); 0552 0553 if (thumbnail.isNull()) { 0554 kWarning(30519) << "Read thumbnail is null!"; 0555 delete io; 0556 return KoFilter::StupidError; 0557 } 0558 0559 delete io; 0560 0561 kDebug(30519) << "File" << filename << " loaded!"; 0562 0563 return KoFilter::OK; 0564 }