filters

kword/msword/document.cpp
1/* This file is part of the KOffice project
2 Copyright (C) 2002 Werner Trobin <trobin@kde.org>
3 Copyright (C) 2002 David Faure <faure@kde.org>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "document.h"
21#include "conversion.h"
22#include "texthandler.h"
23#include "graphicshandler.h"
24#include "versionmagic.h"
25
26#include <KoRect.h>
27#include <KoUnit.h>
28#include <KoPageLayout.h>
29#include <kdebug.h>
30
31#include <wv2/styles.h>
32#include <wv2/ustring.h>
33#include <wv2/word97_generated.h>
34#include <wv2/parser.h>
35#include <wv2/parserfactory.h>
36#include <wv2/paragraphproperties.h>
37#include <wv2/associatedstrings.h>
38#include <tdelocale.h>
39#include <KoStore.h>
40#include <KoFilterChain.h>
41
42
43Document::Document( const std::string& fileName, TQDomDocument& mainDocument, TQDomDocument& documentInfo, TQDomElement& framesetsElement, KoFilterChain* chain )
44 : m_mainDocument( mainDocument ), m_documentInfo ( documentInfo ),
45 m_framesetsElement( framesetsElement ),
46 m_replacementHandler( new KWordReplacementHandler ), m_tableHandler( new KWordTableHandler ),
47 m_pictureHandler( new KWordPictureHandler( this ) ), m_textHandler( 0 ),
48 m_chain( chain ),
49 m_parser( wvWare::ParserFactory::createParser( fileName ) ), m_headerFooters( 0 ), m_bodyFound( false ),
50 m_footNoteNumber( 0 ), m_endNoteNumber( 0 )
51{
52 if ( m_parser ) // 0 in case of major error (e.g. unsupported format)
53 {
54 m_textHandler = new KWordTextHandler( m_parser );
55 connect( m_textHandler, TQ_SIGNAL( subDocFound( const wvWare::FunctorBase*, int ) ),
56 this, TQ_SLOT( slotSubDocFound( const wvWare::FunctorBase*, int ) ) );
57 connect( m_textHandler, TQ_SIGNAL( tableFound( const KWord::Table& ) ),
58 this, TQ_SLOT( slotTableFound( const KWord::Table& ) ) );
59 connect( m_textHandler, TQ_SIGNAL( pictureFound( const TQString&, const TQString&, const wvWare::FunctorBase* ) ),
60 this, TQ_SLOT( slotPictureFound( const TQString&, const TQString&, const wvWare::FunctorBase* ) ) );
61 m_parser->setSubDocumentHandler( this );
62 m_parser->setTextHandler( m_textHandler );
63 m_parser->setTableHandler( m_tableHandler );
64#ifdef IMAGE_IMPORT
65 m_parser->setPictureHandler( m_pictureHandler );
66#endif
67 m_parser->setInlineReplacementHandler( m_replacementHandler );
68 processStyles();
69 processAssociatedStrings();
70 connect( m_tableHandler, TQ_SIGNAL( sigTableCellStart( int, int, int, int, const KoRect&, const TQString&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::SHD& ) ),
71 this, TQ_SLOT( slotTableCellStart( int, int, int, int, const KoRect&, const TQString&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::SHD& ) ) );
72 connect( m_tableHandler, TQ_SIGNAL( sigTableCellEnd() ),
73 this, TQ_SLOT( slotTableCellEnd() ) );
74 }
75}
76
78{
79 delete m_textHandler;
80 delete m_pictureHandler;
81 delete m_tableHandler;
82 delete m_replacementHandler;
83}
84
85void Document::finishDocument()
86{
87 const wvWare::Word97::DOP& dop = m_parser->dop();
88
89 TQDomElement elementDoc = m_mainDocument.documentElement();
90
91 TQDomElement element;
92 element = m_mainDocument.createElement("ATTRIBUTES");
93 element.setAttribute("processing",0); // WP
94 char allHeaders = ( wvWare::HeaderData::HeaderEven |
95 wvWare::HeaderData::HeaderOdd |
96 wvWare::HeaderData::HeaderFirst );
97 element.setAttribute("hasHeader", m_headerFooters & allHeaders ? 1 : 0 );
98 char allFooters = ( wvWare::HeaderData::FooterEven |
99 wvWare::HeaderData::FooterOdd |
100 wvWare::HeaderData::FooterFirst );
101 element.setAttribute("hasFooter", m_headerFooters & allFooters ? 1 : 0 );
102 //element.setAttribute("unit","mm"); // How to figure out the unit to use?
103
104 element.setAttribute("tabStopValue", (double)dop.dxaTab / 20.0 );
105 elementDoc.appendChild(element);
106
107 element = m_mainDocument.createElement("FOOTNOTESETTING");
108 elementDoc.appendChild(element);
109 element.setAttribute( "start", dop.nFtn ); // initial footnote number for document. Starts at 1.
110 element.setAttribute( "type", Conversion::numberFormatCode( dop.nfcFtnRef2 ) );
111
112 element = m_mainDocument.createElement("ENDNOTESETTING");
113 elementDoc.appendChild(element);
114 element.setAttribute( "start", dop.nEdn ); // initial endnote number for document. Starts at 1.
115 element.setAttribute( "type", Conversion::numberFormatCode( dop.nfcEdnRef2 ) );
116
117 // Done at the end: write the type of headers/footers,
118 // depending on which kind of headers and footers we received.
119 TQDomElement paperElement = elementDoc.namedItem("PAPER").toElement();
120 Q_ASSERT ( !paperElement.isNull() ); // slotFirstSectionFound should have been called!
121 if ( !paperElement.isNull() )
122 {
123 kdDebug(30513) << k_funcinfo << "m_headerFooters=" << m_headerFooters << endl;
124 paperElement.setAttribute("hType", Conversion::headerMaskToHType( m_headerFooters ) );
125 paperElement.setAttribute("fType", Conversion::headerMaskToFType( m_headerFooters ) );
126 }
127
128 // Write out <PICTURES> tag
129 TQDomElement picturesElem = m_mainDocument.createElement("PICTURES");
130 elementDoc.appendChild( picturesElem );
131 for( TQStringList::Iterator it = m_pictureList.begin(); it != m_pictureList.end(); ++it ) {
132 TQDomElement keyElem = m_mainDocument.createElement("KEY");
133 picturesElem.appendChild( keyElem );
134 keyElem.setAttribute( "filename", *it );
135 keyElem.setAttribute( "name", *it );
136 }
137}
138
139void Document::processAssociatedStrings() {
140 wvWare::AssociatedStrings strings( m_parser->associatedStrings() );
141
142 TQDomElement infodoc = m_documentInfo.createElement( "document-info" );
143 TQDomElement author = m_documentInfo.createElement( "author" );
144 TQDomElement fullname = m_documentInfo.createElement( "full-name" );
145 TQDomElement title = m_documentInfo.createElement( "title" );
146 TQDomElement about = m_documentInfo.createElement( "about" );
147
148 m_documentInfo.appendChild(infodoc);
149
150 if ( !strings.author().isNull()) {
151 fullname.appendChild(
152 m_documentInfo.createTextNode(
153 Conversion::string (
154 strings.author()
155 ).string()));
156 author.appendChild(fullname);
157 infodoc.appendChild(author);
158 }
159
160 if ( !strings.title().isNull()) {
161 title.appendChild(
162 m_documentInfo.createTextNode(
163 Conversion::string (
164 strings.title()
165 ).string()));
166 about.appendChild(title);
167 infodoc.appendChild(about);
168 }
169
170}
171
172void Document::processStyles()
173{
174 TQDomElement stylesElem = m_mainDocument.createElement( "STYLES" );
175 m_mainDocument.documentElement().appendChild( stylesElem );
176
177 m_textHandler->setFrameSetElement( stylesElem );
178 const wvWare::StyleSheet& styles = m_parser->styleSheet();
179 unsigned int count = styles.size();
180 //kdDebug(30513) << k_funcinfo << "styles count=" << count << endl;
181 for ( unsigned int i = 0; i < count ; ++i )
182 {
183 const wvWare::Style* style = styles.styleByIndex( i );
184 Q_ASSERT( style );
185 //kdDebug(30513) << k_funcinfo << "style " << i << " " << style << endl;
186 if ( style && style->type() == wvWare::Style::sgcPara )
187 {
188 TQDomElement styleElem = m_mainDocument.createElement("STYLE");
189 stylesElem.appendChild( styleElem );
190
191 TQConstString name = Conversion::string( style->name() );
192 TQDomElement element = m_mainDocument.createElement("NAME");
193 element.setAttribute( "value", name.string() );
194 styleElem.appendChild( element );
195
196 kdDebug(30513) << k_funcinfo << "Style " << i << ": " << name.string() << endl;
197
198 const wvWare::Style* followingStyle = styles.styleByID( style->followingStyle() );
199 if ( followingStyle && followingStyle != style )
200 {
201 TQConstString followingName = Conversion::string( followingStyle->name() );
202 element = m_mainDocument.createElement("FOLLOWING");
203 element.setAttribute( "name", followingName.string() );
204 styleElem.appendChild( element );
205 }
206
207 m_textHandler->paragLayoutBegin(); // new style, reset some vars
208
209 // It's important to do that one first, for m_shadowTextFound
210 m_textHandler->writeFormat( styleElem, &style->chp(), 0L /*all of it, no ref chp*/, 0, 0, 1, 0L );
211
212 m_textHandler->writeLayout( styleElem, style->paragraphProperties(), style );
213 }
214 // KWord doesn't support character styles yet
215 }
216}
217
218bool Document::parse()
219{
220 if ( m_parser )
221 return m_parser->parse();
222 return false;
223}
224
225void Document::bodyStart()
226{
227 kdDebug(30513) << k_funcinfo << endl;
228
229 TQDomElement mainFramesetElement = m_mainDocument.createElement("FRAMESET");
230 mainFramesetElement.setAttribute("frameType",1);
231 mainFramesetElement.setAttribute("frameInfo",0);
232 // TODO: "name" attribute (needs I18N)
233 m_framesetsElement.appendChild(mainFramesetElement);
234
235 // Those values are unused. The paper margins make recalcFrames() resize this frame.
236 createInitialFrame( mainFramesetElement, 29, 798, 42, 566, false, Reconnect );
237
238 m_textHandler->setFrameSetElement( mainFramesetElement );
239 connect( m_textHandler, TQ_SIGNAL( firstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ),
240 this, TQ_SLOT( slotFirstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ) );
241 m_bodyFound = true;
242}
243
244void Document::bodyEnd()
245{
246 kdDebug(30513) << k_funcinfo << endl;
247 disconnect( m_textHandler, TQ_SIGNAL( firstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ),
248 this, TQ_SLOT( slotFirstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ) );
249}
250
251
252void Document::slotFirstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> sep )
253{
254 kdDebug(30513) << k_funcinfo << endl;
255 TQDomElement elementDoc = m_mainDocument.documentElement();
256
257 TQDomElement elementPaper = m_mainDocument.createElement("PAPER");
258 bool landscape = (sep->dmOrientPage == 2);
259 double width = (double)sep->xaPage / 20.0;
260 double height = (double)sep->yaPage / 20.0;
261 elementPaper.setAttribute("width", width);
262 elementPaper.setAttribute("height", height);
263
264 // guessFormat takes millimeters
265 width = POINT_TO_MM( width );
266 height = POINT_TO_MM( height );
267 KoFormat paperFormat = KoPageFormat::guessFormat( landscape ? height : width, landscape ? width : height );
268 elementPaper.setAttribute("format",paperFormat);
269
270 elementPaper.setAttribute("orientation", landscape ? PG_LANDSCAPE : PG_PORTRAIT );
271 elementPaper.setAttribute("columns", sep->ccolM1 + 1 );
272 elementPaper.setAttribute("columnspacing", (double)sep->dxaColumns / 20.0);
273 elementPaper.setAttribute("spHeadBody", (double)sep->dyaHdrTop / 20.0);
274 elementPaper.setAttribute("spFootBody", (double)sep->dyaHdrBottom / 20.0);
275 // elementPaper.setAttribute("zoom",100); // not a doc property in kword
276 elementDoc.appendChild(elementPaper);
277
278 TQDomElement element = m_mainDocument.createElement("PAPERBORDERS");
279 element.setAttribute("left", (double)sep->dxaLeft / 20.0);
280 element.setAttribute("top",(double)sep->dyaTop / 20.0);
281 element.setAttribute("right", (double)sep->dxaRight / 20.0);
282 element.setAttribute("bottom", (double)sep->dyaBottom / 20.0);
283 elementPaper.appendChild(element);
284
285 // TODO apply brcTop/brcLeft etc. to the main FRAME
286 // TODO use sep->fEndNote to set the 'use endnotes or footnotes' flag
287}
288
289void Document::headerStart( wvWare::HeaderData::Type type )
290{
291 kdDebug(30513) << "startHeader type=" << type << " (" << Conversion::headerTypeToFramesetName( type ) << ")" << endl;
292 // Werner says the headers are always emitted in the order of the Type enum.
293
294 TQDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
295 framesetElement.setAttribute( "frameType", 1 );
296 framesetElement.setAttribute( "frameInfo", Conversion::headerTypeToFrameInfo( type ) );
297 framesetElement.setAttribute( "name", Conversion::headerTypeToFramesetName( type ) );
298 m_framesetsElement.appendChild(framesetElement);
299
300 bool isHeader = Conversion::isHeader( type );
301
302 createInitialFrame( framesetElement, 29, 798, isHeader?0:567, isHeader?41:567+41, true, Copy );
303
304 m_textHandler->setFrameSetElement( framesetElement );
305
306 m_headerFooters |= type;
307
308 /*if ( Conversion::isHeader( type ) )
309 m_hasHeader = true;
310 else
311 m_hasFooter = true;*/
312}
313
314void Document::headerEnd()
315{
316 m_textHandler->setFrameSetElement( TQDomElement() );
317}
318
319void Document::footnoteStart()
320{
321 // Grab data that was stored with the functor, that triggered this parsing
322 SubDocument subdoc( m_subdocQueue.front() );
323 int type = subdoc.data;
324
325 // Create footnote/endnote frameset
326 TQDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
327 framesetElement.setAttribute( "frameType", 1 /* text */ );
328 framesetElement.setAttribute( "frameInfo", 7 /* footnote/endnote */ );
329 if ( type == wvWare::FootnoteData::Endnote )
330 // Keep name in sync with KWordTextHandler::footnoteFound
331 framesetElement.setAttribute("name", i18n("Endnote %1").arg( ++m_endNoteNumber ) );
332 else
333 // Keep name in sync with KWordTextHandler::footnoteFound
334 framesetElement.setAttribute("name", i18n("Footnote %1").arg( ++m_footNoteNumber ) );
335 m_framesetsElement.appendChild(framesetElement);
336
337 createInitialFrame( framesetElement, 29, 798, 567, 567+41, true, NoFollowup );
338
339 m_textHandler->setFrameSetElement( framesetElement );
340}
341
342void Document::footnoteEnd()
343{
344 kdDebug(30513) << k_funcinfo << endl;
345 m_textHandler->setFrameSetElement( TQDomElement() );
346}
347
348void Document::slotTableCellStart( int row, int column, int rowSpan, int columnSpan, const KoRect& cellRect, const TQString& tableName, const wvWare::Word97::BRC& brcTop, const wvWare::Word97::BRC& brcBottom, const wvWare::Word97::BRC& brcLeft, const wvWare::Word97::BRC& brcRight, const wvWare::Word97::SHD& shd )
349{
350 // Create footnote/endnote frameset
351 TQDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
352 framesetElement.setAttribute( "frameType", 1 /* text */ );
353 framesetElement.setAttribute( "frameInfo", 0 /* normal text */ );
354 framesetElement.setAttribute( "grpMgr", tableName );
355 TQString name = i18n("Table_Name Cell row,column", "%1 Cell %2,%3").arg(tableName).arg(row).arg(column);
356 framesetElement.setAttribute( "name", name );
357 framesetElement.setAttribute( "row", row );
358 framesetElement.setAttribute( "col", column );
359 framesetElement.setAttribute( "rows", rowSpan );
360 framesetElement.setAttribute( "cols", columnSpan );
361 m_framesetsElement.appendChild(framesetElement);
362
363 TQDomElement frameElem = createInitialFrame( framesetElement, cellRect.left(), cellRect.right(), cellRect.top(), cellRect.bottom(), true, NoFollowup );
364 generateFrameBorder( frameElem, brcTop, brcBottom, brcLeft, brcRight, shd );
365
366 m_textHandler->setFrameSetElement( framesetElement );
367}
368
369void Document::slotTableCellEnd()
370{
371 m_textHandler->setFrameSetElement( TQDomElement() );
372}
373
374TQDomElement Document::createInitialFrame( TQDomElement& parentFramesetElem, double left, double right, double top, double bottom, bool autoExtend, NewFrameBehavior nfb )
375{
376 TQDomElement frameElementOut = parentFramesetElem.ownerDocument().createElement("FRAME");
377 frameElementOut.setAttribute( "left", left );
378 frameElementOut.setAttribute( "right", right );
379 frameElementOut.setAttribute( "top", top );
380 frameElementOut.setAttribute( "bottom", bottom );
381 frameElementOut.setAttribute( "runaround", 1 );
382 // AutoExtendFrame for header/footer/footnote/endnote, AutoCreateNewFrame for body text
383 frameElementOut.setAttribute( "autoCreateNewFrame", autoExtend ? 0 : 1 );
384 frameElementOut.setAttribute( "newFrameBehavior", nfb );
385 parentFramesetElem.appendChild( frameElementOut );
386 return frameElementOut;
387}
388
389void Document::generateFrameBorder( TQDomElement& frameElementOut, const wvWare::Word97::BRC& brcTop, const wvWare::Word97::BRC& brcBottom, const wvWare::Word97::BRC& brcLeft, const wvWare::Word97::BRC& brcRight, const wvWare::Word97::SHD& shd )
390{
391 // Frame borders
392
393 if ( brcTop.cv != 255 && brcTop.dptLineWidth != 255 ) // see tablehandler.cpp
394 Conversion::setBorderAttributes( frameElementOut, brcTop, "t" );
395 if ( brcBottom.cv != 255 && brcBottom.dptLineWidth != 255 ) // see tablehandler.cpp
396 Conversion::setBorderAttributes( frameElementOut, brcBottom, "b" );
397 if ( brcLeft.cv != 255 && brcLeft.dptLineWidth != 255 ) // could still be 255, for first column
398 Conversion::setBorderAttributes( frameElementOut, brcLeft, "l" );
399 if ( brcRight.cv != 255 && brcRight.dptLineWidth != 255 ) // could still be 255, for last column
400 Conversion::setBorderAttributes( frameElementOut, brcRight, "r" );
401
402 // Frame background brush (color and fill style)
403 if ( shd.cvFore != 0 || shd.cvBack != 0 )
404 {
405 // If ipat = 0 (solid fill), icoBack is the background color.
406 // But otherwise, icoFore is the one we need to set as bkColor
407 // (and icoBack is usually white; it's the other colour of the pattern,
408 // something that we can't set in TQt apparently).
409 int bkColor = shd.ipat ? shd.cvFore : shd.cvBack;
410 kdDebug(30513) << "generateFrameBorder: " << " icoFore=" << shd.cvFore << " icoBack=" << shd.cvBack << " ipat=" << shd.ipat << " -> bkColor=" << bkColor << endl;
411
412 // Reverse-engineer MSWord's own hackery: it models various gray levels
413 // using dithering. But this looks crappy with TQt. So we go back to a TQColor.
414 bool grayHack = ( shd.ipat && shd.cvFore == 1 && shd.cvBack == 8 );
415 if ( grayHack )
416 {
417 bool ok;
418 int grayLevel = Conversion::ditheringToGray( shd.ipat, &ok );
419 if ( ok )
420 {
421 TQColor color( 0, 0, grayLevel, TQColor::Hsv );
422 TQString prefix = "bk";
423 frameElementOut.setAttribute( "bkRed", color.red() );
424 frameElementOut.setAttribute( "bkBlue", color.blue() );
425 frameElementOut.setAttribute( "bkGreen", color.green() );
426 }
427 else grayHack = false;
428 }
429 if ( !grayHack )
430 {
431 Conversion::setColorAttributes( frameElementOut, bkColor, "bk", true );
432 // Fill style
433 int brushStyle = Conversion::fillPatternStyle( shd.ipat );
434 frameElementOut.setAttribute( "bkStyle", brushStyle );
435 }
436 }
437}
438
439void Document::slotSubDocFound( const wvWare::FunctorBase* functor, int data )
440{
441 SubDocument subdoc( functor, data, TQString(), TQString() );
442 m_subdocQueue.push( subdoc );
443}
444
445void Document::slotTableFound( const KWord::Table& table )
446{
447 m_tableQueue.push( table );
448}
449
450void Document::slotPictureFound( const TQString& frameName, const TQString& pictureName,
451 const wvWare::FunctorBase* pictureFunctor )
452{
453 SubDocument subdoc( pictureFunctor, 0, frameName, pictureName );
454 m_subdocQueue.push( subdoc );
455}
456
457void Document::processSubDocQueue()
458{
459 // Table cells can contain footnotes, and footnotes can contain tables [without footnotes though]
460 // This is why we need to repeat until there's nothing more do to (#79024)
461 while ( !m_subdocQueue.empty() || !m_tableQueue.empty() )
462 {
463 while ( !m_subdocQueue.empty() )
464 {
465 SubDocument subdoc( m_subdocQueue.front() );
466 Q_ASSERT( subdoc.functorPtr );
467 (*subdoc.functorPtr)(); // call it
468 delete subdoc.functorPtr; // delete it
469 m_subdocQueue.pop();
470 }
471 while ( !m_tableQueue.empty() )
472 {
473 KWord::Table& table = m_tableQueue.front();
474 m_tableHandler->tableStart( &table );
475 TQValueList<KWord::Row> &rows = table.rows;
476 for( TQValueList<KWord::Row>::Iterator it = rows.begin(); it != rows.end(); ++it ) {
477 KWord::TableRowFunctorPtr f = (*it).functorPtr;
478 Q_ASSERT( f );
479 (*f)(); // call it
480 delete f; // delete it
481 }
482 m_tableHandler->tableEnd();
483 m_tableQueue.pop();
484 }
485 }
486}
487
488KoStoreDevice* Document::createPictureFrameSet( const KoSize& size )
489{
490 // Grab data that was stored with the functor, that triggered this parsing
491 SubDocument subdoc( m_subdocQueue.front() );
492
493 TQDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
494 framesetElement.setAttribute( "frameType", 2 /*picture*/ );
495 framesetElement.setAttribute( "frameInfo", 0 );
496 framesetElement.setAttribute( "name", subdoc.name );
497 m_framesetsElement.appendChild(framesetElement);
498
499 // The position doesn't matter as long as the picture is inline
500 // FIXME for non-inline pics ####
501 // To determine the size, look at OOo's filter (WW8PicDesc in ww8graf2.cpp, version 1.50, line 406)
502 // Hint: #i17200#, a bit of guesswork I'm afraid
503 // if (aPic.dxaGoal == 1000 && aPic.mx == 1) //100% hack ? (from ww8graf2.cpp)
504 createInitialFrame( framesetElement, 0, size.width(), 0, size.height(), false, NoFollowup );
505
506 TQDomElement pictureElem = m_mainDocument.createElement("PICTURE");
507 framesetElement.appendChild( pictureElem );
508
509 TQDomElement keyElem = m_mainDocument.createElement("KEY");
510 pictureElem.appendChild( keyElem );
511 keyElem.setAttribute( "filename", subdoc.extraName );
512 m_pictureList.append( subdoc.extraName );
513
514 kdDebug(30513) << "Preparing to write picture for '" << subdoc.name << "' into " << subdoc.extraName << endl;
515 return m_chain->storageFile( subdoc.extraName, KoStore::Write );
516}
517
518
519#include "document.moc"
virtual ~Document()
Destructor.