kword13parser.cpp
1/* This file is part of the KDE project
2 Copyright 2001, 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library 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 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. 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 <kdebug.h>
21
22#include "kword13formatone.h"
23#include "kword13formatother.h"
24#include "kword13layout.h"
25#include "kword13frameset.h"
26#include "kword13picture.h"
27#include "kword13document.h"
28#include "kword13parser.h"
29
30KWord13StackItem::KWord13StackItem() : elementType( KWord13TypeUnknown ), m_currentFrameset( 0 )
31{
32}
33
34KWord13StackItem::~KWord13StackItem()
35{
36}
37
38KWord13Parser::KWord13Parser( KWord13Document* kwordDocument )
39 : m_kwordDocument(kwordDocument), m_currentParagraph( 0 ),
40 m_currentLayout( 0 ), m_currentFormat( 0 )
41{
42 parserStack.setAutoDelete( true );
43 KWord13StackItem* bottom = new KWord13StackItem;
44 bottom->elementType = KWord13TypeBottom;
45 parserStack.push( bottom ); //Security item (not to empty the stack)
46}
47
48KWord13Parser::~KWord13Parser( void )
49{
50 parserStack.clear();
51 delete m_currentParagraph;
52 delete m_currentLayout;
53 delete m_currentFormat;
54}
55
56bool KWord13Parser::startElementFormatOneProperty( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem)
57{
58 // ### TODO: check status
59 if ( stackItem->elementType == KWord13TypeLayoutFormatOne )
60 {
61 if ( ! m_currentLayout )
62 {
63 kdError(30520) << "No current LAYOUT for storing FORMAT property: " << name << endl;
64 return false;
65 }
66 for (int i = 0; i < attributes.count(); ++i )
67 {
68 TQString attrName ( name );
69 attrName += ':';
70 attrName += attributes.qName( i );
71 m_currentLayout->m_format.m_properties[ attrName ] = attributes.value( i );
72 kdDebug(30520) << "Format Property (for LAYOUT): " << attrName << " = " << attributes.value( i ) << endl;
73 }
74 stackItem->elementType = KWord13TypeEmpty;
75 return true;
76 }
77 else if ( stackItem->elementType == KWord13TypeFormat )
78 {
79 if ( ! m_currentFormat )
80 {
81 kdError(30520) << "No current FORMAT for storing FORMAT property: " << name << endl;
82 return false;
83 }
84 KWord13FormatOneData* data = m_currentFormat->getFormatOneData();
85
86 if ( ! data )
87 {
88 kdError(30520) << "Current FORMAT cannot store FORMAT text property: " << name << endl;
89 return false;
90 }
91
92 for (int i = 0; i < attributes.count(); ++i )
93 {
94 TQString attrName ( name );
95 attrName += ':';
96 attrName += attributes.qName( i );
97 data->m_properties[ attrName ] = attributes.value( i );
98 kdDebug(30520) << "Format Property (for FORMATS): " << attrName << " = " << attributes.value( i ) << endl;
99 }
100 stackItem->elementType = KWord13TypeEmpty;
101 return true;
102 }
103 else if ( stackItem->elementType == KWord13TypeIgnore )
104 {
105 return true;
106 }
107 else
108 {
109 kdError(30520) << "Wrong parents for FORMAT property: " << name << endl;
110 return false;
111 }
112}
113
114bool KWord13Parser::startElementLayoutProperty( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem)
115{
116 // ### TODO: check status
117 if ( stackItem->elementType == KWord13TypeIgnore )
118 {
119 return true;
120 }
121 else if ( m_currentLayout )
122 {
123 for (int i = 0; i < attributes.count(); ++i )
124 {
125 TQString attrName ( name );
126 attrName += ':';
127 attrName += attributes.qName( i );
128 m_currentLayout->m_layoutProperties[ attrName ] = attributes.value( i );
129 kdDebug(30520) << "Layout Property: " << attrName << " = " << attributes.value( i ) << endl;
130 }
131 stackItem->elementType = KWord13TypeEmpty;
132 return true;
133 }
134 else
135 {
136 kdError(30520) << "No current layout for storing property: " << name << endl;
137 return false;
138 }
139}
140
141bool KWord13Parser::startElementName( const TQString&, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
142{
143 if ( stackItem->elementType != KWord13TypeLayout )
144 {
145 // We have something else than a LAYOU/STYLE, so ignore for now.
146 stackItem->elementType = KWord13TypeIgnore;
147 return true;
148 }
149
150 stackItem->elementType = KWord13TypeEmpty;
151
152 if ( m_currentLayout )
153 {
154 m_currentLayout->m_name = attributes.value( "value" );
155 }
156 return true;
157}
158
159bool KWord13Parser::startElementFormat( const TQString&, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
160{
161 // ### TODO: check parent?
162 if ( stackItem->elementType == KWord13TypeIgnore )
163 {
164 return true;
165 }
166 else if ( stackItem->elementType == KWord13TypeLayout )
167 {
168 stackItem->elementType = KWord13TypeLayoutFormatOne;
169 return true; // Everything is done directly on the layout
170 }
171 else if ( stackItem->elementType != KWord13TypeFormatsPlural )
172 {
173 kdError(30520) << "<FORMAT> is child neither of <FORMATS> nor of <LAYOUT> nor of <STYLE>! Aborting!" << endl;
174 return false; // Assume parsing error!
175 }
176
177 stackItem->elementType = KWord13TypeFormat;
178
179 if ( m_currentFormat )
180 {
181 kdWarning(30520) << "Current format already defined!" << endl;
182 delete m_currentFormat;
183 m_currentFormat = 0;
184 }
185
186 bool ok = false;
187 const int id = attributes.value( "id" ).toInt( &ok );
188
189 if ( id == 1 && ok ) // Normal text
190 {
192 const int len = attributes.value( "len" ).toInt( &ok );
193 if ( ok )
194 one->m_length = len;
195 m_currentFormat = one;
196 }
197 else if ( id == 4 && ok ) // Variable
198 {
199 stackItem->elementType = KWord13TypeVariable;
200 m_currentFormat = new KWord13FormatFour;
201 }
202 else if ( id == 6 && ok ) // Anchor
203 {
204 stackItem->elementType = KWord13TypeAnchor;
205 m_currentFormat = new KWord13FormatSix;
206 }
207 else
208 {
209 // ### TODO: provisory
210 stackItem->elementType = KWord13TypeIgnore;
211 m_currentFormat = new KWord13Format;
212 if ( ok )
213 m_currentFormat->m_id = id;
214 }
215 const int pos = attributes.value( "pos" ).toInt( &ok );
216 if ( ok )
217 {
218 m_currentFormat->m_pos = pos;
219 }
220 else
221 {
222 kdWarning(30520) << "Cannot set position of <FORMAT>: " << attributes.value( "pos" ) << endl;
223 return false; // Assume parse error!
224 }
225
226 kdDebug(30520) << "<FORMAT id=\"" << id << "\" pos=\"" << pos << "\" len=\"" << attributes.value( "len" ) << "\">" << endl;
227
228 return true;
229}
230
231bool KWord13Parser::startElementLayout( const TQString&, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
232{
233 // ### TODO: check parent?
234 if ( stackItem->elementType == KWord13TypeIgnore )
235 {
236 return true;
237 }
238
239 stackItem->elementType = KWord13TypeLayout;
240
241 if ( m_currentFormat )
242 {
243 kdWarning(30520) << "Current format defined! (Layout)" << endl;
244 delete m_currentFormat;
245 m_currentFormat = 0;
246 }
247 if ( m_currentLayout )
248 {
249 // Delete an eventually already existing paragraph (should not happen)
250 kdWarning(30520) << "Current layout already defined!" << endl;
251 delete m_currentLayout;
252 }
253
254 m_currentLayout = new KWord13Layout;
255 m_currentLayout->m_outline = ( attributes.value( "outline" ) == "true" );
256
257 return true;
258}
259
260bool KWord13Parser::startElementParagraph( const TQString&, const TQXmlAttributes&, KWord13StackItem *stackItem )
261{
262 if ( stackItem->elementType == KWord13TypeUnknownFrameset )
263 {
264 stackItem->elementType = KWord13TypeIgnore;
265 return true;
266 }
267
268 stackItem->elementType = KWord13TypeParagraph;
269
270 if ( m_currentParagraph )
271 {
272 // Delete an eventually already existing paragraph (should not happen)
273 kdWarning(30520) << "Current paragraph already defined!" << endl;
274 delete m_currentParagraph;
275 }
276
277 m_currentParagraph = new KWord13Paragraph;
278
279 return true;
280}
281
282bool KWord13Parser::startElementFrame( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
283{
284 if ( stackItem->elementType == KWord13TypeFrameset || stackItem->elementType == KWord13TypePictureFrameset )
285 {
286 stackItem->elementType = KWord13TypeEmpty;
287 if ( stackItem->m_currentFrameset )
288 {
289 const int num = ++stackItem->m_currentFrameset->m_numFrames;
290 for (int i = 0; i < attributes.count(); ++i )
291 {
292 TQString attrName ( name );
293 attrName += ':';
294 attrName += TQString::number( num );
295 attrName += ':';
296 attrName += attributes.qName( i );
297 stackItem->m_currentFrameset->m_frameData[ attrName ] = attributes.value( i );
298 kdDebug(30520) << "FrameData: " << attrName << " = " << attributes.value( i ) << endl;
299 }
300
301 }
302 else
303 {
304 kdError(30520) << "Data of <FRAMESET> not found" << endl;
305 return false;
306 }
307 }
308 else if ( stackItem->elementType != KWord13TypeUnknownFrameset )
309 {
310 kdError(30520) << "<FRAME> not child of <FRAMESET>" << endl;
311 return false;
312 }
313 return true;
314}
315
316bool KWord13Parser::startElementFrameset( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
317{
318 const TQString frameTypeStr( attributes.value( "frameType" ) );
319 const TQString frameInfoStr( attributes.value( "frameInfo" ) );
320
321 if ( frameTypeStr.isEmpty() || frameInfoStr.isEmpty() )
322 {
323 kdError(30520) << "<FRAMESET> without frameType or frameInfo attribute!" << endl;
324 return false;
325 }
326
327 const int frameType = frameTypeStr.toInt();
328 const int frameInfo = frameInfoStr.toInt();
329
330 if ( frameType == 1 )
331 {
332 stackItem->elementType = KWord13TypeFrameset;
333 KWordTextFrameset* frameset = new KWordTextFrameset( frameType, frameInfo, attributes.value( "name" ) );
334
335 // Normal text frame (in or outside a table)
336 if ( ( !frameInfo ) && attributes.value( "grpMgr" ).isEmpty() )
337 {
338 m_kwordDocument->m_normalTextFramesetList.append( frameset );
339 stackItem->m_currentFrameset = m_kwordDocument->m_normalTextFramesetList.current();
340 }
341 else if ( !frameInfo )
342 {
343 // We just store the frameset in the frameset table list
344 // Grouping the framesets by table will be done after the parsing, not now.
345 m_kwordDocument->m_tableFramesetList.append( frameset );
346 stackItem->m_currentFrameset = m_kwordDocument->m_tableFramesetList.current();
347 }
348 else if ( frameInfo >= 1 && frameInfo <= 6 )
349 {
350 m_kwordDocument->m_headerFooterFramesetList.append( frameset );
351 stackItem->m_currentFrameset = m_kwordDocument->m_headerFooterFramesetList.current();
352 }
353 else if ( frameInfo == 7 )
354 {
355 m_kwordDocument->m_footEndNoteFramesetList.append( frameset );
356 stackItem->m_currentFrameset = m_kwordDocument->m_footEndNoteFramesetList.current();
357 }
358 else
359 {
360 kdError(30520) << "Unknown text frameset!" << endl;
361 m_kwordDocument->m_otherFramesetList.append( frameset );
362 stackItem->m_currentFrameset = m_kwordDocument->m_otherFramesetList.current();
363 }
364 }
365 else if ( ( frameType == 2 ) // picture or image
366 || ( frameType == 5 ) ) // ciipart
367 {
368 if ( !frameInfo )
369 {
370 kdWarning(30520) << "Unknown FrameInfo for pictures: " << frameInfo << endl;
371 }
372 stackItem->elementType = KWord13TypePictureFrameset;
373 KWord13PictureFrameset* frameset = new KWord13PictureFrameset( frameType, frameInfo, attributes.value( "name" ) );
374 m_kwordDocument->m_otherFramesetList.append( frameset );
375 stackItem->m_currentFrameset = m_kwordDocument->m_otherFramesetList.current();
376 }
377 // ### frameType == 6 : horizontal line (however KWord did not save it correctly)
378 // ### frameType == 4 : formula
379 // ### frametype == 3 : embedded (but only in <SETTINGS>)
380 else
381 {
382 // Frame of unknown/unsupported type
383 kdWarning(30520) << "Unknown/unsupported <FRAMESET> type! Type: " << frameTypeStr << " Info: " << frameInfoStr << endl;
384 stackItem->elementType = KWord13TypeUnknownFrameset;
385 KWord13Frameset* frameset = new KWord13Frameset( frameType, frameInfo, attributes.value( "name" ) );
386 m_kwordDocument->m_otherFramesetList.append( frameset );
387 stackItem->m_currentFrameset = m_kwordDocument->m_otherFramesetList.current();
388 }
389 return true;
390}
391
392
393bool KWord13Parser::startElementDocumentAttributes( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem,
394 const KWord13StackItemType& allowedParentType, const KWord13StackItemType& newType )
395{
396 if ( parserStack.current()->elementType == allowedParentType )
397 {
398 stackItem->elementType = newType;
399 for (int i = 0; i < attributes.count(); ++i )
400 {
401 TQString attrName ( name );
402 attrName += ':';
403 attrName += attributes.qName( i );
404 m_kwordDocument->m_documentProperties[ attrName ] = attributes.value( i );
405 kdDebug(30520) << "DocAttr: " << attrName << " = " << attributes.value( i ) << endl;
406 }
407 return true;
408 }
409 else
410 {
411 kdError(30520) << "Wrong parent!" << endl;
412 return false;
413 }
414}
415
416bool KWord13Parser::startElementKey( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
417{
418 const TQString key( calculatePictureKey( attributes.value( "filename" ),
419 attributes.value( "year" ), attributes.value( "month" ), attributes.value( "day" ),
420 attributes.value( "hour" ), attributes.value( "minute" ), attributes.value( "second" ),
421 attributes.value( "msec" ) ) );
422 kdDebug(30520) << "Picture key: " << key << endl;
423
424 if ( stackItem->elementType == KWord13TypePicturesPlural )
425 {
426 KWord13Picture* pic = new KWord13Picture;
427 pic->m_storeName = attributes.value( "name" );
428 if ( pic->m_storeName.isEmpty() )
429 {
430 kdError(30520) << "Picture defined without store name! Aborting!" << endl;
431 return false; // Assume parse error
432 }
433 // ### TODO: catch duplicate keys (should not happen but who knows?)
434 m_kwordDocument->m_pictureDict.insert( key, pic );
435 }
436 else if ( stackItem->elementType == KWord13TypePicture )
437 {
438 // ### TODO: error messages?
439 if ( stackItem->m_currentFrameset )
440 {
441 stackItem->m_currentFrameset->setKey( key );
442 }
443 }
444 else
445 {
446 // Neither child of <PICTURES>, <PIXMAPS>, <CLIPARTS>
447 // nor of <PICTURE>, <IMAGE>, <CLIPART>
448 // ### TODO: parse error?
449 }
450 return true;
451}
452
453bool KWord13Parser::startElementAnchor( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
454{
455 if ( stackItem->elementType == KWord13TypeAnchor )
456 {
457 const TQString anchorType ( attributes.value( "type" ) );
458 if ( anchorType == "grpMgr" )
459 kdWarning(30520) << "Anchor of type grpMgr! Not tested!" << endl; // ### TODO
460 else if ( anchorType != "frameset" )
461 {
462 kdError(30520) << "Unsupported anchor type: " << anchorType << endl;
463 return false;
464 }
465 const TQString frameset ( attributes.value( "instance" ) );
466 if ( frameset.isEmpty() )
467 {
468 kdError(30520) << "Anchor to an empty frameset name! Aborting!" << endl;
469 return false;
470 }
471 if ( m_currentFormat )
472 {
473 KWord13FormatSix* six = (KWord13FormatSix*) m_currentFormat;
474 six->m_anchorName = frameset;
475 }
476 // add frameset name to the list of anchored framesets
477 if ( m_kwordDocument->m_anchoredFramesetNames.find( frameset ) == m_kwordDocument->m_anchoredFramesetNames.end() )
478 {
479 m_kwordDocument->m_anchoredFramesetNames.append( frameset );
480 }
481 }
482 else
483 {
484 kdError(30520) << "Anchor not child of <FORMAT id=\"6\"> Aborting!" << endl;
485 return false;
486 }
487 return true;
488}
489
490
491bool KWord13Parser::startElement( const TQString&, const TQString&, const TQString& name, const TQXmlAttributes& attributes )
492{
493 kdDebug(30520) << indent << "<" << name << ">" << endl; // DEBUG
494 indent += "*"; //DEBUG
495 if (parserStack.isEmpty())
496 {
497 kdError(30520) << "Stack is empty!! Aborting! (in KWordParser::startElement)" << endl;
498 return false;
499 }
500
501 // Create a new stack element copying the top of the stack.
502 KWord13StackItem *stackItem=new KWord13StackItem(*parserStack.current());
503
504 if (!stackItem)
505 {
506 kdError(30520) << "Could not create Stack Item! Aborting! (in StructureParser::startElement)" << endl;
507 return false;
508 }
509
510 stackItem->itemName=name;
511
512 bool success=false;
513
514 // Order of element names: probability in a document
515 if ( name == "COLOR" || name == "FONT" || name =="SIZE"
516 || name == "WEIGHT" || name == "ITALIC" || name == "UNDERLINE"
517 || name == "STRIKEOUT" || name == "VERTALIGN" || name == "SHADOW"
518 || name == "FONTATTRIBUTE" || name == "LANGUAGE"
519 || name == "TEXTBACKGROUNDCOLOR" || name == "OFFSETFROMBASELINE" )
520 {
521 success = startElementFormatOneProperty( name, attributes, stackItem );
522 }
523 else if ( name == "FLOW" || name == "INDENTS" || name == "OFFSETS"
524 || name == "LINESPACING" || name == "PAGEBREAKING"
525 || name == "LEFTBORDER" || name == "RIGHTBORDER" || name == "FOLLOWING"
526 || name == "TOPBORDER" || name == "BOTTOMBORDER" || name == "COUNTER" )
527 {
528 success = startElementLayoutProperty( name, attributes, stackItem );
529 }
530 else if ( name == "TEXT" )
531 {
532 if ( stackItem->elementType == KWord13TypeParagraph && m_currentParagraph )
533 {
534 stackItem->elementType = KWord13TypeText;
535 m_currentParagraph->setText( TQString() );
536 }
537 else
538 {
539 stackItem->elementType = KWord13TypeIgnore;
540 }
541 success = true;
542 }
543 else if ( name == "NAME" )
544 {
545 success = startElementName( name, attributes, stackItem );
546 }
547 else if ( name == "FORMATS" )
548 {
549 if ( stackItem->elementType == KWord13TypeParagraph && m_currentParagraph )
550 {
551 stackItem->elementType = KWord13TypeFormatsPlural;
552 }
553 else
554 {
555 stackItem->elementType = KWord13TypeIgnore;
556 }
557 success = true;
558 }
559 else if ( name == "PARAGRAPH" )
560 {
561 success = startElementParagraph( name, attributes, stackItem );
562 }
563 else if ( name == "FORMAT" )
564 {
565 success = startElementFormat( name, attributes, stackItem );
566 }
567 else if (name == "LAYOUT" )
568 {
569 success = startElementLayout( name, attributes, stackItem );
570 }
571 else if ( name == "TYPE" )
572 {
573 // ### TEMPORARY
574 if ( m_currentFormat && ( stackItem->elementType == KWord13TypeVariable ) )
575 {
576 ( (KWord13FormatFour*) m_currentFormat ) -> m_text = attributes.value( "text" );
577 }
578 success = true;
579 }
580 else if ( name == "KEY" )
581 {
582 success = startElementKey( name, attributes, stackItem );
583 }
584 else if ( name == "ANCHOR" )
585 {
586 success = startElementAnchor( name, attributes, stackItem );
587 }
588 else if ( name == "PICTURE" || name == "IMAGE" || name == "CLIPART" )
589 {
590 // ### TODO: keepAspectRatio (but how to transform it to OASIS)
591 if ( stackItem->elementType == KWord13TypePictureFrameset )
592 {
593 stackItem->elementType = KWord13TypePicture;
594 }
595 success = true;
596 }
597 else if ( name == "FRAME" )
598 {
599 success = startElementFrame( name, attributes, stackItem );
600 }
601 else if ( name == "FRAMESET" )
602 {
603 success = startElementFrameset( name, attributes, stackItem );
604 }
605 else if (name == "STYLE" )
606 {
607 success = startElementLayout( name, attributes, stackItem );
608 }
609 else if ( name == "DOC" )
610 {
611 success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypeBottom, KWord13TypeDocument );
612 }
613 else if ( name == "PAPER")
614 {
615 success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypeDocument, KWord13TypePaper );
616 }
617 else if ( name == "PAPERBORDERS" )
618 {
619 success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypePaper, KWord13TypeEmpty );
620 }
621 else if ( ( name == "ATTRIBUTES" ) || ( name == "VARIABLESETTINGS" )
622 || ( name == "FOOTNOTESETTINGS" ) || ( name == "ENDNOTESETTINGS" ) )
623 {
624 success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypeDocument, KWord13TypeEmpty );
625 }
626 else if ( name == "FRAMESTYLE" )
627 {
628 // ### TODO, but some of the <STYLE> children are also children of <FRAMESTYLE>, so we have to set it to "ignore"
629 stackItem->elementType = KWord13TypeIgnore;
630 success = true;
631 }
632 else if ( name == "PICTURES" || name == "PIXMAPS" || name == "CLIPARTS" )
633 {
634 // We just need a separate "type" for the <KEY> children
635 stackItem->elementType = KWord13TypePicturesPlural;
636 success = true;
637 }
638 else
639 {
640 stackItem->elementType = KWord13TypeUnknown;
641 success = true;
642 }
643
644 if ( success )
645 {
646 parserStack.push( stackItem );
647 }
648 else
649 { // We have a problem so destroy our resources.
650 delete stackItem;
651 }
652
653 return success;
654}
655
656bool KWord13Parser :: endElement( const TQString&, const TQString& , const TQString& name)
657{
658 indent.remove( 0, 1 ); // DEBUG
659 //kdDebug(30520) << indent << "</" << name << ">" << endl; // DEBUG
660 if (parserStack.isEmpty())
661 {
662 kdError(30520) << "Stack is empty!! Aborting! (in StructureParser::endElement)" << endl;
663 return false;
664 }
665
666 bool success=false;
667
668 KWord13StackItem *stackItem=parserStack.pop();
669
670 if ( name == "PARAGRAPH" )
671 {
672 if ( stackItem->m_currentFrameset && m_currentParagraph )
673 {
674 if ( stackItem->m_currentFrameset->addParagraph( *m_currentParagraph ) )
675 {
676 success = true;
677 }
678 // ### HACK: do not delete the data of <FORMATS>
679 m_currentParagraph->m_formats.setAutoDelete( false );
680 }
681 else if ( stackItem->elementType == KWord13TypeIgnore )
682 {
683 success = true;
684 }
685 delete m_currentParagraph;
686 m_currentParagraph = 0;
687 }
688 else if ( name == "FORMAT" )
689 {
690 if ( stackItem->elementType == KWord13TypeFormat )
691 {
692 if ( m_currentParagraph )
693 {
694 m_currentParagraph->m_formats.append( m_currentFormat );
695 kdDebug(30520) << "Adding to <FORMATS>: " << ((void*) m_currentFormat) << endl;
696 m_currentFormat = 0;
697 }
698 else
699 {
700 kdError(30520) << "No paragraph to store <FORMAT>! Aborting!" << endl;
701 delete m_currentFormat;
702 m_currentFormat = 0;
703 return false; // Assume parsing error!
704 }
705
706 }
707 else if ( stackItem->elementType == KWord13TypeLayoutFormatOne )
708 {
709 // Nothing to do!
710 }
711 success = true;
712 }
713 else if ( name == "LAYOUT" )
714 {
715 if ( m_currentLayout && m_currentParagraph )
716 {
717 m_currentParagraph->m_layout = *m_currentLayout;
718 }
719 delete m_currentLayout;
720 m_currentLayout = 0;
721 success = true;
722 }
723 else if ( name == "STYLE" )
724 {
725 if ( m_kwordDocument && m_currentLayout )
726 {
727 if ( m_currentLayout->m_name.isEmpty() )
728 {
729 // ### TODO: what should be really done with anonymous styles (should not happen but it would have consequences)
730 kdError(30520) << "Anonymous style found! Aborting" << endl;
731 return false; // Assume a parsing error!
732 }
733 m_kwordDocument->m_styles.append( *m_currentLayout );
734 success = true;
735 }
736 delete m_currentLayout;
737 m_currentLayout = 0;
738 }
739 else if ( name == "DOC" )
740 {
741 success = true;
742 }
743 else
744 {
745 success = true; // No problem, so authorisation to continue parsing
746 }
747
748 if (!success)
749 {
750 // If we have no success, then it was surely a tag mismatch. Help debugging!
751 kdError(30506) << "Found closing tag name: " << name << " expected: " << stackItem->itemName << endl;
752 }
753
754 delete stackItem;
755
756 return success;
757}
758
759bool KWord13Parser :: characters ( const TQString & ch )
760{
761#if 0
762 // DEBUG start
763 if (ch=="\n")
764 {
765 kdDebug(30520) << indent << " (LINEFEED)" << endl;
766 }
767 else if (ch.length()> 40)
768 { // 40 characters are enough (especially for image data)
769 kdDebug(30520) << indent << " :" << ch.left(40) << "..." << endl;
770 }
771 else
772 {
773 kdDebug(30520) << indent << " :" << ch << ":" << endl;
774 }
775 // DEBUG end
776#endif
777
778 if (parserStack.isEmpty())
779 {
780 kdError(30520) << "Stack is empty!! Aborting! (in StructureParser::characters)" << endl;
781 return false;
782 }
783
784 bool success=false;
785
786 KWord13StackItem *stackItem = parserStack.current();
787
788 if ( stackItem->elementType == KWord13TypeText )
789 {
790 // <TEXT>
791 if ( m_currentParagraph )
792 {
793 bool found = false; // Some unexpected control character?
794 // ### TODO: this is perhaps a good point to check for non-XML characters
795 const uint length = ch.length();
796 for ( uint i = 0; i < length; ++i )
797 {
798 const ushort uni = ch.at(i).unicode();
799 if ( uni >= 32 )
800 continue; // Normal character
801 else if ( uni == 9 || uni == 10 || uni == 13)
802 continue; // Tabulator, Line Feed, Carriage Return
803 else if ( uni == 1 )
804 {
805 // Old KWord documents have a TQChar(1) as anchor character
806 // So replace it with the anchor character of recent KWord versions
807 ch[i]='#';
808 }
809 else
810 {
811 ch[i]='?';
812 found = true;
813 }
814 }
815 if ( found )
816 kdWarning(30520) << "Unexcepted control characters found in text!" << endl;
817 m_currentParagraph->appendText( ch );
818 success = true;
819 }
820 else
821 {
822 kdError(30520) << "No current paragraph defined! Tag mismatch?" << endl;
823 success = false;
824 }
825 }
826 else if (stackItem->elementType==KWord13TypeEmpty)
827 {
828 success=ch.stripWhiteSpace().isEmpty();
829 if (!success)
830 {
831 // We have a parsing error, so abort!
832 kdError(30520) << "Empty element "<< stackItem->itemName <<" is not empty! Aborting! (in KWordParser::characters)" << endl;
833 }
834 }
835 else
836 {
837 success=true;
838 }
839
840 return success;
841}
842
843bool KWord13Parser::warning(const TQXmlParseException& exception)
844{
845 kdWarning(30520) << "XML parsing warning: line " << exception.lineNumber()
846 << " col " << exception.columnNumber() << " message: " << exception.message() << endl;
847 return true;
848}
849
850bool KWord13Parser::error(const TQXmlParseException& exception)
851{
852 // A XML error is recoverable, so it is only a KDE warning
853 kdWarning(30520) << "XML parsing error: line " << exception.lineNumber()
854 << " col " << exception.columnNumber() << " message: " << exception.message() << endl;
855 return true;
856}
857
858bool KWord13Parser::fatalError (const TQXmlParseException& exception)
859{
860 kdError(30520) << "XML parsing fatal error: line " << exception.lineNumber()
861 << " col " << exception.columnNumber() << " message: " << exception.message() << endl;
862 // ### TODO: user message box
863 return false; // Stop parsing now, we do not need further errors.
864}
865
866TQString KWord13Parser::calculatePictureKey( const TQString& filename,
867 const TQString& year, const TQString& month, const TQString& day,
868 const TQString& hour, const TQString& minute, const TQString& second,
869 const TQString& microsecond ) const
870{
871 bool ok;
872 bool globalOk = true;
873
874 ok = false;
875 const int iYear = year.toInt( & ok );
876 globalOk = globalOk && ok;
877
878 ok = false;
879 const int iMonth = month.toInt( & ok );
880 globalOk = globalOk && ok;
881
882 ok = false;
883 const int iDay = day.toInt( & ok );
884 globalOk = globalOk && ok;
885
886 ok = false;
887 const int iHour = hour.toInt( & ok );
888 globalOk = globalOk && ok;
889
890 ok = false;
891 const int iMinute = minute.toInt( & ok );
892 globalOk = globalOk && ok;
893
894 ok = false;
895 const int iSecond = second.toInt( & ok );
896 globalOk = globalOk && ok;
897
898 ok = false;
899 const int iMicrosecond = microsecond.toInt( & ok );
900 globalOk = globalOk && ok;
901
902 if ( globalOk )
903 {
904 // No error until then, so check if the date/time is valid at all
905 globalOk = globalOk && TQDate::isValid( iYear, iMonth, iDay );
906 globalOk = globalOk && TQTime::isValid( iHour, iMinute, iSecond, iMicrosecond );
907 }
908
909 TQDateTime dt;
910 if ( globalOk )
911 {
912 // The date/time seems correct
913 dt = TQDateTime( TQDate( iYear, iMonth, iDay ), TQTime( iHour, iMinute, iSecond, iMicrosecond ) );
914 }
915 else
916 {
917 // *NIX epoch (We do not really care if it is UTC or local time)
918 dt = TQDateTime( TQDate( 1970, 1, 1 ), TQTime( 0, 0, 0, 0 ) );
919 }
920
921 // We put the date/time first, as if the date is useful, it will have faster a difference than a path
922 // where the common pth might be very long.
923
924 // Output the date/time as compact as possible
925 TQString result ( dt.toString( "yyyyMMddhhmmsszzz" ) );
926 result += '@'; // A separator
927 result += filename;
928 return result;
929}
format for variable
Contains the data of the <FORMAT id="1"> children also the grand-children of <STYLE> and <LAYOUT>
class for <FORMAT id="1">
int m_length
Length of format.
format for anchor
TQString m_anchorName
name of anchor
Basic classes for all format classes.
int m_id
Type of format.
Layout or style.