kword

KWTextParag.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001 David Faure <faure@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 "KWTextParag.h"
21#include "KWDocument.h"
22#include "KWAnchor.h"
23#include "KWTextImage.h"
24#include "KWTextFrameSet.h"
25#include "KWVariable.h"
26#include "KWLoadingInfo.h"
27
28#include <KoVariable.h>
29#include <KoParagCounter.h>
30#include <KoOasisContext.h>
31#include <KoXmlNS.h>
32#include <KoOasisStyles.h>
33
34#include <tdeglobalsettings.h>
35#include <tdelocale.h>
36#include <kdebug.h>
37#include <assert.h>
38
39//#define DEBUG_FORMATTING
40#undef S_NONE // Solaris defines it in sys/signal.h
41
42// Called by KoTextParag::drawParagString - all params are in pixel coordinates
43void KWTextParag::drawFormattingChars( TQPainter &painter, int start, int len,
44 int lastY_pix, int baseLine_pix, int h_pix, // in pixels
45 bool drawSelections,
46 KoTextFormat *lastFormat, const TQMemArray<int> &selectionStarts,
47 const TQMemArray<int> &selectionEnds, const TQColorGroup &cg,
48 bool rightToLeft, int line, KoTextZoomHandler* zh,
49 int whichFormattingChars )
50{
51 KWTextFrameSet * textfs = kwTextDocument()->textFrameSet();
52 if ( !textfs )
53 return;
54 KWDocument * doc = textfs->kWordDocument();
55 if ( !doc || !doc->viewFormattingChars() )
56 return;
57 // We set whichFormattingChars before calling KoTextFormat::drawFormattingChars
58 whichFormattingChars = 0;
59 if ( doc->viewFormattingSpace() )
60 whichFormattingChars |= FormattingSpace;
61 if ( doc->viewFormattingBreak() )
62 whichFormattingChars |= FormattingBreak;
63 if ( doc->viewFormattingEndParag() )
64 whichFormattingChars |= FormattingEndParag;
65 if ( doc->viewFormattingTabs() )
66 whichFormattingChars |= FormattingTabs;
67
68 if ( !whichFormattingChars )
69 return;
70 if ( start + len == length() && (whichFormattingChars & FormattingBreak) && hardFrameBreakAfter() )
71 {
72 painter.save();
73 TQPen pen( TDEGlobalSettings::linkColor() ); // #101820
74 painter.setPen( pen );
75 //kdDebug() << "KWTextParag::drawFormattingChars start=" << start << " len=" << len << " length=" << length() << endl;
76 // keep in sync with KWTextFrameSet::formatVertically
77 TQString str = i18n( "--- Frame Break ---" );
78 int width = 0;
79 //width = lastFormat->screenStringWidth( zh, str );
80 width = lastFormat->screenFontMetrics( zh ).width( str );
81 TQColorGroup cg2( cg );
82 //cg2.setColor( TQColorGroup::Base, TQt::green ); // for debug
83 int last = length() - 1;
84 KoTextStringChar &ch = string()->at( last );
85 int x = zh->layoutUnitToPixelX( ch.x );// + ch.pixelxadj;
86
87 KoTextFormat format( *lastFormat );
88 format.setColor( pen.color() ); // ### A bit slow, maybe pass the color to drawParagStringInternal ?
89 KoTextParag::drawParagStringInternal(
90 painter, str, 0, str.length(),
91 x, lastY_pix, // startX and lastY
92 zh->layoutUnitToPixelY( ch.ascent() ), // baseline
93 width, zh->layoutUnitToPixelY( ch.height() ), // bw and h
94 drawSelections, &format, selectionStarts,
95 selectionEnds, cg2, rightToLeft, line, zh, false );
96 // Clear 'paint end of line' flag, we don't want it overwriting the above
97 whichFormattingChars &= ~FormattingEndParag;
98 painter.restore();
99 }
100
101 KoTextParag::drawFormattingChars( painter, start, len,
102 lastY_pix, baseLine_pix, h_pix,
103 drawSelections,
104 lastFormat, selectionStarts,
105 selectionEnds, cg, rightToLeft,
106 line, zh, whichFormattingChars );
107}
108
110{
111 m_layout.pageBreaking = pb;
112 invalidate(0);
113 if ( next() && ( pb & KoParagLayout::HardFrameBreakAfter ) )
114 next()->invalidate(0);
115}
116
117KWTextDocument * KWTextParag::kwTextDocument() const
118{
119 return static_cast<KWTextDocument *>( document() );
120}
121
122//static
123TQDomElement KWTextParag::saveFormat( TQDomDocument & doc, KoTextFormat * curFormat, KoTextFormat * refFormat, int pos, int len )
124{
125 //kdDebug() << "KWTextParag::saveFormat refFormat=" << ( refFormat ? refFormat->key() : "none" )
126 // << " curFormat=" << curFormat->key()
127 // << " pos=" << pos << " len=" << len << endl;
128 TQDomElement formatElem = doc.createElement( "FORMAT" );
129 formatElem.setAttribute( "id", 1 ); // text format
130 if ( len ) // 0 when saving the format of a style
131 {
132 formatElem.setAttribute( "pos", pos );
133 formatElem.setAttribute( "len", len );
134 }
135 TQDomElement elem;
136 if( !refFormat || curFormat->font().weight() != refFormat->font().weight() )
137 {
138 elem = doc.createElement( "WEIGHT" );
139 formatElem.appendChild( elem );
140 elem.setAttribute( "value", curFormat->font().weight() );
141 }
142 if( !refFormat || curFormat->color() != refFormat->color() )
143 {
144 if ( curFormat->color().isValid() )
145 {
146 elem = doc.createElement( "COLOR" );
147 formatElem.appendChild( elem );
148 elem.setAttribute( "red", curFormat->color().red() );
149 elem.setAttribute( "green", curFormat->color().green() );
150 elem.setAttribute( "blue", curFormat->color().blue() );
151 }
152 else
153 {
154 if ( refFormat )
155 {
156 elem = doc.createElement( "COLOR" );
157 formatElem.appendChild( elem );
158 elem.setAttribute( "red", -1 );
159 elem.setAttribute( "green", -1 );
160 elem.setAttribute( "blue", -1 );
161 }
162 }
163 }
164 if( !refFormat || curFormat->font().family() != refFormat->font().family() )
165 {
166 elem = doc.createElement( "FONT" );
167 formatElem.appendChild( elem );
168 elem.setAttribute( "name", curFormat->font().family() );
169 }
170 if( !refFormat || curFormat->pointSize() != refFormat->pointSize() )
171 {
172 elem = doc.createElement( "SIZE" );
173 formatElem.appendChild( elem );
174 elem.setAttribute( "value", curFormat->pointSize() );
175 }
176 if( !refFormat || curFormat->font().italic() != refFormat->font().italic() )
177 {
178 elem = doc.createElement( "ITALIC" );
179 formatElem.appendChild( elem );
180 elem.setAttribute( "value", static_cast<int>(curFormat->font().italic()) );
181 }
182 if( !refFormat
183 || curFormat->underlineType() != refFormat->underlineType()
184 || curFormat->textUnderlineColor() !=refFormat->textUnderlineColor()
185 || curFormat->underlineStyle() !=refFormat->underlineStyle()
186 || curFormat->wordByWord() != refFormat->wordByWord())
187 {
188 elem = doc.createElement( "UNDERLINE" );
189 formatElem.appendChild( elem );
190 if ( curFormat->doubleUnderline() )
191 elem.setAttribute( "value", "double" );
192 else if ( curFormat->underlineType() == KoTextFormat::U_SIMPLE_BOLD)
193 elem.setAttribute( "value", "single-bold" );
194 else if( curFormat->underlineType()==KoTextFormat::U_WAVE)
195 elem.setAttribute( "value", "wave" );
196 else
197 elem.setAttribute( "value", static_cast<int>(curFormat->underline()) );
198 TQString strLineType=KoTextFormat::underlineStyleToString( curFormat->underlineStyle() );
199 elem.setAttribute( "styleline", strLineType );
200 if ( curFormat->textUnderlineColor().isValid() )
201 elem.setAttribute( "underlinecolor", curFormat->textUnderlineColor().name() );
202
203 elem.setAttribute( "wordbyword" , static_cast<int>(curFormat->wordByWord()));
204 }
205 if( !refFormat
206 || curFormat->strikeOutType() != refFormat->strikeOutType()
207 || curFormat->strikeOutStyle()!= refFormat->strikeOutStyle()
208 || curFormat->wordByWord() != refFormat->wordByWord())
209 {
210 elem = doc.createElement( "STRIKEOUT" );
211 formatElem.appendChild( elem );
212 if ( curFormat->doubleStrikeOut() )
213 elem.setAttribute( "value", "double" );
214 else if ( curFormat->strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)
215 elem.setAttribute( "value", "single-bold" );
216 else
217 elem.setAttribute( "value", static_cast<int>(curFormat->strikeOut()) );
218 TQString strLineType=KoTextFormat::strikeOutStyleToString( curFormat->strikeOutStyle() );
219 elem.setAttribute( "styleline", strLineType );
220 elem.setAttribute( "wordbyword" , static_cast<int>(curFormat->wordByWord()));
221 }
222 if( !refFormat || (curFormat->vAlign() != refFormat->vAlign())
223 || (curFormat->relativeTextSize() != refFormat->relativeTextSize()))
224 {
225 elem = doc.createElement( "VERTALIGN" );
226 formatElem.appendChild( elem );
227 elem.setAttribute( "value", static_cast<int>(curFormat->vAlign()) );
228 if ( curFormat->relativeTextSize()!=0.66)
229 elem.setAttribute( "relativetextsize", curFormat->relativeTextSize() );
230 }
231 if( !refFormat || curFormat->textBackgroundColor() != refFormat->textBackgroundColor() )
232 {
233 if ( curFormat->textBackgroundColor().isValid())
234 {
235 elem = doc.createElement( "TEXTBACKGROUNDCOLOR" );
236 formatElem.appendChild( elem );
237 elem.setAttribute( "red", curFormat->textBackgroundColor().red() );
238 elem.setAttribute( "green", curFormat->textBackgroundColor().green() );
239 elem.setAttribute( "blue", curFormat->textBackgroundColor().blue() );
240 }
241 else
242 {
243 if ( refFormat )
244 {
245 elem = doc.createElement( "TEXTBACKGROUNDCOLOR" );
246 formatElem.appendChild( elem );
247 elem.setAttribute( "red", -1 );
248 elem.setAttribute( "green", -1 );
249 elem.setAttribute( "blue", -1 );
250 }
251 }
252 }
253 if( !refFormat ||
254 ( curFormat->shadowDistanceX() != refFormat->shadowDistanceX()
255 || ( curFormat->shadowDistanceY() != refFormat->shadowDistanceY() )
256 || ( curFormat->shadowColor() != refFormat->shadowColor() ) ) )
257 {
258 elem = doc.createElement( "SHADOW" );
259 formatElem.appendChild( elem );
260 elem.setAttribute( "text-shadow", curFormat->shadowAsCss() );
261 }
262 if( !refFormat || curFormat->offsetFromBaseLine() != refFormat->offsetFromBaseLine())
263 {
264 elem = doc.createElement( "OFFSETFROMBASELINE" );
265 formatElem.appendChild( elem );
266 elem.setAttribute( "value", curFormat->offsetFromBaseLine() );
267 }
268 if( !refFormat || curFormat->attributeFont() != refFormat->attributeFont())
269 {
270 elem = doc.createElement( "FONTATTRIBUTE" );
271 formatElem.appendChild( elem );
272 elem.setAttribute( "value", KoTextFormat::attributeFontToString(curFormat->attributeFont()) );
273 }
274 if( !refFormat || curFormat->language() != refFormat->language())
275 {
276 elem = doc.createElement( "LANGUAGE" );
277 formatElem.appendChild( elem );
278 elem.setAttribute( "value", curFormat->language() );
279 }
280 return formatElem;
281}
282
283void KWTextParag::save( TQDomElement &parentElem, bool saveAnchorsFramesets )
284{
285 // The TQMAX below ensures that although we don't save the trailing space
286 // in the normal case, we do save it for empty paragraphs (#30336)
287 save( parentElem, 0, TQMAX( 0, length()-2 ), saveAnchorsFramesets );
288}
289
290void KWTextParag::save( TQDomElement &parentElem, int from /* default 0 */,
291 int to /* default length()-2 */,
292 bool saveAnchorsFramesets /* default false */ )
293{
294 TQDomDocument doc = parentElem.ownerDocument();
295 TQDomElement paragElem = doc.createElement( "PARAGRAPH" );
296 parentElem.appendChild( paragElem );
297 TQDomElement textElem = doc.createElement( "TEXT" );
298 textElem.setAttribute("xml:space", "preserve");
299 paragElem.appendChild( textElem );
300 if ( partOfTableOfContents() )
301 paragElem.setAttribute( "toc", "true" );
302 TQString text = string()->toString();
303 Q_ASSERT( text.right(1)[0] == ' ' );
304 textElem.appendChild( doc.createTextNode( text.mid( from, to - from + 1 ) ) );
305
306 TQDomElement formatsElem = doc.createElement( "FORMATS" );
307 int startPos = -1;
308 int index = 0; // Usually same as 'i' but if from>0, 'i' indexes the parag's text and this one indexes the output
309 KoTextFormat *curFormat = paragraphFormat();
310 for ( int i = from; i <= to; ++i, ++index )
311 {
312 KoTextStringChar & ch = string()->at(i);
313 KoTextFormat * newFormat = static_cast<KoTextFormat *>( ch.format() );
314 if ( ch.isCustom() )
315 {
316 if ( startPos > -1 && curFormat) { // Save former format
317 TQDomElement formatElem = saveFormat( doc, curFormat,
318 paragraphFormat(), startPos, index-startPos );
319 if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
320 formatsElem.appendChild( formatElem );
321 }
322
323 TQDomElement formatElem = saveFormat( doc, newFormat, paragraphFormat(), index, 1 );
324 formatsElem.appendChild( formatElem );
325 KoTextCustomItem* customItem = ch.customItem();
326 formatElem.setAttribute( "id", customItem->typeId() );
327 customItem->save( formatElem );
328 startPos = -1;
329 curFormat = paragraphFormat();
330 // Save the contents of the frameset inside the anchor
331 // This is NOT used when saving, but it is used when copying an inline frame
332 if ( saveAnchorsFramesets )
333 {
334 KWFrameSet* inlineFs = 0L;
335 if ( dynamic_cast<KWAnchor *>( customItem ) )
336 inlineFs = static_cast<KWAnchor *>( customItem )->frameSet();
337 else if ( dynamic_cast<KWFootNoteVariable *>( customItem ) )
338 inlineFs = static_cast<KWFootNoteVariable *>( customItem )->frameSet();
339
340 if ( inlineFs )
341 {
342 // Save inline framesets at the toplevel. Necessary when copying a textframeset that
343 // itself includes an inline frameset - we want all frameset tags at the toplevel.
344 TQDomElement elem = doc.documentElement();
345 kdDebug() << " saving into " << elem.tagName() << endl;
346 inlineFs->toXML( elem );
347 }
348 }
349 }
350 else
351 {
352 if ( newFormat != curFormat )
353 {
354 // Format changed.
355 if ( startPos > -1 && curFormat) { // Save former format
356 TQDomElement formatElem = saveFormat( doc, curFormat, paragraphFormat(), startPos, index-startPos );
357 if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
358 formatsElem.appendChild( formatElem );
359 }
360
361 // Format different from paragraph's format ?
362 if( newFormat != paragFormat() )
363 {
364 startPos = index;
365 curFormat = newFormat;
366 }
367 else
368 {
369 startPos = -1;
370 curFormat = paragraphFormat();
371 }
372 }
373 }
374 }
375 if ( startPos > -1 && index > startPos && curFormat) { // Save last format
376 TQDomElement formatElem = saveFormat( doc, curFormat, paragraphFormat(), startPos, index-startPos );
377 if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
378 formatsElem.appendChild( formatElem );
379 }
380
381 if (!formatsElem.firstChild().isNull()) // Do we have formats to save ?
382 paragElem.appendChild( formatsElem );
383
384
385 TQDomElement layoutElem = doc.createElement( "LAYOUT" );
386 paragElem.appendChild( layoutElem );
387
388 // save with the real alignment (left or right, not auto)
389 m_layout.saveParagLayout( layoutElem, resolveAlignment() );
390
391 // Paragraph's format
392 // ## Maybe we should have a "default format" somewhere and
393 // pass it instead of 0L, to only save the non-default attributes
394 // But this would break all export filters again.
395 TQDomElement paragFormatElement = saveFormat( doc, paragraphFormat(), 0L, 0, to - from + 1 );
396 layoutElem.appendChild( paragFormatElement );
397}
398
399//static
400KoTextFormat KWTextParag::loadFormat( TQDomElement &formatElem, KoTextFormat * refFormat, const TQFont & defaultFont, const TQString & defaultLanguage, bool hyphanation )
401{
402 KoTextFormat format;
403 //todo fixme !!!!!!!!!!!!
404 format.setHyphenation( hyphanation );
405 TQFont font;
406 if ( refFormat )
407 {
408 format = *refFormat;
409 format.setCollection( 0 ); // Out of collection copy
410 font = format.font();
411 }
412 else
413 {
414 font = defaultFont;
415 }
416
417 TQDomElement elem;
418 elem = formatElem.namedItem( "FONT" ).toElement();
419 if ( !elem.isNull() )
420 {
421 font.setFamily( elem.attribute("name") );
422 }
423 else if ( !refFormat )
424 { // No reference format and no FONT tag -> use default font
425 font = defaultFont;
426 }
427 elem = formatElem.namedItem( "WEIGHT" ).toElement();
428 if ( !elem.isNull() )
429 font.setWeight( elem.attribute( "value" ).toInt() );
430 elem = formatElem.namedItem( "SIZE" ).toElement();
431 if ( !elem.isNull() )
432 font.setPointSize( elem.attribute("value").toInt() );
433 elem = formatElem.namedItem( "ITALIC" ).toElement();
434 if ( !elem.isNull() )
435 font.setItalic( elem.attribute("value").toInt() == 1 );
436 elem = formatElem.namedItem( "UNDERLINE" ).toElement();
437 if ( !elem.isNull() ) {
438 TQString value = elem.attribute("value");
439 if ( value == "0" || value == "1" )
440 format.setUnderlineType( (value.toInt() == 1)?KoTextFormat::U_SIMPLE: KoTextFormat::U_NONE );
441 else if ( value == "single" ) // value never used when saving, but why not support it? ;)
442 format.setUnderlineType ( KoTextFormat::U_SIMPLE);
443 else if ( value == "double" )
444 format.setUnderlineType ( KoTextFormat::U_DOUBLE);
445 else if ( value == "single-bold" )
446 format.setUnderlineType ( KoTextFormat::U_SIMPLE_BOLD);
447 else if( value =="wave")
448 format.setUnderlineType ( KoTextFormat::U_WAVE);
449 if ( elem.hasAttribute("styleline" ))
450 {
451 TQString strLineType = elem.attribute("styleline");
452 format.setUnderlineStyle( KoTextFormat::stringToUnderlineStyle( strLineType ));
453 }
454 if ( elem.hasAttribute("underlinecolor"))
455 {
456 TQColor col( TQColor(elem.attribute("underlinecolor")));
457 format.setTextUnderlineColor( col );
458 }
459 if ( elem.hasAttribute( "wordbyword" ))
460 format.setWordByWord( elem.attribute("wordbyword").toInt()==1);
461 }
462 elem = formatElem.namedItem( "STRIKEOUT" ).toElement();
463 if ( !elem.isNull() )
464 {
465 TQString value = elem.attribute("value");
466 if ( value == "0" || value == "1" )
467 format.setStrikeOutType( (value.toInt() == 1)?KoTextFormat::S_SIMPLE: KoTextFormat::S_NONE );
468 else if ( value == "single" ) // value never used when saving, but why not support it? ;)
469 format.setStrikeOutType ( KoTextFormat::S_SIMPLE);
470 else if ( value == "double" )
471 format.setStrikeOutType ( KoTextFormat::S_DOUBLE);
472 else if ( value =="single-bold" )
473 format.setStrikeOutType ( KoTextFormat::S_SIMPLE_BOLD);
474
475 if ( elem.hasAttribute("styleline" ))
476 {
477 TQString strLineType = elem.attribute("styleline");
478 format.setStrikeOutStyle( KoTextFormat::stringToStrikeOutStyle( strLineType ));
479 }
480 if ( elem.hasAttribute( "wordbyword" ))
481 format.setWordByWord( elem.attribute("wordbyword").toInt()==1);
482 }
483 // ######## Not needed in 3.0?
484 /*
485 elem = formatElem.namedItem( "CHARSET" ).toElement();
486 if ( !elem.isNull() )
487 font.setCharSet( (TQFont::CharSet) elem.attribute("value").toInt() );
488 */
489 format.setFont( font );
490
491 elem = formatElem.namedItem( "VERTALIGN" ).toElement();
492 if ( !elem.isNull() )
493 {
494 format.setVAlign( static_cast<KoTextFormat::VerticalAlignment>( elem.attribute("value").toInt() ) );
495 if (elem.hasAttribute("relativetextsize"))
496 format.setRelativeTextSize(elem.attribute("relativetextsize").toDouble());
497 }
498 elem = formatElem.namedItem( "COLOR" ).toElement();
499 if ( !elem.isNull() )
500 {
501 int red = elem.attribute("red").toInt();
502 int green = elem.attribute("green").toInt();
503 int blue = elem.attribute("blue").toInt();
504 if ( red == -1 && blue == -1 && green == -1 )
505 format.setColor( TQColor() );
506 else
507 format.setColor( TQColor(red,green,blue) );
508 }
509 elem = formatElem.namedItem( "TEXTBACKGROUNDCOLOR" ).toElement();
510 if ( !elem.isNull() )
511 {
512 int red = elem.attribute("red").toInt();
513 int green = elem.attribute("green").toInt();
514 int blue = elem.attribute("blue").toInt();
515 if ( red == -1 && blue == -1 && green == -1 )
516 format.setTextBackgroundColor( TQColor() );
517 else
518 format.setTextBackgroundColor( TQColor(red,green,blue) );
519 }
520 elem = formatElem.namedItem( "SHADOW" ).toElement();
521 if ( !elem.isNull() )
522 {
523 format.parseShadowFromCss( elem.attribute( "text-shadow" ) );
524 } else {
525 // Compat with koffice-1.2
526 elem = formatElem.namedItem( "SHADOWTEXT" ).toElement();
527 if ( !elem.isNull() && elem.attribute("value").toInt() && KoParagLayout::shadowCssCompat )
528 {
529 // Retrieve shadow attributes from KoParagLayout
530 // We don't have its pointer, so shadowCssCompat is static.
531 format.parseShadowFromCss( *KoParagLayout::shadowCssCompat );
532 }
533 }
534
535 elem = formatElem.namedItem( "OFFSETFROMBASELINE" ).toElement();
536 if ( !elem.isNull() )
537 format.setOffsetFromBaseLine( elem.attribute("value").toInt());
538
539 elem = formatElem.namedItem( "FONTATTRIBUTE" ).toElement();
540 if ( !elem.isNull() )
541 format.setAttributeFont( KoTextFormat::stringToAttributeFont(elem.attribute("value")));
542
543 elem = formatElem.namedItem( "LANGUAGE" ).toElement();
544 if ( !elem.isNull() )
545 format.setLanguage( elem.attribute("value") );
546 else if ( !refFormat )// No reference format and no LANGUAGE tag -> use default font
547 format.setLanguage( defaultLanguage );
548
549 //kdDebug() << "KWTextParag::loadFormat format=" << format.key() << endl;
550 return format;
551}
552
553void KWTextParag::loadLayout( TQDomElement & attributes )
554{
555 TQDomElement layout = attributes.namedItem( "LAYOUT" ).toElement();
556 if ( !layout.isNull() )
557 {
558 KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
559 KoParagLayout paragLayout = loadParagLayout( layout, doc, true );
560 setParagLayout( paragLayout );
561
562 // Load default format from style.
563 KoTextFormat *defaultFormat = style() ? &style()->format() : 0L;
564 TQDomElement formatElem = layout.namedItem( "FORMAT" ).toElement();
565 if ( !formatElem.isNull() )
566 {
567 // Load paragraph format
568 KoTextFormat f = loadFormat( formatElem, defaultFormat, doc->defaultFont(), doc->globalLanguage(), doc->globalHyphenation() );
569 setFormat( document()->formatCollection()->format( &f ) );
570 }
571 else // No paragraph format
572 {
573 if ( defaultFormat ) // -> use the one from the style
574 setFormat( document()->formatCollection()->format( defaultFormat ) );
575 }
576 }
577 else
578 {
579 // Even the simplest import filter should do <LAYOUT><NAME value="Standard"/></LAYOUT>
580 kdWarning(32001) << "No LAYOUT tag in PARAGRAPH, dunno what layout to apply" << endl;
581 }
582}
583
584void KWTextParag::load( TQDomElement &attributes )
585{
586 loadLayout( attributes );
587
588 // Set the text after setting the paragraph format - so that the format applies
589 TQDomElement element = attributes.namedItem( "TEXT" ).toElement();
590 if ( !element.isNull() )
591 {
592 //kdDebug() << "KWTextParag::load '" << element.text() << "'" << endl;
593 append( element.text() );
594 // Apply default format - this should be automatic !!
595 setFormat( 0, string()->length(), paragFormat(), true );
596 }
597
598 if ( attributes.attribute( "toc" ) == "true" )
599 setPartOfTableOfContents( true );
600
601 loadFormatting( attributes );
602
603 setChanged( true );
604 invalidate( 0 );
605}
606
607void KWTextParag::loadFormatting( TQDomElement &attributes, int offset, bool loadFootNote )
608{
609
610 TQValueList<int> removeLenList;
611 TQValueList<int> removePosList;
612
613 KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
614 TQDomElement formatsElem = attributes.namedItem( "FORMATS" ).toElement();
615 if ( !formatsElem.isNull() )
616 {
617 TQDomElement formatElem = formatsElem.firstChild().toElement();
618 for ( ; !formatElem.isNull() ; formatElem = formatElem.nextSibling().toElement() )
619 {
620 if ( formatElem.tagName() == "FORMAT" )
621 {
622 int index = formatElem.attribute( "pos" ).toInt() + offset;
623 int len = formatElem.attribute( "len" ).toInt();
624
625 int id = formatElem.attribute( "id" ).toInt();
626 switch( id ) {
627 case 1: // Normal text
628 {
629 KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
630 //kdDebug(32002) << "KWTextParag::loadFormatting applying formatting from " << index << " to " << index+len << endl;
631 setFormat( index, len, document()->formatCollection()->format( &f ) );
632 break;
633 }
634 case 2: // Picture
635 {
636 len = 1; // it was missing from old 1.0 files
637
638 // The character matching this format is probably a TQChar(1)
639 // However, as it is an invalid XML character, we must replace it
640 // or it will be written out while save the file.
641 KoTextStringChar& ch = string()->at(index);
642 if (ch.c.unicode()==1)
643 {
644 kdDebug() << "Replacing TQChar(1) (in KWTextParag::loadFormatting)" << endl;
645 ch.c='#';
646 }
647
648 KWTextImage * custom = new KWTextImage( kwTextDocument(), TQString() );
649 kdDebug() << "KWTextParag::loadFormatting insertCustomItem" << endl;
650 paragFormat()->addRef();
651 setCustomItem( index, custom, paragFormat() );
652 custom->load( formatElem );
653 break;
654 }
655 case 3: // Tabulator
656 {
657 len = 1; // it was missing from old 1.0 files
658
659 // We have to replace the # or TQChar(1) by a tabulator
660 KoTextStringChar& ch = string()->at(index);
661 ch.c='\t';
662
663 // I assume that we need the same treatment as for id == 1
664 KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
665 //kdDebug(32002) << "KWTextParag::loadFormatting applying formatting from " << index << " to " << index+len << endl;
666 setFormat( index, len, document()->formatCollection()->format( &f ) );
667 break;
668 }
669 case 4: // Variable
670 {
671 TQDomElement varElem = formatElem.namedItem( "VARIABLE" ).toElement();
672 bool oldDoc = false;
673 if ( varElem.isNull() )
674 {
675 // Not found, must be an old document -> the tags were directly
676 // under the FORMAT tag.
677 varElem = formatElem;
678 oldDoc = true;
679 }
680 TQDomElement typeElem = varElem.namedItem( "TYPE" ).toElement();
681 if ( typeElem.isNull() )
682 kdWarning(32001) <<
683 ( oldDoc ? "No <TYPE> in <FORMAT> with id=4, for a variable [old document assumed] !"
684 : "No <TYPE> found in <VARIABLE> tag!" ) << endl;
685 else
686 {
687 int type = typeElem.attribute( "type" ).toInt();
688 TQString key = typeElem.attribute( "key" );
689 kdDebug() << "KWTextParag::loadFormatting variable type=" << type << " key=" << key << endl;
690 KoVariableFormat * varFormat = key.isEmpty() ? 0 : doc->variableFormatCollection()->format( key.latin1() );
691 // If varFormat is 0 (no key specified), the default format will be used.
692 int correct = 0;
693 if (typeElem.hasAttribute( "correct" ))
694 correct = typeElem.attribute("correct").toInt();
695 KoVariable * var =doc->variableCollection()->createVariable( type, -1, doc->variableFormatCollection(), varFormat,kwTextDocument(),doc, correct, true , loadFootNote);
696 if ( var )
697 {
698 var->load( varElem );
699 KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
700 setCustomItem( index, var, document()->formatCollection()->format( &f ) );
701 }
702 if(len>1) {
703 removePosList.append(index+1);
704 removeLenList.append(len-1);
705 }
706 }
707 break;
708 }
709 case 6: // Anchor
710 {
711 Q_ASSERT( len == 1 );
712 TQDomElement anchorElem = formatElem.namedItem( "ANCHOR" ).toElement();
713 if ( !anchorElem.isNull() ) {
714 TQString type = anchorElem.attribute( "type" );
715 if ( type == "grpMgr" /* old syntax */ || type == "frameset" )
716 {
717 TQString framesetName = anchorElem.attribute( "instance" );
719 pos.textfs = kwTextDocument()->textFrameSet();
720 pos.paragId = paragId();
721 pos.index = index;
722 doc->addAnchorRequest( framesetName, pos );
723 }
724 else
725 kdWarning() << "Anchor type not supported: " << type << endl;
726 }
727 else
728 kdWarning() << "Missing ANCHOR tag" << endl;
729 break;
730 }
731 default:
732 kdWarning() << "KWTextParag::loadFormatting id=" << id << " not supported" << endl;
733 break;
734 }
735 }
736 }
737 }
738 for(unsigned int i=0; i < removeLenList.count(); i++) {
739 remove(*removePosList.at(i), *removeLenList.at(i));
740 }
741}
742
743void KWTextParag::setParagLayout( const KoParagLayout & layout, int flags, int marginIndex )
744{
745 KoTextParag::setParagLayout( layout, flags, marginIndex );
746
747 if ( flags & KoParagLayout::PageBreaking )
748 setPageBreaking( layout.pageBreaking );
749}
750
752
753// Create a KoParagLayout from XML.
754KoParagLayout KWTextParag::loadParagLayout( TQDomElement & parentElem, KWDocument *doc, bool findStyle )
755{
756 KoParagLayout layout;
757
758 // Only when loading paragraphs, not when loading styles
759 if ( findStyle )
760 {
761 KoParagStyle *style;
762 // Name of the style. If there is no style, then we do not supply
763 // any default!
764 TQDomElement element = parentElem.namedItem( "NAME" ).toElement();
765 if ( !element.isNull() )
766 {
767 TQString styleName = element.attribute( "value" );
768 style = doc->styleCollection()->findStyle( styleName );
769 if (!style)
770 {
771 kdError(32001) << "Cannot find style \"" << styleName << "\" specified in paragraph LAYOUT - using Standard" << endl;
772 style = doc->styleCollection()->findStyle( "Standard" );
773 }
774 //else kdDebug() << "KoParagLayout::KoParagLayout setting style to " << style << " " << style->name() << endl;
775 }
776 else
777 {
778 kdError(32001) << "Missing NAME tag in paragraph LAYOUT - using Standard" << endl;
779 style = doc->styleCollection()->findStyle( "Standard" );
780 }
781 Q_ASSERT(style);
782 layout.style = style;
783 }
784
785 KoParagLayout::loadParagLayout( layout, parentElem, doc->syntaxVersion() );
786
787 return layout;
788}
789
790void KWTextParag::join( KoTextParag *parag )
791{
792 m_layout.pageBreaking &= ~(KoParagLayout::HardFrameBreakBefore|KoParagLayout::HardFrameBreakAfter);
793 KoTextParag::join( parag );
794}
795
796void KWTextParag::loadOasis( const TQDomElement& paragElement, KoOasisContext& context, KoStyleCollection *styleCollection, uint& pos )
797{
798 KoTextParag::loadOasis( paragElement, context, styleCollection, pos );
799
800 KWTextFrameSet* textfs = kwTextDocument()->textFrameSet();
801 if ( textfs->isMainFrameset() && textfs->kWordDocument()->isLoading() /*not during copy/paste*/ )
802 {
803 KWDocument * doc = textfs->kWordDocument();
804 TQString& currentMasterPageRef = doc->loadingInfo()->m_currentMasterPage;
805 const TQString styleName = paragElement.attributeNS( KoXmlNS::text, "style-name", TQString() );
806 if ( !styleName.isEmpty() )
807 {
808 const TQDomElement* paragraphStyle = context.oasisStyles().findStyle( styleName, "paragraph" );
809 TQString masterPageName = paragraphStyle ? paragraphStyle->attributeNS( KoXmlNS::style, "master-page-name", TQString() ) : TQString();
810
811 // In KWord we don't support sections so the first paragraph is the one that determines the page layout.
812 if ( prev() == 0 ) {
813 if ( masterPageName.isEmpty() )
814 masterPageName = "Standard"; // Seems to be a builtin name for the default layout...
815 currentMasterPageRef = masterPageName; // do this first to avoid recursion
816 context.styleStack().save();
817 context.styleStack().setTypeProperties( "paragraph" );
818 context.addStyles( paragraphStyle, "paragraph" );
819 // This is quite ugly... OOo stores the starting page-number in the first paragraph style...
820 TQString pageNumber = context.styleStack().attributeNS( KoXmlNS::style, "page-number" );
821 if ( !pageNumber.isEmpty() )
822 doc->variableCollection()->variableSetting()->setStartingPageNumber( pageNumber.toInt() );
823 context.styleStack().restore();
824
825 doc->loadOasisPageLayout( masterPageName, context ); // page layout
826 }
827 else if ( !masterPageName.isEmpty() // empty means no change
828 && masterPageName != currentMasterPageRef )
829 {
830 // Detected a change in the master page -> this means we have to use a new page layout
831 // and insert a frame break if not on the first paragraph.
832 kdDebug(32001) << "KWTextParag::loadOasis: change of master page detected: from " << currentMasterPageRef << " to " << masterPageName << " -> inserting page break" << endl;
833 currentMasterPageRef = masterPageName;
834 // [see also KoParagLayout for the 'normal' way to insert page breaks]
835 m_layout.pageBreaking |= KoParagLayout::HardFrameBreakBefore;
836 // We have no way to load/use the new page layout, KWord doesn't have "sections".
837 }
838 }
839 }
840}
841
842void KWTextParag::saveOasis( KoXmlWriter& writer, KoSavingContext& context,
843 int from, int to, bool saveAnchorsFramesets ) const
844{
845 // Special case for inline tables that are alone in their paragraph:
846 // save <table> instead of <p>.
847 if ( string()->length() == 2 /*&& saveAnchorsFramesets*/ ) {
848 KoTextStringChar &ch = string()->at( 0 );
849 if ( ch.isCustom() && dynamic_cast<KWAnchor*>( ch.customItem() )) {
850 KWFrameSet* fs = static_cast<KWAnchor *>( ch.customItem() )->frameSet();
851 if ( fs->type() == FT_TABLE ) {
852 // TODO maybe save parag style? extract a common method out of KoTextStringChar::saveOasis
853 fs->saveOasis( writer, context, true );
854 return;
855 }
856 }
857 }
858 KoTextParag::saveOasis( writer, context, from, to, saveAnchorsFramesets );
859}
An anchor is a special character, or 'custom item'.
Definition KWAnchor.h:35
The variable showing the footnote number in superscript, in the text.
Definition KWVariable.h:106
Class: KWFrameSet Base type, a frameset holds content as well as frames to show that content.
Definition KWFrameSet.h:62
virtual FrameSetType type() const
The type of frameset.
Definition KWFrameSet.h:76
virtual TQDomElement toXML(TQDomElement &parentElem, bool saveFrames=true)
save to XML - when copying to clipboard
Definition KWFrameSet.h:320
virtual void saveOasis(KoXmlWriter &writer, KoSavingContext &context, bool saveFrames) const =0
Save to OASIS format.
TQString m_currentMasterPage
Current master-page name (OASIS loading).
This is our KoTextDocument reimplementation, to create KWTextParag instead of KoTextParags,...
This class is used by "Insert Picture", i.e.
Definition KWTextImage.h:34
void load(TQDomElement &attributes)
Load (from KWord-1.3 XML) the paragraph.
static KoTextFormat loadFormat(TQDomElement &formatElem, KoTextFormat *refFormat, const TQFont &defaultFont, const TQString &defaultLanguage, bool hyphanation)
Public for loading a style (KWord-1.3 XML).
static KoParagLayout loadParagLayout(TQDomElement &parentElem, KWDocument *doc, bool useRefStyle)
Load (from KWord-1.3 XML), optionally using styles from document.
static TQDomElement saveFormat(TQDomDocument &doc, KoTextFormat *curFormat, KoTextFormat *refFormat, int pos, int len)
Public for saving a style (KWord-1.3 XML).
void save(TQDomElement &parentElem, bool saveAnchorsFramesets=false)
Save (to KWord-1.3 XML) the whole paragraph.
void loadLayout(TQDomElement &attributes)
Load (from KWord-1.3 XML) and apply paragraph layout.
void setPageBreaking(int pb)
The type of page-breaking behaviour.
void loadFormatting(TQDomElement &attributes, int offset=0, bool loadFootNote=true)
Load (from KWord-1.3 XML) and apply <FORMAT> tags (used by KWTextParag::load and by KWPasteCommand).
Definition of an anchor's position:
Definition KWAnchorPos.h:32