ooutils.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
3 Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
4 Copyright (c) 2003 David Faure <faure@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include "ooutils.h"
23#include <KoDocument.h>
24#include <KoStyleStack.h>
25#include <tqdom.h>
26#include <tqcolor.h>
27#include <tqimage.h>
28#include <KoUnit.h>
29#include <tqregexp.h>
30#include <kdebug.h>
31#include <kzip.h>
32#include <KoDom.h>
33#include <tqxml.h>
34
35const char* const ooNS::office="http://openoffice.org/2000/office";
36const char* const ooNS::style="http://openoffice.org/2000/style";
37const char* const ooNS::text="http://openoffice.org/2000/text";
38const char* const ooNS::table="http://openoffice.org/2000/table";
39const char* const ooNS::draw="http://openoffice.org/2000/drawing";
40const char* const ooNS::presentation="http://openoffice.org/2000/presentation";
41const char* const ooNS::fo="http://www.w3.org/1999/XSL/Format";
42const char* const ooNS::xlink="http://www.w3.org/1999/xlink";
43const char* const ooNS::number="http://openoffice.org/2000/datastyle";
44const char* const ooNS::svg="http://www.w3.org/2000/svg";
45const char* const ooNS::dc="http://purl.org/dc/elements/1.1/";
46const char* const ooNS::meta="http://openoffice.org/2000/meta";
47const char* const ooNS::config="http://openoffice.org/2001/config";
48
49TQString OoUtils::expandWhitespace(const TQDomElement& tag)
50{
51 //tags like <text:s text:c="4">
52
53 int howmany=1;
54 if (tag.hasAttributeNS( ooNS::text, "c"))
55 howmany = tag.attributeNS( ooNS::text, "c", TQString()).toInt();
56
57 TQString result;
58 return result.fill(32, howmany);
59}
60
61bool OoUtils::parseBorder(const TQString & tag, double * width, int * style, TQColor * color)
62{
63 //string like "0.088cm solid #800000"
64
65 if (tag.isEmpty() || tag=="none" || tag=="hidden") // in fact no border
66 return false;
67
68 TQString _width = tag.section(' ', 0, 0);
69 TQString _style = tag.section(' ', 1, 1);
70 TQString _color = tag.section(' ', 2, 2);
71
72 *width = KoUnit::parseValue(_width, 1.0);
73
74 if ( _style == "dashed" )
75 *style = 1;
76 else if ( _style == "dotted" )
77 *style = 2;
78 else if ( _style == "dot-dash" ) // not in xsl/fo, but in OASIS (in other places)
79 *style = 3;
80 else if ( _style == "dot-dot-dash" ) // not in xsl/fo, but in OASIS (in other places)
81 *style = 4;
82 else if ( _style == "double" )
83 *style = 5;
84 else
85 *style = 0;
86
87 if (_color.isEmpty())
88 *color = TQColor();
89 else
90 color->setNamedColor(_color);
91
92 return true;
93}
94
95void OoUtils::importIndents( TQDomElement& parentElement, const KoStyleStack& styleStack )
96{
97 if ( styleStack.hasAttributeNS( ooNS::fo, "margin-left" ) || // 3.11.19
98 styleStack.hasAttributeNS( ooNS::fo, "margin-right" ) )
99 // *text-indent must always be bound to either margin-left or margin-right
100 {
101 double marginLeft = KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-left" ) );
102 double marginRight = KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-right" ) );
103 double first = 0;
104 if (styleStack.attributeNS( ooNS::style, "auto-text-indent") == "true") // style:auto-text-indent takes precedence
105 // ### "indented by a value that is based on the current font size"
106 // ### and "requires margin-left and margin-right
107 // ### but how much is the indent?
108 first = 10;
109 else if (styleStack.hasAttributeNS( ooNS::fo, "text-indent"))
110 first = KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "text-indent"));
111
112 if ( marginLeft != 0 || marginRight != 0 || first != 0 )
113 {
114 TQDomElement indent = parentElement.ownerDocument().createElement( "INDENTS" );
115 if( marginLeft != 0 )
116 indent.setAttribute( "left", marginLeft );
117 if( marginRight != 0 )
118 indent.setAttribute( "right", marginRight );
119 if( first != 0 )
120 indent.setAttribute( "first", first );
121 parentElement.appendChild( indent );
122 }
123 }
124}
125
126void OoUtils::importLineSpacing( TQDomElement& parentElement, const KoStyleStack& styleStack )
127{
128 if( styleStack.hasAttributeNS( ooNS::fo, "line-height") )
129 {
130 // Fixed line height
131 TQString value = styleStack.attributeNS( ooNS::fo, "line-height" ); // 3.11.1
132 if ( value != "normal" )
133 {
134 TQDomElement lineSpacing = parentElement.ownerDocument().createElement( "LINESPACING" );
135
136 if ( value.endsWith("%" ) )
137 {
138 double percent = value.left(value.length()-1).toDouble();
139 if( percent == 100 )
140 lineSpacing.setAttribute("type","single");
141 else if( percent == 150 )
142 lineSpacing.setAttribute("type","oneandhalf");
143 else if( percent == 200 )
144 lineSpacing.setAttribute("type","double");
145 else
146 {
147 lineSpacing.setAttribute("type", "multiple");
148 lineSpacing.setAttribute("spacingvalue", percent/100);
149 }
150 }
151 else // fixed value (TODO use KoUnit::parseValue to get it in pt)
152 {
153 kdWarning(30519) << "Unhandled value for fo:line-height: " << value << endl;
154 lineSpacing.setAttribute("type","single"); // fallback
155 }
156 parentElement.appendChild( lineSpacing );
157 }
158 }
159 // Line-height-at-least is mutually exclusive with line-height
160 else if ( styleStack.hasAttributeNS( ooNS::style, "line-height-at-least") ) // 3.11.2
161 {
162 TQString value = styleStack.attributeNS( ooNS::style, "line-height-at-least" );
163 // kotext has "at least" but that's for the linespacing, not for the entire line height!
164 // Strange. kotext also has "at least" for the whole line height....
165 // Did we make the wrong choice in kotext?
166 //kdWarning(30519) << "Unimplemented support for style:line-height-at-least: " << value << endl;
167 // Well let's see if this makes a big difference.
168 TQDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING");
169 lineSpacing.setAttribute("type", "atleast");
170 lineSpacing.setAttribute("spacingvalue", KoUnit::parseValue(value));
171 parentElement.appendChild(lineSpacing);
172 }
173 // Line-spacing is mutually exclusive with line-height and line-height-at-least
174 else if ( styleStack.hasAttributeNS( ooNS::style, "line-spacing") ) // 3.11.3
175 {
176 double value = KoUnit::parseValue( styleStack.attributeNS( ooNS::style, "line-spacing" ) );
177 if ( value != 0.0 )
178 {
179 TQDomElement lineSpacing = parentElement.ownerDocument().createElement( "LINESPACING" );
180 lineSpacing.setAttribute( "type", "custom" );
181 lineSpacing.setAttribute( "spacingvalue", value );
182 parentElement.appendChild( lineSpacing );
183 }
184 }
185
186}
187
188void OoUtils::importTopBottomMargin( TQDomElement& parentElement, const KoStyleStack& styleStack )
189{
190 if( styleStack.hasAttributeNS( ooNS::fo, "margin-top") || // 3.11.22
191 styleStack.hasAttributeNS( ooNS::fo, "margin-bottom"))
192 {
193 double mtop = KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-top" ) );
194 double mbottom = KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-bottom" ) );
195 if( mtop != 0 || mbottom != 0 )
196 {
197 TQDomElement offset = parentElement.ownerDocument().createElement( "OFFSETS" );
198 if( mtop != 0 )
199 offset.setAttribute( "before", mtop );
200 if( mbottom != 0 )
201 offset.setAttribute( "after", mbottom );
202 parentElement.appendChild( offset );
203 }
204 }
205}
206
207void OoUtils::importTabulators( TQDomElement& parentElement, const KoStyleStack& styleStack )
208{
209 if ( !styleStack.hasChildNodeNS( ooNS::style, "tab-stops" ) ) // 3.11.10
210 return;
211 TQDomElement tabStops = styleStack.childNodeNS( ooNS::style, "tab-stops" );
212 //kdDebug(30519) << k_funcinfo << tabStops.childNodes().count() << " tab stops in layout." << endl;
213 for ( TQDomNode it = tabStops.firstChild(); !it.isNull(); it = it.nextSibling() )
214 {
215 TQDomElement tabStop = it.toElement();
216 Q_ASSERT( tabStop.tagName() == "style:tab-stop" );
217 TQString type = tabStop.attributeNS( ooNS::style, "type", TQString() ); // left, right, center or char
218
219 TQDomElement elem = parentElement.ownerDocument().createElement( "TABULATOR" );
220 int kOfficeType = 0;
221 if ( type == "left" )
222 kOfficeType = 0;
223 else if ( type == "center" )
224 kOfficeType = 1;
225 else if ( type == "right" )
226 kOfficeType = 2;
227 else if ( type == "char" ) {
228 TQString delimiterChar = tabStop.attributeNS( ooNS::style, "char", TQString() ); // single character
229 elem.setAttribute( "alignchar", delimiterChar );
230 kOfficeType = 3; // "alignment on decimal point"
231 }
232
233 elem.setAttribute( "type", kOfficeType );
234
235 double pos = KoUnit::parseValue( tabStop.attributeNS( ooNS::style, "position", TQString() ) );
236 elem.setAttribute( "ptpos", pos );
237
238 // TODO Convert leaderChar's unicode value to the KOffice enum
239 // (blank/dots/line/dash/dash-dot/dash-dot-dot, 0 to 5)
240 TQString leaderChar = tabStop.attributeNS( ooNS::style, "leader-char", TQString() ); // single character
241 if ( !leaderChar.isEmpty() )
242 {
243 int filling = 0;
244 TQChar ch = leaderChar[0];
245 switch (ch.latin1()) {
246 case '.':
247 filling = 1; break;
248 case '-':
249 case '_': // TODO in KWord: differentiate --- and ___
250 filling = 2; break;
251 default:
252 // KWord doesn't have support for "any char" as filling.
253 // Instead it has dash-dot and dash-dot-dot - but who uses that in a tabstop?
254 break;
255 }
256 elem.setAttribute( "filling", filling );
257 }
258 parentElement.appendChild( elem );
259 }
260
261}
262
263void OoUtils::importBorders( TQDomElement& parentElement, const KoStyleStack& styleStack )
264{
265 if (styleStack.hasAttributeNS( ooNS::fo, "border","left"))
266 {
267 double width;
268 int style;
269 TQColor color;
270 if (OoUtils::parseBorder(styleStack.attributeNS( ooNS::fo, "border", "left"), &width, &style, &color))
271 {
272 TQDomElement lbElem = parentElement.ownerDocument().createElement("LEFTBORDER");
273 lbElem.setAttribute("width", width);
274 lbElem.setAttribute("style", style);
275 if (color.isValid()) {
276 lbElem.setAttribute("red", color.red());
277 lbElem.setAttribute("green", color.green());
278 lbElem.setAttribute("blue", color.blue());
279 }
280 parentElement.appendChild(lbElem);
281 }
282 }
283
284 if (styleStack.hasAttributeNS( ooNS::fo, "border", "right"))
285 {
286 double width;
287 int style;
288 TQColor color;
289 if (OoUtils::parseBorder(styleStack.attributeNS( ooNS::fo, "border", "right"), &width, &style, &color))
290 {
291 TQDomElement lbElem = parentElement.ownerDocument().createElement("RIGHTBORDER");
292 lbElem.setAttribute("width", width);
293 lbElem.setAttribute("style", style);
294 if (color.isValid()) {
295 lbElem.setAttribute("red", color.red());
296 lbElem.setAttribute("green", color.green());
297 lbElem.setAttribute("blue", color.blue());
298 }
299 parentElement.appendChild(lbElem);
300 }
301 }
302
303 if (styleStack.hasAttributeNS( ooNS::fo, "border", "top"))
304 {
305 double width;
306 int style;
307 TQColor color;
308 if (OoUtils::parseBorder(styleStack.attributeNS( ooNS::fo, "border", "top"), &width, &style, &color))
309 {
310 TQDomElement lbElem = parentElement.ownerDocument().createElement("TOPBORDER");
311 lbElem.setAttribute("width", width);
312 lbElem.setAttribute("style", style);
313 if (color.isValid()) {
314 lbElem.setAttribute("red", color.red());
315 lbElem.setAttribute("green", color.green());
316 lbElem.setAttribute("blue", color.blue());
317 }
318 parentElement.appendChild(lbElem);
319 }
320 }
321
322 if (styleStack.hasAttributeNS( ooNS::fo, "border", "bottom"))
323 {
324 double width;
325 int style;
326 TQColor color;
327 if (OoUtils::parseBorder(styleStack.attributeNS( ooNS::fo, "border", "bottom"), &width, &style, &color))
328 {
329 TQDomElement lbElem = parentElement.ownerDocument().createElement("BOTTOMBORDER");
330 lbElem.setAttribute("width", width);
331 lbElem.setAttribute("style", style);
332 if (color.isValid()) {
333 lbElem.setAttribute("red", color.red());
334 lbElem.setAttribute("green", color.green());
335 lbElem.setAttribute("blue", color.blue());
336 }
337 parentElement.appendChild(lbElem);
338 }
339 }
340}
341
342void OoUtils::importUnderline( const TQString& in, TQString& underline, TQString& styleline )
343{
344 underline = "single";
345 if ( in == "none" )
346 underline = "0";
347 else if ( in == "single" )
348 styleline = "solid";
349 else if ( in == "double" )
350 {
351 underline = in;
352 styleline = "solid";
353 }
354 else if ( in == "dotted" || in == "bold-dotted" ) // bold-dotted not in libkotext
355 styleline = "dot";
356 else if ( in == "dash"
357 // those are not in libkotext:
358 || in == "long-dash"
359 || in == "bold-dash"
360 || in == "bold-long-dash"
361 )
362 styleline = "dash";
363 else if ( in == "dot-dash"
364 || in == "bold-dot-dash") // not in libkotext
365 styleline = "dashdot"; // tricky ;)
366 else if ( in == "dot-dot-dash"
367 || in == "bold-dot-dot-dash") // not in libkotext
368 styleline = "dashdotdot"; // this is getting fun...
369 else if ( in == "wave"
370 || in == "bold-wave" // not in libkotext
371 || in == "double-wave" // not in libkotext
372 || in == "small-wave" ) // not in libkotext
373 {
374 underline = in;
375 styleline = "solid";
376 }
377 else if( in == "bold" )
378 {
379 underline = "single-bold";
380 styleline = "solid";
381 }
382 else
383 kdWarning(30519) << k_funcinfo << " unsupported text-underline value: " << in << endl;
384}
385
386void OoUtils::importTextPosition( const TQString& text_position, TQString& value, TQString& relativetextsize )
387{
388 //OO: <vertical position (% or sub or super)> [<size as %>]
389 //Examples: "super" or "super 58%" or "82% 58%" (where 82% is the vertical position)
390 // TODO in kword: vertical positions other than sub/super
391 TQStringList lst = TQStringList::split( ' ', text_position );
392 if ( !lst.isEmpty() )
393 {
394 TQString textPos = lst.front().stripWhiteSpace();
395 TQString textSize;
396 lst.pop_front();
397 if ( !lst.isEmpty() )
398 textSize = lst.front().stripWhiteSpace();
399 if ( !lst.isEmpty() )
400 kdWarning(30519) << "Strange text position: " << text_position << endl;
401 bool super = textPos == "super";
402 bool sub = textPos == "sub";
403 if ( textPos.endsWith("%") )
404 {
405 textPos.truncate( textPos.length() - 1 );
406 // This is where we interpret the text position into kotext's simpler
407 // "super" or "sub".
408 double val = textPos.toDouble();
409 if ( val > 0 )
410 super = true;
411 else if ( val < 0 )
412 sub = true;
413 }
414 if ( super )
415 value = "2";
416 else if ( sub )
417 value = "1";
418 else
419 value = "0";
420 if ( !textSize.isEmpty() && textSize.endsWith("%") )
421 {
422 textSize.truncate( textSize.length() - 1 );
423 double textSizeValue = textSize.toDouble() / 100; // e.g. 0.58
424 relativetextsize = TQString::number( textSizeValue );
425 }
426 }
427 else
428 value = "0";
429}
430
431void OoUtils::createDocumentInfo(TQDomDocument &_meta, TQDomDocument & docinfo)
432{
433 TQDomNode meta = KoDom::namedItemNS( _meta, ooNS::office, "document-meta" );
434 TQDomNode office = KoDom::namedItemNS( meta, ooNS::office, "meta" );
435
436 if ( office.isNull() )
437 return;
438 TQDomElement elementDocInfo = docinfo.documentElement();
439
440 TQDomElement e = KoDom::namedItemNS( office, ooNS::dc, "creator" );
441 if ( !e.isNull() && !e.text().isEmpty() )
442 {
443 TQDomElement author = docinfo.createElement( "author" );
444 TQDomElement t = docinfo.createElement( "full-name" );
445 author.appendChild( t );
446 t.appendChild( docinfo.createTextNode( e.text() ) );
447 elementDocInfo.appendChild( author);
448 }
449
450 e = KoDom::namedItemNS( office, ooNS::dc, "title" );
451 if ( !e.isNull() && !e.text().isEmpty() )
452 {
453 TQDomElement about = docinfo.createElement( "about" );
454 TQDomElement title = docinfo.createElement( "title" );
455 about.appendChild( title );
456 title.appendChild( docinfo.createTextNode( e.text() ) );
457 elementDocInfo.appendChild( about );
458 }
459
460 e = KoDom::namedItemNS( office, ooNS::dc, "description" );
461 if ( !e.isNull() && !e.text().isEmpty() )
462 {
463 TQDomElement about = elementDocInfo.namedItem( "about" ).toElement();
464 if ( about.isNull() ) {
465 about = docinfo.createElement( "about" );
466 elementDocInfo.appendChild( about );
467 }
468 TQDomElement title = docinfo.createElement( "abstract" );
469 about.appendChild( title );
470 title.appendChild( docinfo.createTextNode( e.text() ) );
471 }
472 e = KoDom::namedItemNS( office, ooNS::dc, "subject" );
473 if ( !e.isNull() && !e.text().isEmpty() )
474 {
475 TQDomElement about = elementDocInfo.namedItem( "about" ).toElement();
476 if ( about.isNull() ) {
477 about = docinfo.createElement( "about" );
478 elementDocInfo.appendChild( about );
479 }
480 TQDomElement subject = docinfo.createElement( "subject" );
481 about.appendChild( subject );
482 subject.appendChild( docinfo.createTextNode( e.text() ) );
483 }
484 e = KoDom::namedItemNS( office, ooNS::meta, "keywords" );
485 if ( !e.isNull() )
486 {
487 TQDomElement about = elementDocInfo.namedItem( "about" ).toElement();
488 if ( about.isNull() ) {
489 about = docinfo.createElement( "about" );
490 elementDocInfo.appendChild( about );
491 }
492 TQDomElement tmp = KoDom::namedItemNS( e, ooNS::meta, "keyword" );
493 if ( !tmp.isNull() && !tmp.text().isEmpty() )
494 {
495 TQDomElement keyword = docinfo.createElement( "keyword" );
496 about.appendChild( keyword );
497 keyword.appendChild( docinfo.createTextNode( tmp.text() ) );
498 }
499 }
500}
501
502KoFilter::ConversionStatus OoUtils::loadAndParse(const TQString& fileName, TQDomDocument& doc, KoStore *m_store )
503{
504 kdDebug(30518) << "loadAndParse: Trying to open " << fileName << endl;
505
506 if (!m_store->open(fileName))
507 {
508 kdWarning(30519) << "Entry " << fileName << " not found!" << endl;
509 return KoFilter::FileNotFound;
510 }
511 KoFilter::ConversionStatus convertStatus = loadAndParse( m_store->device(),doc, fileName );
512 m_store->close();
513 return convertStatus;
514
515}
516
517KoFilter::ConversionStatus OoUtils::loadAndParse(TQIODevice* io, TQDomDocument& doc, const TQString & fileName)
518{
519 TQXmlInputSource source( io );
520 // Copied from TQDomDocumentPrivate::setContent, to change the whitespace thing
521 TQXmlSimpleReader reader;
522 KoDocument::setupXmlReader( reader, true /*namespaceProcessing*/ );
523
524 // Error variables for TQDomDocument::setContent
525 TQString errorMsg;
526 int errorLine, errorColumn;
527 if ( !doc.setContent( &source, &reader, &errorMsg, &errorLine, &errorColumn ) )
528 {
529 kdError(30519) << "Parsing error in " << fileName << "! Aborting!" << endl
530 << " In line: " << errorLine << ", column: " << errorColumn << endl
531 << " Error message: " << errorMsg << endl;
532 return KoFilter::ParsingError;
533 }
534
535 kdDebug(30519) << "File " << fileName << " loaded and parsed!" << endl;
536
537 return KoFilter::OK;
538
539}
540
541KoFilter::ConversionStatus OoUtils::loadAndParse(const TQString& filename, TQDomDocument& doc, KZip * m_zip)
542{
543 kdDebug(30519) << "Trying to open " << filename << endl;
544
545 if (!m_zip)
546 {
547 kdError(30519) << "No ZIP file!" << endl;
548 return KoFilter::CreationError; // Should not happen
549 }
550
551 const KArchiveEntry* entry = m_zip->directory()->entry( filename );
552 if (!entry)
553 {
554 kdWarning(30519) << "Entry " << filename << " not found!" << endl;
555 return KoFilter::FileNotFound;
556 }
557 if (entry->isDirectory())
558 {
559 kdWarning(30519) << "Entry " << filename << " is a directory!" << endl;
560 return KoFilter::WrongFormat;
561 }
562 const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry);
563 kdDebug(30519) << "Entry " << filename << " has size " << f->size() << endl;
564 TQIODevice* io = f->device();
565 KoFilter::ConversionStatus convertStatus = loadAndParse( io,doc, filename );
566 delete io;
567 return convertStatus;
568}
569
570KoFilter::ConversionStatus OoUtils::loadThumbnail( TQImage& thumbnail, KZip * m_zip )
571{
572 const TQString filename( "Thumbnails/thumbnail.png" );
573 kdDebug(30519) << "Trying to open thumbnail " << filename << endl;
574
575 if (!m_zip)
576 {
577 kdError(30519) << "No ZIP file!" << endl;
578 return KoFilter::CreationError; // Should not happen
579 }
580
581 const KArchiveEntry* entry = m_zip->directory()->entry( filename );
582 if (!entry)
583 {
584 kdWarning(30519) << "Entry " << filename << " not found!" << endl;
585 return KoFilter::FileNotFound;
586 }
587 if (entry->isDirectory())
588 {
589 kdWarning(30519) << "Entry " << filename << " is a directory!" << endl;
590 return KoFilter::WrongFormat;
591 }
592 const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry);
593 TQIODevice* io=f->device();
594 kdDebug(30519) << "Entry " << filename << " has size " << f->size() << endl;
595
596 if ( ! io->open( IO_ReadOnly ) )
597 {
598 kdWarning(30519) << "Thumbnail could not be opened!" <<endl;
599 delete io;
600 return KoFilter::StupidError;
601 }
602
603 TQImageIO imageIO( io, "PNG" );
604 if ( ! imageIO.read() )
605 {
606 kdWarning(30519) << "Thumbnail could not be read!" <<endl;
607 delete io;
608 return KoFilter::StupidError;
609 }
610
611 io->close();
612
613 thumbnail = imageIO.image();
614
615 if ( thumbnail.isNull() )
616 {
617 kdWarning(30519) << "Read thumbnail is null!" <<endl;
618 delete io;
619 return KoFilter::StupidError;
620 }
621
622 delete io;
623
624 kdDebug(30519) << "File " << filename << " loaded!" << endl;
625
626 return KoFilter::OK;
627}