kword

KWTextParag.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "KWTextParag.h"
00021 #include "KWDocument.h"
00022 #include "KWAnchor.h"
00023 #include "KWTextImage.h"
00024 #include "KWTextFrameSet.h"
00025 #include "KWVariable.h"
00026 #include "KWLoadingInfo.h"
00027 
00028 #include <KoVariable.h>
00029 #include <KoParagCounter.h>
00030 #include <KoOasisContext.h>
00031 #include <KoXmlNS.h>
00032 #include <KoOasisStyles.h>
00033 
00034 #include <kglobalsettings.h>
00035 #include <klocale.h>
00036 #include <kdebug.h>
00037 #include <assert.h>
00038 
00039 //#define DEBUG_FORMATTING
00040 #undef S_NONE // Solaris defines it in sys/signal.h
00041 
00042 // Called by KoTextParag::drawParagString - all params are in pixel coordinates
00043 void KWTextParag::drawFormattingChars( QPainter &painter, int start, int len,
00044                                        int lastY_pix, int baseLine_pix, int h_pix, // in pixels
00045                                        bool drawSelections,
00046                                        KoTextFormat *lastFormat, const QMemArray<int> &selectionStarts,
00047                                        const QMemArray<int> &selectionEnds, const QColorGroup &cg,
00048                                        bool rightToLeft, int line, KoTextZoomHandler* zh,
00049                                        int whichFormattingChars )
00050 {
00051     KWTextFrameSet * textfs = kwTextDocument()->textFrameSet();
00052     if ( !textfs )
00053         return;
00054     KWDocument * doc = textfs->kWordDocument();
00055     if ( !doc || !doc->viewFormattingChars() )
00056         return;
00057     // We set whichFormattingChars before calling KoTextFormat::drawFormattingChars
00058     whichFormattingChars = 0;
00059     if ( doc->viewFormattingSpace() )
00060         whichFormattingChars |= FormattingSpace;
00061     if ( doc->viewFormattingBreak() )
00062         whichFormattingChars |= FormattingBreak;
00063     if ( doc->viewFormattingEndParag() )
00064         whichFormattingChars |= FormattingEndParag;
00065     if ( doc->viewFormattingTabs() )
00066         whichFormattingChars |= FormattingTabs;
00067 
00068     if ( !whichFormattingChars )
00069         return;
00070     if ( start + len == length() && (whichFormattingChars & FormattingBreak) && hardFrameBreakAfter() )
00071     {
00072         painter.save();
00073         QPen pen( KGlobalSettings::linkColor() ); // #101820
00074         painter.setPen( pen );
00075         //kdDebug() << "KWTextParag::drawFormattingChars start=" << start << " len=" << len << " length=" << length() << endl;
00076             // keep in sync with KWTextFrameSet::formatVertically
00077             QString str = i18n( "--- Frame Break ---" );
00078             int width = 0;
00079             //width = lastFormat->screenStringWidth( zh, str );
00080             width = lastFormat->screenFontMetrics( zh ).width( str );
00081             QColorGroup cg2( cg );
00082             //cg2.setColor( QColorGroup::Base, Qt::green ); // for debug
00083             int last = length() - 1;
00084             KoTextStringChar &ch = string()->at( last );
00085             int x = zh->layoutUnitToPixelX( ch.x );// + ch.pixelxadj;
00086 
00087             KoTextFormat format( *lastFormat );
00088             format.setColor( pen.color() ); // ### A bit slow, maybe pass the color to drawParagStringInternal ?
00089             KoTextParag::drawParagStringInternal(
00090                 painter, str, 0, str.length(),
00091                 x, lastY_pix, // startX and lastY
00092                 zh->layoutUnitToPixelY( ch.ascent() ), // baseline
00093                 width, zh->layoutUnitToPixelY( ch.height() ), // bw and h
00094                 drawSelections, &format, selectionStarts,
00095                 selectionEnds, cg2, rightToLeft, line, zh, false );
00096         // Clear 'paint end of line' flag, we don't want it overwriting the above
00097         whichFormattingChars &= ~FormattingEndParag;
00098         painter.restore();
00099     }
00100 
00101     KoTextParag::drawFormattingChars( painter, start, len,
00102                                       lastY_pix, baseLine_pix, h_pix,
00103                                       drawSelections,
00104                                       lastFormat, selectionStarts,
00105                                       selectionEnds, cg, rightToLeft,
00106                                       line, zh, whichFormattingChars );
00107 }
00108 
00109 void KWTextParag::setPageBreaking( int pb )
00110 {
00111     m_layout.pageBreaking = pb;
00112     invalidate(0);
00113     if ( next() && ( pb & KoParagLayout::HardFrameBreakAfter ) )
00114         next()->invalidate(0);
00115 }
00116 
00117 KWTextDocument * KWTextParag::kwTextDocument() const
00118 {
00119     return static_cast<KWTextDocument *>( document() );
00120 }
00121 
00122 //static
00123 QDomElement KWTextParag::saveFormat( QDomDocument & doc, KoTextFormat * curFormat, KoTextFormat * refFormat, int pos, int len )
00124 {
00125     //kdDebug() << "KWTextParag::saveFormat refFormat=" << (  refFormat ? refFormat->key() : "none" )
00126     //          << " curFormat=" << curFormat->key()
00127     //          << " pos=" << pos << " len=" << len << endl;
00128     QDomElement formatElem = doc.createElement( "FORMAT" );
00129     formatElem.setAttribute( "id", 1 ); // text format
00130     if ( len ) // 0 when saving the format of a style
00131     {
00132         formatElem.setAttribute( "pos", pos );
00133         formatElem.setAttribute( "len", len );
00134     }
00135     QDomElement elem;
00136     if( !refFormat || curFormat->font().weight() != refFormat->font().weight() )
00137     {
00138         elem = doc.createElement( "WEIGHT" );
00139         formatElem.appendChild( elem );
00140         elem.setAttribute( "value", curFormat->font().weight() );
00141     }
00142     if( !refFormat || curFormat->color() != refFormat->color() )
00143     {
00144         if ( curFormat->color().isValid() )
00145         {
00146             elem = doc.createElement( "COLOR" );
00147             formatElem.appendChild( elem );
00148             elem.setAttribute( "red", curFormat->color().red() );
00149             elem.setAttribute( "green", curFormat->color().green() );
00150             elem.setAttribute( "blue", curFormat->color().blue() );
00151         }
00152         else
00153         {
00154             if ( refFormat )
00155             {
00156                 elem = doc.createElement( "COLOR" );
00157                 formatElem.appendChild( elem );
00158                 elem.setAttribute( "red", -1 );
00159                 elem.setAttribute( "green", -1 );
00160                 elem.setAttribute( "blue", -1 );
00161             }
00162         }
00163     }
00164     if( !refFormat || curFormat->font().family() != refFormat->font().family() )
00165     {
00166         elem = doc.createElement( "FONT" );
00167         formatElem.appendChild( elem );
00168         elem.setAttribute( "name", curFormat->font().family() );
00169     }
00170     if( !refFormat || curFormat->pointSize() != refFormat->pointSize() )
00171     {
00172         elem = doc.createElement( "SIZE" );
00173         formatElem.appendChild( elem );
00174         elem.setAttribute( "value", curFormat->pointSize() );
00175     }
00176     if( !refFormat || curFormat->font().italic() != refFormat->font().italic() )
00177     {
00178         elem = doc.createElement( "ITALIC" );
00179         formatElem.appendChild( elem );
00180         elem.setAttribute( "value", static_cast<int>(curFormat->font().italic()) );
00181     }
00182     if( !refFormat
00183         || curFormat->underlineType() != refFormat->underlineType()
00184         || curFormat->textUnderlineColor() !=refFormat->textUnderlineColor()
00185         || curFormat->underlineStyle() !=refFormat->underlineStyle()
00186         || curFormat->wordByWord() != refFormat->wordByWord())
00187     {
00188         elem = doc.createElement( "UNDERLINE" );
00189         formatElem.appendChild( elem );
00190         if ( curFormat->doubleUnderline() )
00191             elem.setAttribute( "value", "double" );
00192         else if ( curFormat->underlineType() == KoTextFormat::U_SIMPLE_BOLD)
00193             elem.setAttribute( "value", "single-bold" );
00194         else if( curFormat->underlineType()==KoTextFormat::U_WAVE)
00195             elem.setAttribute( "value", "wave" );
00196         else
00197             elem.setAttribute( "value", static_cast<int>(curFormat->underline()) );
00198         QString strLineType=KoTextFormat::underlineStyleToString( curFormat->underlineStyle() );
00199         elem.setAttribute( "styleline", strLineType );
00200         if ( curFormat->textUnderlineColor().isValid() )
00201             elem.setAttribute( "underlinecolor", curFormat->textUnderlineColor().name() );
00202 
00203         elem.setAttribute( "wordbyword" , static_cast<int>(curFormat->wordByWord()));
00204     }
00205     if( !refFormat
00206         || curFormat->strikeOutType() != refFormat->strikeOutType()
00207         || curFormat->strikeOutStyle()!= refFormat->strikeOutStyle()
00208         || curFormat->wordByWord() != refFormat->wordByWord())
00209     {
00210         elem = doc.createElement( "STRIKEOUT" );
00211         formatElem.appendChild( elem );
00212         if ( curFormat->doubleStrikeOut() )
00213             elem.setAttribute( "value", "double" );
00214         else if ( curFormat->strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)
00215             elem.setAttribute( "value", "single-bold" );
00216         else
00217             elem.setAttribute( "value", static_cast<int>(curFormat->strikeOut()) );
00218         QString strLineType=KoTextFormat::strikeOutStyleToString( curFormat->strikeOutStyle() );
00219         elem.setAttribute( "styleline", strLineType );
00220         elem.setAttribute( "wordbyword" , static_cast<int>(curFormat->wordByWord()));
00221     }
00222     if( !refFormat || (curFormat->vAlign() != refFormat->vAlign())
00223         || (curFormat->relativeTextSize() != refFormat->relativeTextSize()))
00224     {
00225         elem = doc.createElement( "VERTALIGN" );
00226         formatElem.appendChild( elem );
00227         elem.setAttribute( "value", static_cast<int>(curFormat->vAlign()) );
00228         if ( curFormat->relativeTextSize()!=0.66)
00229             elem.setAttribute( "relativetextsize", curFormat->relativeTextSize() );
00230     }
00231     if( !refFormat || curFormat->textBackgroundColor() != refFormat->textBackgroundColor() )
00232     {
00233         if ( curFormat->textBackgroundColor().isValid())
00234         {
00235             elem = doc.createElement( "TEXTBACKGROUNDCOLOR" );
00236             formatElem.appendChild( elem );
00237             elem.setAttribute( "red", curFormat->textBackgroundColor().red() );
00238             elem.setAttribute( "green", curFormat->textBackgroundColor().green() );
00239             elem.setAttribute( "blue", curFormat->textBackgroundColor().blue() );
00240         }
00241         else
00242         {
00243             if ( refFormat )
00244             {
00245                 elem = doc.createElement( "TEXTBACKGROUNDCOLOR" );
00246                 formatElem.appendChild( elem );
00247                 elem.setAttribute( "red", -1 );
00248                 elem.setAttribute( "green", -1 );
00249                 elem.setAttribute( "blue", -1 );
00250             }
00251         }
00252     }
00253     if( !refFormat ||
00254         ( curFormat->shadowDistanceX() != refFormat->shadowDistanceX()
00255           || ( curFormat->shadowDistanceY() != refFormat->shadowDistanceY() )
00256           || ( curFormat->shadowColor() != refFormat->shadowColor() ) ) )
00257     {
00258         elem = doc.createElement( "SHADOW" );
00259         formatElem.appendChild( elem );
00260         elem.setAttribute( "text-shadow", curFormat->shadowAsCss() );
00261     }
00262     if( !refFormat || curFormat->offsetFromBaseLine() != refFormat->offsetFromBaseLine())
00263     {
00264         elem = doc.createElement( "OFFSETFROMBASELINE" );
00265         formatElem.appendChild( elem );
00266         elem.setAttribute( "value", curFormat->offsetFromBaseLine() );
00267     }
00268     if( !refFormat || curFormat->attributeFont() != refFormat->attributeFont())
00269     {
00270         elem = doc.createElement( "FONTATTRIBUTE" );
00271         formatElem.appendChild( elem );
00272         elem.setAttribute( "value", KoTextFormat::attributeFontToString(curFormat->attributeFont()) );
00273     }
00274     if( !refFormat || curFormat->language() != refFormat->language())
00275     {
00276         elem = doc.createElement( "LANGUAGE" );
00277         formatElem.appendChild( elem );
00278         elem.setAttribute( "value", curFormat->language() );
00279     }
00280     return formatElem;
00281 }
00282 
00283 void KWTextParag::save( QDomElement &parentElem, bool saveAnchorsFramesets )
00284 {
00285     // The QMAX below ensures that although we don't save the trailing space
00286     // in the normal case, we do save it for empty paragraphs (#30336)
00287     save( parentElem, 0, QMAX( 0, length()-2 ), saveAnchorsFramesets );
00288 }
00289 
00290 void KWTextParag::save( QDomElement &parentElem, int from /* default 0 */,
00291                         int to /* default length()-2 */,
00292                         bool saveAnchorsFramesets /* default false */ )
00293 {
00294     QDomDocument doc = parentElem.ownerDocument();
00295     QDomElement paragElem = doc.createElement( "PARAGRAPH" );
00296     parentElem.appendChild( paragElem );
00297     QDomElement textElem = doc.createElement( "TEXT" );
00298     textElem.setAttribute("xml:space", "preserve");
00299     paragElem.appendChild( textElem );
00300     if ( partOfTableOfContents() )
00301         paragElem.setAttribute( "toc", "true" );
00302     QString text = string()->toString();
00303     Q_ASSERT( text.right(1)[0] == ' ' );
00304     textElem.appendChild( doc.createTextNode( text.mid( from, to - from + 1 ) ) );
00305 
00306     QDomElement formatsElem = doc.createElement( "FORMATS" );
00307     int startPos = -1;
00308     int index = 0; // Usually same as 'i' but if from>0, 'i' indexes the parag's text and this one indexes the output
00309     KoTextFormat *curFormat = paragraphFormat();
00310     for ( int i = from; i <= to; ++i, ++index )
00311     {
00312         KoTextStringChar & ch = string()->at(i);
00313         KoTextFormat * newFormat = static_cast<KoTextFormat *>( ch.format() );
00314         if ( ch.isCustom() )
00315         {
00316             if ( startPos > -1 && curFormat) { // Save former format
00317                 QDomElement formatElem = saveFormat( doc, curFormat,
00318                                                      paragraphFormat(), startPos, index-startPos );
00319                 if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
00320                     formatsElem.appendChild( formatElem );
00321             }
00322 
00323             QDomElement formatElem = saveFormat( doc, newFormat, paragraphFormat(), index, 1 );
00324             formatsElem.appendChild( formatElem );
00325             KoTextCustomItem* customItem = ch.customItem();
00326             formatElem.setAttribute( "id", customItem->typeId() );
00327             customItem->save( formatElem );
00328             startPos = -1;
00329             curFormat = paragraphFormat();
00330             // Save the contents of the frameset inside the anchor
00331             // This is NOT used when saving, but it is used when copying an inline frame
00332             if ( saveAnchorsFramesets )
00333             {
00334                 KWFrameSet* inlineFs = 0L;
00335                 if ( dynamic_cast<KWAnchor *>( customItem )  )
00336                     inlineFs = static_cast<KWAnchor *>( customItem )->frameSet();
00337                 else if ( dynamic_cast<KWFootNoteVariable *>( customItem ) )
00338                     inlineFs = static_cast<KWFootNoteVariable *>( customItem )->frameSet();
00339 
00340                 if ( inlineFs )
00341                 {
00342                     // Save inline framesets at the toplevel. Necessary when copying a textframeset that
00343                     // itself includes an inline frameset - we want all frameset tags at the toplevel.
00344                     QDomElement elem = doc.documentElement();
00345                     kdDebug() << " saving into " << elem.tagName() << endl;
00346                     inlineFs->toXML( elem );
00347                 }
00348             }
00349         }
00350         else
00351         {
00352             if ( newFormat != curFormat )
00353             {
00354                 // Format changed.
00355                 if ( startPos > -1 && curFormat) { // Save former format
00356                     QDomElement formatElem = saveFormat( doc, curFormat, paragraphFormat(), startPos, index-startPos );
00357                     if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
00358                         formatsElem.appendChild( formatElem );
00359                 }
00360 
00361                 // Format different from paragraph's format ?
00362                 if( newFormat != paragFormat() )
00363                 {
00364                     startPos = index;
00365                     curFormat = newFormat;
00366                 }
00367                 else
00368                 {
00369                     startPos = -1;
00370                     curFormat = paragraphFormat();
00371                 }
00372             }
00373         }
00374     }
00375     if ( startPos > -1 && index > startPos && curFormat) { // Save last format
00376         QDomElement formatElem = saveFormat( doc, curFormat, paragraphFormat(), startPos, index-startPos );
00377         if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
00378             formatsElem.appendChild( formatElem );
00379     }
00380 
00381     if (!formatsElem.firstChild().isNull()) // Do we have formats to save ?
00382         paragElem.appendChild( formatsElem );
00383 
00384 
00385     QDomElement layoutElem = doc.createElement( "LAYOUT" );
00386     paragElem.appendChild( layoutElem );
00387 
00388     // save with the real alignment (left or right, not auto)
00389     m_layout.saveParagLayout( layoutElem, resolveAlignment() );
00390 
00391     // Paragraph's format
00392     // ## Maybe we should have a "default format" somewhere and
00393     // pass it instead of 0L, to only save the non-default attributes
00394     // But this would break all export filters again.
00395     QDomElement paragFormatElement = saveFormat( doc, paragraphFormat(), 0L, 0, to - from + 1 );
00396     layoutElem.appendChild( paragFormatElement );
00397 }
00398 
00399 //static
00400 KoTextFormat KWTextParag::loadFormat( QDomElement &formatElem, KoTextFormat * refFormat, const QFont & defaultFont, const QString & defaultLanguage, bool hyphanation )
00401 {
00402     KoTextFormat format;
00403     //todo fixme !!!!!!!!!!!!
00404     format.setHyphenation( hyphanation );
00405     QFont font;
00406     if ( refFormat )
00407     {
00408         format = *refFormat;
00409         format.setCollection( 0 ); // Out of collection copy
00410         font = format.font();
00411     }
00412     else
00413     {
00414         font = defaultFont;
00415     }
00416 
00417     QDomElement elem;
00418     elem = formatElem.namedItem( "FONT" ).toElement();
00419     if ( !elem.isNull() )
00420     {
00421         font.setFamily( elem.attribute("name") );
00422     }
00423     else if ( !refFormat )
00424     {   // No reference format and no FONT tag -> use default font
00425         font = defaultFont;
00426     }
00427     elem = formatElem.namedItem( "WEIGHT" ).toElement();
00428     if ( !elem.isNull() )
00429         font.setWeight( elem.attribute( "value" ).toInt() );
00430     elem = formatElem.namedItem( "SIZE" ).toElement();
00431     if ( !elem.isNull() )
00432         font.setPointSize( elem.attribute("value").toInt() );
00433     elem = formatElem.namedItem( "ITALIC" ).toElement();
00434     if ( !elem.isNull() )
00435         font.setItalic( elem.attribute("value").toInt() == 1 );
00436     elem = formatElem.namedItem( "UNDERLINE" ).toElement();
00437     if ( !elem.isNull() ) {
00438         QString value = elem.attribute("value");
00439         if ( value == "0" || value == "1" )
00440             format.setUnderlineType( (value.toInt() == 1)?KoTextFormat::U_SIMPLE: KoTextFormat::U_NONE );
00441         else if ( value == "single" ) // value never used when saving, but why not support it? ;)
00442             format.setUnderlineType ( KoTextFormat::U_SIMPLE);
00443         else if ( value == "double" )
00444             format.setUnderlineType ( KoTextFormat::U_DOUBLE);
00445         else if ( value == "single-bold" )
00446             format.setUnderlineType ( KoTextFormat::U_SIMPLE_BOLD);
00447         else if( value =="wave")
00448             format.setUnderlineType ( KoTextFormat::U_WAVE);
00449         if ( elem.hasAttribute("styleline" ))
00450         {
00451             QString strLineType = elem.attribute("styleline");
00452             format.setUnderlineStyle( KoTextFormat::stringToUnderlineStyle( strLineType ));
00453         }
00454         if ( elem.hasAttribute("underlinecolor"))
00455         {
00456             QColor col( QColor(elem.attribute("underlinecolor")));
00457             format.setTextUnderlineColor( col );
00458         }
00459         if ( elem.hasAttribute( "wordbyword" ))
00460             format.setWordByWord( elem.attribute("wordbyword").toInt()==1);
00461     }
00462     elem = formatElem.namedItem( "STRIKEOUT" ).toElement();
00463     if ( !elem.isNull() )
00464     {
00465         QString value = elem.attribute("value");
00466         if ( value == "0" || value == "1" )
00467             format.setStrikeOutType( (value.toInt() == 1)?KoTextFormat::S_SIMPLE: KoTextFormat::S_NONE );
00468         else if ( value == "single" ) // value never used when saving, but why not support it? ;)
00469             format.setStrikeOutType ( KoTextFormat::S_SIMPLE);
00470         else if ( value == "double" )
00471             format.setStrikeOutType ( KoTextFormat::S_DOUBLE);
00472         else if ( value =="single-bold" )
00473             format.setStrikeOutType ( KoTextFormat::S_SIMPLE_BOLD);
00474 
00475         if ( elem.hasAttribute("styleline" ))
00476         {
00477             QString strLineType = elem.attribute("styleline");
00478             format.setStrikeOutStyle( KoTextFormat::stringToStrikeOutStyle( strLineType ));
00479         }
00480         if ( elem.hasAttribute( "wordbyword" ))
00481             format.setWordByWord( elem.attribute("wordbyword").toInt()==1);
00482     }
00483     // ######## Not needed in 3.0?
00484     /*
00485     elem = formatElem.namedItem( "CHARSET" ).toElement();
00486     if ( !elem.isNull() )
00487         font.setCharSet( (QFont::CharSet) elem.attribute("value").toInt() );
00488     */
00489     format.setFont( font );
00490 
00491     elem = formatElem.namedItem( "VERTALIGN" ).toElement();
00492     if ( !elem.isNull() )
00493     {
00494         format.setVAlign( static_cast<KoTextFormat::VerticalAlignment>( elem.attribute("value").toInt() ) );
00495         if (elem.hasAttribute("relativetextsize"))
00496             format.setRelativeTextSize(elem.attribute("relativetextsize").toDouble());
00497     }
00498     elem = formatElem.namedItem( "COLOR" ).toElement();
00499     if ( !elem.isNull() )
00500     {
00501         int red = elem.attribute("red").toInt();
00502         int green = elem.attribute("green").toInt();
00503         int blue = elem.attribute("blue").toInt();
00504         if ( red == -1 && blue == -1 && green == -1 )
00505             format.setColor( QColor() );
00506         else
00507             format.setColor( QColor(red,green,blue) );
00508     }
00509     elem = formatElem.namedItem( "TEXTBACKGROUNDCOLOR" ).toElement();
00510     if ( !elem.isNull() )
00511     {
00512         int red = elem.attribute("red").toInt();
00513         int green = elem.attribute("green").toInt();
00514         int blue = elem.attribute("blue").toInt();
00515         if ( red == -1 && blue == -1 && green == -1 )
00516             format.setTextBackgroundColor( QColor() );
00517         else
00518             format.setTextBackgroundColor( QColor(red,green,blue) );
00519     }
00520     elem = formatElem.namedItem( "SHADOW" ).toElement();
00521     if ( !elem.isNull() )
00522     {
00523         format.parseShadowFromCss( elem.attribute( "text-shadow" ) );
00524     } else {
00525         // Compat with koffice-1.2
00526         elem = formatElem.namedItem( "SHADOWTEXT" ).toElement();
00527         if ( !elem.isNull() && elem.attribute("value").toInt() && KoParagLayout::shadowCssCompat )
00528         {
00529             // Retrieve shadow attributes from KoParagLayout
00530             // We don't have its pointer, so shadowCssCompat is static.
00531             format.parseShadowFromCss( *KoParagLayout::shadowCssCompat );
00532         }
00533     }
00534 
00535     elem = formatElem.namedItem( "OFFSETFROMBASELINE" ).toElement();
00536     if ( !elem.isNull() )
00537         format.setOffsetFromBaseLine( elem.attribute("value").toInt());
00538 
00539     elem = formatElem.namedItem( "FONTATTRIBUTE" ).toElement();
00540     if ( !elem.isNull() )
00541         format.setAttributeFont( KoTextFormat::stringToAttributeFont(elem.attribute("value")));
00542 
00543     elem = formatElem.namedItem( "LANGUAGE" ).toElement();
00544     if ( !elem.isNull() )
00545         format.setLanguage( elem.attribute("value") );
00546     else if ( !refFormat )// No reference format and no LANGUAGE tag -> use default font
00547         format.setLanguage( defaultLanguage );
00548 
00549     //kdDebug() << "KWTextParag::loadFormat format=" << format.key() << endl;
00550     return format;
00551 }
00552 
00553 void KWTextParag::loadLayout( QDomElement & attributes )
00554 {
00555     QDomElement layout = attributes.namedItem( "LAYOUT" ).toElement();
00556     if ( !layout.isNull() )
00557     {
00558         KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
00559         KoParagLayout paragLayout = loadParagLayout( layout, doc, true );
00560         setParagLayout( paragLayout );
00561 
00562         // Load default format from style.
00563         KoTextFormat *defaultFormat = style() ? &style()->format() : 0L;
00564         QDomElement formatElem = layout.namedItem( "FORMAT" ).toElement();
00565         if ( !formatElem.isNull() )
00566         {
00567             // Load paragraph format
00568             KoTextFormat f = loadFormat( formatElem, defaultFormat, doc->defaultFont(), doc->globalLanguage(), doc->globalHyphenation() );
00569             setFormat( document()->formatCollection()->format( &f ) );
00570         }
00571         else // No paragraph format
00572         {
00573             if ( defaultFormat ) // -> use the one from the style
00574                 setFormat( document()->formatCollection()->format( defaultFormat ) );
00575         }
00576     }
00577     else
00578     {
00579         // Even the simplest import filter should do <LAYOUT><NAME value="Standard"/></LAYOUT>
00580         kdWarning(32001) << "No LAYOUT tag in PARAGRAPH, dunno what layout to apply" << endl;
00581     }
00582 }
00583 
00584 void KWTextParag::load( QDomElement &attributes )
00585 {
00586     loadLayout( attributes );
00587 
00588     // Set the text after setting the paragraph format - so that the format applies
00589     QDomElement element = attributes.namedItem( "TEXT" ).toElement();
00590     if ( !element.isNull() )
00591     {
00592         //kdDebug() << "KWTextParag::load '" << element.text() << "'" << endl;
00593         append( element.text() );
00594         // Apply default format - this should be automatic !!
00595         setFormat( 0, string()->length(), paragFormat(), TRUE );
00596     }
00597 
00598     if ( attributes.attribute( "toc" ) == "true" )
00599         setPartOfTableOfContents( true );
00600 
00601     loadFormatting( attributes );
00602 
00603     setChanged( true );
00604     invalidate( 0 );
00605 }
00606 
00607 void KWTextParag::loadFormatting( QDomElement &attributes, int offset, bool loadFootNote )
00608 {
00609 
00610     QValueList<int> removeLenList;
00611     QValueList<int> removePosList;
00612 
00613     KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
00614     QDomElement formatsElem = attributes.namedItem( "FORMATS" ).toElement();
00615     if ( !formatsElem.isNull() )
00616     {
00617         QDomElement formatElem = formatsElem.firstChild().toElement();
00618         for ( ; !formatElem.isNull() ; formatElem = formatElem.nextSibling().toElement() )
00619         {
00620             if ( formatElem.tagName() == "FORMAT" )
00621             {
00622                 int index = formatElem.attribute( "pos" ).toInt() + offset;
00623                 int len = formatElem.attribute( "len" ).toInt();
00624 
00625                 int id = formatElem.attribute( "id" ).toInt();
00626                 switch( id ) {
00627                 case 1: // Normal text
00628                 {
00629                     KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
00630                     //kdDebug(32002) << "KWTextParag::loadFormatting applying formatting from " << index << " to " << index+len << endl;
00631                     setFormat( index, len, document()->formatCollection()->format( &f ) );
00632                     break;
00633                 }
00634                 case 2: // Picture
00635                 {
00636                     len = 1; // it was missing from old 1.0 files
00637 
00638                     // The character matching this format is probably a QChar(1)
00639                     // However, as it is an invalid XML character, we must replace it
00640                     // or it will be written out while save the file.
00641                     KoTextStringChar& ch = string()->at(index);
00642                     if (ch.c.unicode()==1)
00643                     {
00644                         kdDebug() << "Replacing QChar(1) (in KWTextParag::loadFormatting)" << endl;
00645                         ch.c='#';
00646                     }
00647 
00648                     KWTextImage * custom = new KWTextImage( kwTextDocument(), QString::null );
00649                     kdDebug() << "KWTextParag::loadFormatting insertCustomItem" << endl;
00650                     paragFormat()->addRef();
00651                     setCustomItem( index, custom, paragFormat() );
00652                     custom->load( formatElem );
00653                     break;
00654                 }
00655                 case 3: // Tabulator
00656                 {
00657                     len = 1; // it was missing from old 1.0 files
00658 
00659                     // We have to replace the # or QChar(1) by a tabulator
00660                     KoTextStringChar& ch = string()->at(index);
00661                     ch.c='\t';
00662 
00663                     // I assume that we need the same treatment as for id == 1
00664                     KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
00665                     //kdDebug(32002) << "KWTextParag::loadFormatting applying formatting from " << index << " to " << index+len << endl;
00666                     setFormat( index, len, document()->formatCollection()->format( &f ) );
00667                     break;
00668                 }
00669                 case 4: // Variable
00670                 {
00671                     QDomElement varElem = formatElem.namedItem( "VARIABLE" ).toElement();
00672                     bool oldDoc = false;
00673                     if ( varElem.isNull() )
00674                     {
00675                         // Not found, must be an old document -> the tags were directly
00676                         // under the FORMAT tag.
00677                         varElem = formatElem;
00678                         oldDoc = true;
00679                     }
00680                     QDomElement typeElem = varElem.namedItem( "TYPE" ).toElement();
00681                     if ( typeElem.isNull() )
00682                         kdWarning(32001) <<
00683                             ( oldDoc ? "No <TYPE> in <FORMAT> with id=4, for a variable [old document assumed] !"
00684                               : "No <TYPE> found in <VARIABLE> tag!" ) << endl;
00685                     else
00686                     {
00687                         int type = typeElem.attribute( "type" ).toInt();
00688                         QString key = typeElem.attribute( "key" );
00689                         kdDebug() << "KWTextParag::loadFormatting variable type=" << type << " key=" << key << endl;
00690                         KoVariableFormat * varFormat = key.isEmpty() ? 0 : doc->variableFormatCollection()->format( key.latin1() );
00691                         // If varFormat is 0 (no key specified), the default format will be used.
00692                         int correct = 0;
00693                         if (typeElem.hasAttribute( "correct" ))
00694                             correct = typeElem.attribute("correct").toInt();
00695                         KoVariable * var =doc->variableCollection()->createVariable( type, -1, doc->variableFormatCollection(), varFormat,kwTextDocument(),doc, correct, true , loadFootNote);
00696                         if ( var )
00697                         {
00698                             var->load( varElem );
00699                             KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
00700                             setCustomItem( index, var, document()->formatCollection()->format( &f ) );
00701                         }
00702                         if(len>1) {
00703                             removePosList.append(index+1);
00704                             removeLenList.append(len-1);
00705                         }
00706                     }
00707                     break;
00708                 }
00709                 case 6: // Anchor
00710                 {
00711                     Q_ASSERT( len == 1 );
00712                     QDomElement anchorElem = formatElem.namedItem( "ANCHOR" ).toElement();
00713                     if ( !anchorElem.isNull() ) {
00714                         QString type = anchorElem.attribute( "type" );
00715                         if ( type == "grpMgr" /* old syntax */ || type == "frameset" )
00716                         {
00717                             QString framesetName = anchorElem.attribute( "instance" );
00718                             KWAnchorPosition pos;
00719                             pos.textfs = kwTextDocument()->textFrameSet();
00720                             pos.paragId = paragId();
00721                             pos.index = index;
00722                             doc->addAnchorRequest( framesetName, pos );
00723                         }
00724                         else
00725                             kdWarning() << "Anchor type not supported: " << type << endl;
00726                     }
00727                     else
00728                         kdWarning() << "Missing ANCHOR tag" << endl;
00729                     break;
00730                 }
00731                 default:
00732                     kdWarning() << "KWTextParag::loadFormatting id=" << id << " not supported" << endl;
00733                     break;
00734                 }
00735             }
00736         }
00737     }
00738     for(unsigned int i=0; i < removeLenList.count(); i++) {
00739         remove(*removePosList.at(i), *removeLenList.at(i));
00740     }
00741 }
00742 
00743 void KWTextParag::setParagLayout( const KoParagLayout & layout, int flags, int marginIndex )
00744 {
00745     KoTextParag::setParagLayout( layout, flags, marginIndex );
00746 
00747     if ( flags & KoParagLayout::PageBreaking )
00748         setPageBreaking( layout.pageBreaking );
00749 }
00750 
00752 
00753 // Create a KoParagLayout from XML.
00754 KoParagLayout KWTextParag::loadParagLayout( QDomElement & parentElem, KWDocument *doc, bool findStyle )
00755 {
00756     KoParagLayout layout;
00757 
00758     // Only when loading paragraphs, not when loading styles
00759     if ( findStyle )
00760     {
00761         KoParagStyle *style;
00762         // Name of the style. If there is no style, then we do not supply
00763         // any default!
00764         QDomElement element = parentElem.namedItem( "NAME" ).toElement();
00765         if ( !element.isNull() )
00766         {
00767             QString styleName = element.attribute( "value" );
00768             style = doc->styleCollection()->findStyle( styleName );
00769             if (!style)
00770             {
00771                 kdError(32001) << "Cannot find style \"" << styleName << "\" specified in paragraph LAYOUT - using Standard" << endl;
00772                 style = doc->styleCollection()->findStyle( "Standard" );
00773             }
00774             //else kdDebug() << "KoParagLayout::KoParagLayout setting style to " << style << " " << style->name() << endl;
00775         }
00776         else
00777         {
00778             kdError(32001) << "Missing NAME tag in paragraph LAYOUT - using Standard" << endl;
00779             style = doc->styleCollection()->findStyle( "Standard" );
00780         }
00781         Q_ASSERT(style);
00782         layout.style = style;
00783     }
00784 
00785     KoParagLayout::loadParagLayout( layout, parentElem, doc->syntaxVersion() );
00786 
00787     return layout;
00788 }
00789 
00790 void KWTextParag::join( KoTextParag *parag )
00791 {
00792     m_layout.pageBreaking &= ~(KoParagLayout::HardFrameBreakBefore|KoParagLayout::HardFrameBreakAfter);
00793     KoTextParag::join( parag );
00794 }
00795 
00796 void KWTextParag::loadOasis( const QDomElement& paragElement, KoOasisContext& context, KoStyleCollection *styleCollection, uint& pos )
00797 {
00798     KoTextParag::loadOasis( paragElement, context, styleCollection, pos );
00799 
00800     KWTextFrameSet* textfs = kwTextDocument()->textFrameSet();
00801     if ( textfs->isMainFrameset() )
00802     {
00803         KWDocument * doc = textfs->kWordDocument();
00804         QString& currentMasterPageRef = doc->loadingInfo()->m_currentMasterPage;
00805         const QString styleName = paragElement.attributeNS( KoXmlNS::text, "style-name", QString::null );
00806         if ( !styleName.isEmpty() )
00807         {
00808             const QDomElement* paragraphStyle = context.oasisStyles().findStyle( styleName, "paragraph" );
00809             QString masterPageName = paragraphStyle ? paragraphStyle->attributeNS( KoXmlNS::style, "master-page-name", QString::null ) : QString::null;
00810 
00811             // In KWord we don't support sections so the first paragraph is the one that determines the page layout.
00812             if ( prev() == 0 ) {
00813                 if ( masterPageName.isEmpty() )
00814                     masterPageName = "Standard"; // Seems to be a builtin name for the default layout...
00815                 currentMasterPageRef = masterPageName; // do this first to avoid recursion
00816                 context.styleStack().save();
00817                 context.styleStack().setTypeProperties( "paragraph" );
00818                 context.addStyles( paragraphStyle, "paragraph" );
00819                 // This is quite ugly... OOo stores the starting page-number in the first paragraph style...
00820                 QString pageNumber = context.styleStack().attributeNS( KoXmlNS::style, "page-number" );
00821                 if ( !pageNumber.isEmpty() )
00822                     doc->variableCollection()->variableSetting()->setStartingPageNumber( pageNumber.toInt() );
00823                 context.styleStack().restore();
00824 
00825                 doc->loadOasisPageLayout( masterPageName, context ); // page layout
00826             }
00827             else if ( !masterPageName.isEmpty() // empty means no change
00828                       && masterPageName != currentMasterPageRef )
00829             {
00830                 // Detected a change in the master page -> this means we have to use a new page layout
00831                 // and insert a frame break if not on the first paragraph.
00832                 kdDebug(32001) << "KWTextParag::loadOasis: change of master page detected: from " << currentMasterPageRef << " to " << masterPageName << " -> inserting page break" << endl;
00833                 currentMasterPageRef = masterPageName;
00834                 // [see also KoParagLayout for the 'normal' way to insert page breaks]
00835                 m_layout.pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00836                 // We have no way to load/use the new page layout, KWord doesn't have "sections".
00837             }
00838         }
00839     }
00840 }
00841 
00842 void KWTextParag::saveOasis( KoXmlWriter& writer, KoSavingContext& context,
00843                              int from, int to, bool saveAnchorsFramesets ) const
00844 {
00845     // Special case for inline tables that are alone in their paragraph:
00846     // save <table> instead of <p>.
00847     if ( string()->length() == 2 /*&& saveAnchorsFramesets*/ ) {
00848         KoTextStringChar &ch = string()->at( 0 );
00849         if ( ch.isCustom() && dynamic_cast<KWAnchor*>( ch.customItem() )) {
00850             KWFrameSet* fs = static_cast<KWAnchor *>( ch.customItem() )->frameSet();
00851             if ( fs->type() == FT_TABLE ) {
00852                 // TODO maybe save parag style? extract a common method out of KoTextStringChar::saveOasis
00853                 fs->saveOasis( writer, context, true );
00854                 return;
00855             }
00856         }
00857     }
00858     KoTextParag::saveOasis( writer, context, from, to, saveAnchorsFramesets );
00859 }
KDE Home | KDE Accessibility Home | Description of Access Keys