/* This file is part of the KDE project
   Copyright (C) 2001 David Faure <faure@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include "kwtextparag.h"
#include "kwdoc.h"
#include "kwanchor.h"
#include "kwtextimage.h"
#include "kwtextframeset.h"
#include "kwvariable.h"
#include "kwloadinginfo.h"

#include <kovariable.h>
#include <koparagcounter.h>
#include <kooasiscontext.h>
#include <koxmlns.h>
#include <koOasisStyles.h>

#include <kglobalsettings.h>
#include <klocale.h>
#include <kdebug.h>
#include <assert.h>

//#define DEBUG_FORMATTING
#undef S_NONE // Solaris defines it in sys/signal.h

// Called by KoTextParag::drawParagString - all params are in pixel coordinates
void KWTextParag::drawFormattingChars( QPainter &painter, int start, int len,
                                       int lastY_pix, int baseLine_pix, int h_pix, // in pixels
                                       bool drawSelections,
                                       KoTextFormat *lastFormat, const QMemArray<int> &selectionStarts,
                                       const QMemArray<int> &selectionEnds, const QColorGroup &cg,
                                       bool rightToLeft, int line, KoZoomHandler* zh,
                                       int whichFormattingChars )
{
    KWTextFrameSet * textfs = kwTextDocument()->textFrameSet();
    if ( !textfs )
        return;
    KWDocument * doc = textfs->kWordDocument();
    if ( !doc || !doc->viewFormattingChars() )
        return;
    // We set whichFormattingChars before calling KoTextFormat::drawFormattingChars
    whichFormattingChars = 0;
    if ( doc->viewFormattingSpace() )
        whichFormattingChars |= FormattingSpace;
    if ( doc->viewFormattingBreak() )
        whichFormattingChars |= FormattingBreak;
    if ( doc->viewFormattingEndParag() )
        whichFormattingChars |= FormattingEndParag;
    if ( doc->viewFormattingTabs() )
        whichFormattingChars |= FormattingTabs;

    if ( !whichFormattingChars )
        return;
    if ( start + len == length() && (whichFormattingChars & FormattingBreak) && hardFrameBreakAfter() )
    {
        painter.save();
        QPen pen( KGlobalSettings::linkColor() ); // #101820
        painter.setPen( pen );
        //kdDebug() << "KWTextParag::drawFormattingChars start=" << start << " len=" << len << " length=" << length() << endl;
            // keep in sync with KWTextFrameSet::formatVertically
            QString str = i18n( "--- Frame Break ---" );
            int width = 0;
            //width = lastFormat->screenStringWidth( zh, str );
            width = lastFormat->screenFontMetrics( zh ).width( str );
            QColorGroup cg2( cg );
            //cg2.setColor( QColorGroup::Base, Qt::green ); // for debug
            int last = length() - 1;
            KoTextStringChar &ch = string()->at( last );
            int x = zh->layoutUnitToPixelX( ch.x );// + ch.pixelxadj;

            KoTextFormat format( *lastFormat );
            format.setColor( pen.color() ); // ### A bit slow, maybe pass the color to drawParagStringInternal ?
            KoTextParag::drawParagStringInternal(
                painter, str, 0, str.length(),
                x, lastY_pix, // startX and lastY
                zh->layoutUnitToPixelY( ch.ascent() ), // baseline
                width, zh->layoutUnitToPixelY( ch.height() ), // bw and h
                drawSelections, &format, selectionStarts,
                selectionEnds, cg2, rightToLeft, line, zh, false );
        // Clear 'paint end of line' flag, we don't want it overwriting the above
        whichFormattingChars &= ~FormattingEndParag;
        painter.restore();
    }

    KoTextParag::drawFormattingChars( painter, start, len,
                                      lastY_pix, baseLine_pix, h_pix,
                                      drawSelections,
                                      lastFormat, selectionStarts,
                                      selectionEnds, cg, rightToLeft,
                                      line, zh, whichFormattingChars );
}

void KWTextParag::setPageBreaking( int pb )
{
    m_layout.pageBreaking = pb;
    invalidate(0);
    if ( next() && ( pb & KoParagLayout::HardFrameBreakAfter ) )
        next()->invalidate(0);
}

KWTextDocument * KWTextParag::kwTextDocument() const
{
    return static_cast<KWTextDocument *>( document() );
}

//static
QDomElement KWTextParag::saveFormat( QDomDocument & doc, KoTextFormat * curFormat, KoTextFormat * refFormat, int pos, int len )
{
    //kdDebug() << "KWTextParag::saveFormat refFormat=" << (  refFormat ? refFormat->key() : "none" )
    //          << " curFormat=" << curFormat->key()
    //          << " pos=" << pos << " len=" << len << endl;
    QDomElement formatElem = doc.createElement( "FORMAT" );
    formatElem.setAttribute( "id", 1 ); // text format
    if ( len ) // 0 when saving the format of a style
    {
        formatElem.setAttribute( "pos", pos );
        formatElem.setAttribute( "len", len );
    }
    QDomElement elem;
    if( !refFormat || curFormat->font().weight() != refFormat->font().weight() )
    {
        elem = doc.createElement( "WEIGHT" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", curFormat->font().weight() );
    }
    if( !refFormat || curFormat->color() != refFormat->color() )
    {
        if ( curFormat->color().isValid() )
        {
            elem = doc.createElement( "COLOR" );
            formatElem.appendChild( elem );
            elem.setAttribute( "red", curFormat->color().red() );
            elem.setAttribute( "green", curFormat->color().green() );
            elem.setAttribute( "blue", curFormat->color().blue() );
        }
        else
        {
            if ( refFormat )
            {
                elem = doc.createElement( "COLOR" );
                formatElem.appendChild( elem );
                elem.setAttribute( "red", -1 );
                elem.setAttribute( "green", -1 );
                elem.setAttribute( "blue", -1 );
            }
        }
    }
    if( !refFormat || curFormat->font().family() != refFormat->font().family() )
    {
        elem = doc.createElement( "FONT" );
        formatElem.appendChild( elem );
        elem.setAttribute( "name", curFormat->font().family() );
    }
    if( !refFormat || curFormat->pointSize() != refFormat->pointSize() )
    {
        elem = doc.createElement( "SIZE" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", curFormat->pointSize() );
    }
    if( !refFormat || curFormat->font().italic() != refFormat->font().italic() )
    {
        elem = doc.createElement( "ITALIC" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", static_cast<int>(curFormat->font().italic()) );
    }
    if( !refFormat
        || curFormat->underlineType() != refFormat->underlineType()
        || curFormat->textUnderlineColor() !=refFormat->textUnderlineColor()
        || curFormat->underlineStyle() !=refFormat->underlineStyle()
        || curFormat->wordByWord() != refFormat->wordByWord())
    {
        elem = doc.createElement( "UNDERLINE" );
        formatElem.appendChild( elem );
        if ( curFormat->doubleUnderline() )
            elem.setAttribute( "value", "double" );
        else if ( curFormat->underlineType() == KoTextFormat::U_SIMPLE_BOLD)
            elem.setAttribute( "value", "single-bold" );
        else if( curFormat->underlineType()==KoTextFormat::U_WAVE)
            elem.setAttribute( "value", "wave" );
        else
            elem.setAttribute( "value", static_cast<int>(curFormat->underline()) );
        QString strLineType=KoTextFormat::underlineStyleToString( curFormat->underlineStyle() );
        elem.setAttribute( "styleline", strLineType );
        if ( curFormat->textUnderlineColor().isValid() )
            elem.setAttribute( "underlinecolor", curFormat->textUnderlineColor().name() );

        elem.setAttribute( "wordbyword" , static_cast<int>(curFormat->wordByWord()));
    }
    if( !refFormat
        || curFormat->strikeOutType() != refFormat->strikeOutType()
        || curFormat->strikeOutStyle()!= refFormat->strikeOutStyle()
        || curFormat->wordByWord() != refFormat->wordByWord())
    {
        elem = doc.createElement( "STRIKEOUT" );
        formatElem.appendChild( elem );
        if ( curFormat->doubleStrikeOut() )
            elem.setAttribute( "value", "double" );
        else if ( curFormat->strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)
            elem.setAttribute( "value", "single-bold" );
        else
            elem.setAttribute( "value", static_cast<int>(curFormat->strikeOut()) );
        QString strLineType=KoTextFormat::strikeOutStyleToString( curFormat->strikeOutStyle() );
        elem.setAttribute( "styleline", strLineType );
        elem.setAttribute( "wordbyword" , static_cast<int>(curFormat->wordByWord()));
    }
    if( !refFormat || (curFormat->vAlign() != refFormat->vAlign())
        || (curFormat->relativeTextSize() != refFormat->relativeTextSize()))
    {
        elem = doc.createElement( "VERTALIGN" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", static_cast<int>(curFormat->vAlign()) );
        if ( curFormat->relativeTextSize()!=0.66)
            elem.setAttribute( "relativetextsize", curFormat->relativeTextSize() );
    }
    if( !refFormat || curFormat->textBackgroundColor() != refFormat->textBackgroundColor() )
    {
        if ( curFormat->textBackgroundColor().isValid())
        {
            elem = doc.createElement( "TEXTBACKGROUNDCOLOR" );
            formatElem.appendChild( elem );
            elem.setAttribute( "red", curFormat->textBackgroundColor().red() );
            elem.setAttribute( "green", curFormat->textBackgroundColor().green() );
            elem.setAttribute( "blue", curFormat->textBackgroundColor().blue() );
        }
        else
        {
            if ( refFormat )
            {
                elem = doc.createElement( "TEXTBACKGROUNDCOLOR" );
                formatElem.appendChild( elem );
                elem.setAttribute( "red", -1 );
                elem.setAttribute( "green", -1 );
                elem.setAttribute( "blue", -1 );
            }
        }
    }
    if( !refFormat ||
        ( curFormat->shadowDistanceX() != refFormat->shadowDistanceX()
          || ( curFormat->shadowDistanceY() != refFormat->shadowDistanceY() )
          || ( curFormat->shadowColor() != refFormat->shadowColor() ) ) )
    {
        elem = doc.createElement( "SHADOW" );
        formatElem.appendChild( elem );
        elem.setAttribute( "text-shadow", curFormat->shadowAsCss() );
    }
    if( !refFormat || curFormat->offsetFromBaseLine() != refFormat->offsetFromBaseLine())
    {
        elem = doc.createElement( "OFFSETFROMBASELINE" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", curFormat->offsetFromBaseLine() );
    }
    if( !refFormat || curFormat->attributeFont() != refFormat->attributeFont())
    {
        elem = doc.createElement( "FONTATTRIBUTE" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", KoTextFormat::attributeFontToString(curFormat->attributeFont()) );
    }
    if( !refFormat || curFormat->language() != refFormat->language())
    {
        elem = doc.createElement( "LANGUAGE" );
        formatElem.appendChild( elem );
        elem.setAttribute( "value", curFormat->language() );
    }
    return formatElem;
}

void KWTextParag::save( QDomElement &parentElem, bool saveAnchorsFramesets )
{
    // The QMAX below ensures that although we don't save the trailing space
    // in the normal case, we do save it for empty paragraphs (#30336)
    save( parentElem, 0, QMAX( 0, length()-2 ), saveAnchorsFramesets );
}

void KWTextParag::save( QDomElement &parentElem, int from /* default 0 */,
                        int to /* default length()-2 */,
                        bool saveAnchorsFramesets /* default false */ )
{
    QDomDocument doc = parentElem.ownerDocument();
    QDomElement paragElem = doc.createElement( "PARAGRAPH" );
    parentElem.appendChild( paragElem );
    QDomElement textElem = doc.createElement( "TEXT" );
    textElem.setAttribute("xml:space", "preserve");
    paragElem.appendChild( textElem );
    QString text = string()->toString();
    Q_ASSERT( text.right(1)[0] == ' ' );
    textElem.appendChild( doc.createTextNode( text.mid( from, to - from + 1 ) ) );

    QDomElement formatsElem = doc.createElement( "FORMATS" );
    int startPos = -1;
    int index = 0; // Usually same as 'i' but if from>0, 'i' indexes the parag's text and this one indexes the output
    KoTextFormat *curFormat = paragraphFormat();
    for ( int i = from; i <= to; ++i, ++index )
    {
        KoTextStringChar & ch = string()->at(i);
        KoTextFormat * newFormat = static_cast<KoTextFormat *>( ch.format() );
        if ( ch.isCustom() )
        {
            if ( startPos > -1 && curFormat) { // Save former format
                QDomElement formatElem = saveFormat( doc, curFormat,
                                                     paragraphFormat(), startPos, index-startPos );
                if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
                    formatsElem.appendChild( formatElem );
            }

            QDomElement formatElem = saveFormat( doc, newFormat, paragraphFormat(), index, 1 );
            formatsElem.appendChild( formatElem );
            KoTextCustomItem* customItem = ch.customItem();
            formatElem.setAttribute( "id", customItem->typeId() );
            customItem->save( formatElem );
            startPos = -1;
            curFormat = paragraphFormat();
            // Save the contents of the frameset inside the anchor
            // This is NOT used when saving, but it is used when copying an inline frame
            if ( saveAnchorsFramesets )
            {
                KWFrameSet* inlineFs = 0L;
                if ( dynamic_cast<KWAnchor *>( customItem )  )
                    inlineFs = static_cast<KWAnchor *>( customItem )->frameSet();
                else if ( dynamic_cast<KWFootNoteVariable *>( customItem ) )
                    inlineFs = static_cast<KWFootNoteVariable *>( customItem )->frameSet();

                if ( inlineFs )
                {
                    // Save inline framesets at the toplevel. Necessary when copying a textframeset that
                    // itself includes an inline frameset - we want all frameset tags at the toplevel.
                    QDomElement elem = doc.documentElement();
                    kdDebug() << " saving into " << elem.tagName() << endl;
                    inlineFs->toXML( elem );
                }
            }
        }
        else
        {
            if ( newFormat != curFormat )
            {
                // Format changed.
                if ( startPos > -1 && curFormat) { // Save former format
                    QDomElement formatElem = saveFormat( doc, curFormat, paragraphFormat(), startPos, index-startPos );
                    if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
                        formatsElem.appendChild( formatElem );
                }

                // Format different from paragraph's format ?
                if( newFormat != paragFormat() )
                {
                    startPos = index;
                    curFormat = newFormat;
                }
                else
                {
                    startPos = -1;
                    curFormat = paragraphFormat();
                }
            }
        }
    }
    if ( startPos > -1 && index > startPos && curFormat) { // Save last format
        QDomElement formatElem = saveFormat( doc, curFormat, paragraphFormat(), startPos, index-startPos );
        if ( !formatElem.firstChild().isNull() ) // Don't save an empty format tag
            formatsElem.appendChild( formatElem );
    }

    if (!formatsElem.firstChild().isNull()) // Do we have formats to save ?
        paragElem.appendChild( formatsElem );


    QDomElement layoutElem = doc.createElement( "LAYOUT" );
    paragElem.appendChild( layoutElem );

    // save with the real alignment (left or right, not auto)
    m_layout.saveParagLayout( layoutElem, resolveAlignment() );

    // Paragraph's format
    // ## Maybe we should have a "default format" somewhere and
    // pass it instead of 0L, to only save the non-default attributes
    // But this would break all export filters again.
    QDomElement paragFormatElement = saveFormat( doc, paragraphFormat(), 0L, 0, to - from + 1 );
    layoutElem.appendChild( paragFormatElement );
}

//static
KoTextFormat KWTextParag::loadFormat( QDomElement &formatElem, KoTextFormat * refFormat, const QFont & defaultFont, const QString & defaultLanguage, bool hyphanation )
{
    KoTextFormat format;
    //todo fixme !!!!!!!!!!!!
    format.setHyphenation( hyphanation );
    QFont font;
    if ( refFormat )
    {
        format = *refFormat;
        format.setCollection( 0 ); // Out of collection copy
        font = format.font();
    }
    else
    {
        font = defaultFont;
    }

    QDomElement elem;
    elem = formatElem.namedItem( "FONT" ).toElement();
    if ( !elem.isNull() )
    {
        font.setFamily( elem.attribute("name") );
    }
    else if ( !refFormat )
    {   // No reference format and no FONT tag -> use default font
        font = defaultFont;
    }
    elem = formatElem.namedItem( "WEIGHT" ).toElement();
    if ( !elem.isNull() )
        font.setWeight( elem.attribute( "value" ).toInt() );
    elem = formatElem.namedItem( "SIZE" ).toElement();
    if ( !elem.isNull() )
        font.setPointSize( elem.attribute("value").toInt() );
    elem = formatElem.namedItem( "ITALIC" ).toElement();
    if ( !elem.isNull() )
        font.setItalic( elem.attribute("value").toInt() == 1 );
    elem = formatElem.namedItem( "UNDERLINE" ).toElement();
    if ( !elem.isNull() ) {
        QString value = elem.attribute("value");
        if ( value == "0" || value == "1" )
            format.setUnderlineType( (value.toInt() == 1)?KoTextFormat::U_SIMPLE: KoTextFormat::U_NONE );
        else if ( value == "single" ) // value never used when saving, but why not support it? ;)
            format.setUnderlineType ( KoTextFormat::U_SIMPLE);
        else if ( value == "double" )
            format.setUnderlineType ( KoTextFormat::U_DOUBLE);
        else if ( value == "single-bold" )
            format.setUnderlineType ( KoTextFormat::U_SIMPLE_BOLD);
        else if( value =="wave")
            format.setUnderlineType ( KoTextFormat::U_WAVE);
        if ( elem.hasAttribute("styleline" ))
        {
            QString strLineType = elem.attribute("styleline");
            format.setUnderlineStyle( KoTextFormat::stringToUnderlineStyle( strLineType ));
        }
        if ( elem.hasAttribute("underlinecolor"))
        {
            QColor col( QColor(elem.attribute("underlinecolor")));
            format.setTextUnderlineColor( col );
        }
        if ( elem.hasAttribute( "wordbyword" ))
            format.setWordByWord( elem.attribute("wordbyword").toInt()==1);
    }
    elem = formatElem.namedItem( "STRIKEOUT" ).toElement();
    if ( !elem.isNull() )
    {
        QString value = elem.attribute("value");
        if ( value == "0" || value == "1" )
            format.setStrikeOutType( (value.toInt() == 1)?KoTextFormat::S_SIMPLE: KoTextFormat::S_NONE );
        else if ( value == "single" ) // value never used when saving, but why not support it? ;)
            format.setStrikeOutType ( KoTextFormat::S_SIMPLE);
        else if ( value == "double" )
            format.setStrikeOutType ( KoTextFormat::S_DOUBLE);
        else if ( value =="single-bold" )
            format.setStrikeOutType ( KoTextFormat::S_SIMPLE_BOLD);

        if ( elem.hasAttribute("styleline" ))
        {
            QString strLineType = elem.attribute("styleline");
            format.setStrikeOutStyle( KoTextFormat::stringToStrikeOutStyle( strLineType ));
        }
        if ( elem.hasAttribute( "wordbyword" ))
            format.setWordByWord( elem.attribute("wordbyword").toInt()==1);
    }
    // ######## Not needed in 3.0?
    /*
    elem = formatElem.namedItem( "CHARSET" ).toElement();
    if ( !elem.isNull() )
        font.setCharSet( (QFont::CharSet) elem.attribute("value").toInt() );
    */
    format.setFont( font );

    elem = formatElem.namedItem( "VERTALIGN" ).toElement();
    if ( !elem.isNull() )
    {
        format.setVAlign( static_cast<KoTextFormat::VerticalAlignment>( elem.attribute("value").toInt() ) );
        if (elem.hasAttribute("relativetextsize"))
            format.setRelativeTextSize(elem.attribute("relativetextsize").toDouble());
    }
    elem = formatElem.namedItem( "COLOR" ).toElement();
    if ( !elem.isNull() )
    {
        int red = elem.attribute("red").toInt();
        int green = elem.attribute("green").toInt();
        int blue = elem.attribute("blue").toInt();
        if ( red == -1 && blue == -1 && green == -1 )
            format.setColor( QColor() );
        else
            format.setColor( QColor(red,green,blue) );
    }
    elem = formatElem.namedItem( "TEXTBACKGROUNDCOLOR" ).toElement();
    if ( !elem.isNull() )
    {
        int red = elem.attribute("red").toInt();
        int green = elem.attribute("green").toInt();
        int blue = elem.attribute("blue").toInt();
        if ( red == -1 && blue == -1 && green == -1 )
            format.setTextBackgroundColor( QColor() );
        else
            format.setTextBackgroundColor( QColor(red,green,blue) );
    }
    elem = formatElem.namedItem( "SHADOW" ).toElement();
    if ( !elem.isNull() )
    {
        format.parseShadowFromCss( elem.attribute( "text-shadow" ) );
    } else {
        // Compat with koffice-1.2
        elem = formatElem.namedItem( "SHADOWTEXT" ).toElement();
        if ( !elem.isNull() && elem.attribute("value").toInt() && KoParagLayout::shadowCssCompat )
        {
            // Retrieve shadow attributes from KoParagLayout
            // We don't have its pointer, so shadowCssCompat is static.
            format.parseShadowFromCss( *KoParagLayout::shadowCssCompat );
        }
    }

    elem = formatElem.namedItem( "OFFSETFROMBASELINE" ).toElement();
    if ( !elem.isNull() )
        format.setOffsetFromBaseLine( elem.attribute("value").toInt());

    elem = formatElem.namedItem( "FONTATTRIBUTE" ).toElement();
    if ( !elem.isNull() )
        format.setAttributeFont( KoTextFormat::stringToAttributeFont(elem.attribute("value")));

    elem = formatElem.namedItem( "LANGUAGE" ).toElement();
    if ( !elem.isNull() )
        format.setLanguage( elem.attribute("value") );
    else if ( !refFormat )// No reference format and no LANGUAGE tag -> use default font
        format.setLanguage( defaultLanguage );

    //kdDebug() << "KWTextParag::loadFormat format=" << format.key() << endl;
    return format;
}

void KWTextParag::loadLayout( QDomElement & attributes )
{
    QDomElement layout = attributes.namedItem( "LAYOUT" ).toElement();
    if ( !layout.isNull() )
    {
        KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
        KoParagLayout paragLayout = loadParagLayout( layout, doc, true );
        setParagLayout( paragLayout );

        // Load default format from style.
        KoTextFormat *defaultFormat = style() ? &style()->format() : 0L;
        QDomElement formatElem = layout.namedItem( "FORMAT" ).toElement();
        if ( !formatElem.isNull() )
        {
            // Load paragraph format
            KoTextFormat f = loadFormat( formatElem, defaultFormat, doc->defaultFont(), doc->globalLanguage(), doc->globalHyphenation() );
            setFormat( document()->formatCollection()->format( &f ) );
        }
        else // No paragraph format
        {
            if ( defaultFormat ) // -> use the one from the style
                setFormat( document()->formatCollection()->format( defaultFormat ) );
        }
    }
    else
    {
        // Even the simplest import filter should do <LAYOUT><NAME value="Standard"/></LAYOUT>
        kdWarning(32001) << "No LAYOUT tag in PARAGRAPH, dunno what layout to apply" << endl;
    }
}

void KWTextParag::load( QDomElement &attributes )
{
    loadLayout( attributes );

    // Set the text after setting the paragraph format - so that the format applies
    QDomElement element = attributes.namedItem( "TEXT" ).toElement();
    if ( !element.isNull() )
    {
        //kdDebug() << "KWTextParag::load '" << element.text() << "'" << endl;
        append( element.text() );
        // Apply default format - this should be automatic !!
        setFormat( 0, string()->length(), paragFormat(), TRUE );
    }

    loadFormatting( attributes );

    setChanged( true );
    invalidate( 0 );
}

void KWTextParag::loadFormatting( QDomElement &attributes, int offset, bool loadFootNote )
{

    QValueList<int> removeLenList;
    QValueList<int> removePosList;

    KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
    QDomElement formatsElem = attributes.namedItem( "FORMATS" ).toElement();
    if ( !formatsElem.isNull() )
    {
        QDomElement formatElem = formatsElem.firstChild().toElement();
        for ( ; !formatElem.isNull() ; formatElem = formatElem.nextSibling().toElement() )
        {
            if ( formatElem.tagName() == "FORMAT" )
            {
                int index = formatElem.attribute( "pos" ).toInt() + offset;
                int len = formatElem.attribute( "len" ).toInt();

                int id = formatElem.attribute( "id" ).toInt();
                switch( id ) {
                case 1: // Normal text
                {
                    KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
                    //kdDebug(32002) << "KWTextParag::loadFormatting applying formatting from " << index << " to " << index+len << endl;
                    setFormat( index, len, document()->formatCollection()->format( &f ) );
                    break;
                }
                case 2: // Picture
                {
                    len = 1; // it was missing from old 1.0 files

                    // The character matching this format is probably a QChar(1)
                    // However, as it is an invalid XML character, we must replace it
                    // or it will be written out while save the file.
                    KoTextStringChar& ch = string()->at(index);
                    if (ch.c.unicode()==1)
                    {
                        kdDebug() << "Replacing QChar(1) (in KWTextParag::loadFormatting)" << endl;
                        ch.c='#';
                    }

                    KWTextImage * custom = new KWTextImage( kwTextDocument(), QString::null );
                    kdDebug() << "KWTextParag::loadFormatting insertCustomItem" << endl;
                    paragFormat()->addRef();
                    setCustomItem( index, custom, paragFormat() );
                    custom->load( formatElem );
                    break;
                }
                case 3: // Tabulator
                {
                    len = 1; // it was missing from old 1.0 files

                    // We have to replace the # or QChar(1) by a tabulator
                    KoTextStringChar& ch = string()->at(index);
                    ch.c='\t';

                    // I assume that we need the same treatment as for id == 1
                    KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
                    //kdDebug(32002) << "KWTextParag::loadFormatting applying formatting from " << index << " to " << index+len << endl;
                    setFormat( index, len, document()->formatCollection()->format( &f ) );
                    break;
                }
                case 4: // Variable
                {
                    QDomElement varElem = formatElem.namedItem( "VARIABLE" ).toElement();
                    bool oldDoc = false;
                    if ( varElem.isNull() )
                    {
                        // Not found, must be an old document -> the tags were directly
                        // under the FORMAT tag.
                        varElem = formatElem;
                        oldDoc = true;
                    }
                    QDomElement typeElem = varElem.namedItem( "TYPE" ).toElement();
                    if ( typeElem.isNull() )
                        kdWarning(32001) <<
                            ( oldDoc ? "No <TYPE> in <FORMAT> with id=4, for a variable [old document assumed] !"
                              : "No <TYPE> found in <VARIABLE> tag!" ) << endl;
                    else
                    {
                        int type = typeElem.attribute( "type" ).toInt();
                        QString key = typeElem.attribute( "key" );
                        kdDebug() << "KWTextParag::loadFormatting variable type=" << type << " key=" << key << endl;
                        KoVariableFormat * varFormat = key.isEmpty() ? 0 : doc->variableFormatCollection()->format( key.latin1() );
                        // If varFormat is 0 (no key specified), the default format will be used.
                        int correct = 0;
                        if (typeElem.hasAttribute( "correct" ))
                            correct = typeElem.attribute("correct").toInt();
                        KoVariable * var =doc->variableCollection()->createVariable( type, -1, doc->variableFormatCollection(), varFormat,kwTextDocument(),doc, correct, true , loadFootNote);
                        if ( var )
                        {
                            var->load( varElem );
                            KoTextFormat f = loadFormat( formatElem, paragraphFormat(), doc->defaultFont(),doc->globalLanguage(), doc->globalHyphenation() );
                            setCustomItem( index, var, document()->formatCollection()->format( &f ) );
                        }
                        if(len>1) {
                            removePosList.append(index+1);
                            removeLenList.append(len-1);
                        }
                    }
                    break;
                }
                case 6: // Anchor
                {
                    Q_ASSERT( len == 1 );
                    QDomElement anchorElem = formatElem.namedItem( "ANCHOR" ).toElement();
                    if ( !anchorElem.isNull() ) {
                        QString type = anchorElem.attribute( "type" );
                        if ( type == "grpMgr" /* old syntax */ || type == "frameset" )
                        {
                            QString framesetName = anchorElem.attribute( "instance" );
                            KWAnchorPosition pos;
                            pos.textfs = kwTextDocument()->textFrameSet();
                            pos.paragId = paragId();
                            pos.index = index;
                            doc->addAnchorRequest( framesetName, pos );
                        }
                        else
                            kdWarning() << "Anchor type not supported: " << type << endl;
                    }
                    else
                        kdWarning() << "Missing ANCHOR tag" << endl;
                    break;
                }
                default:
                    kdWarning() << "KWTextParag::loadFormatting id=" << id << " not supported" << endl;
                    break;
                }
            }
        }
    }
    for(unsigned int i=0; i < removeLenList.count(); i++) {
        remove(*removePosList.at(i), *removeLenList.at(i));
    }
}

void KWTextParag::setParagLayout( const KoParagLayout & layout, int flags, int marginIndex )
{
    KoTextParag::setParagLayout( layout, flags, marginIndex );

    if ( flags & KoParagLayout::PageBreaking )
        setPageBreaking( layout.pageBreaking );
}

//////////

// Create a KoParagLayout from XML.
KoParagLayout KWTextParag::loadParagLayout( QDomElement & parentElem, KWDocument *doc, bool findStyle )
{
    KoParagLayout layout;

    // Only when loading paragraphs, not when loading styles
    if ( findStyle )
    {
        KoParagStyle *style;
        // Name of the style. If there is no style, then we do not supply
        // any default!
        QDomElement element = parentElem.namedItem( "NAME" ).toElement();
        if ( !element.isNull() )
        {
            QString styleName = element.attribute( "value" );
            style = doc->styleCollection()->findStyle( styleName );
            if (!style)
            {
                kdError(32001) << "Cannot find style \"" << styleName << "\" specified in paragraph LAYOUT - using Standard" << endl;
                style = doc->styleCollection()->findStyle( "Standard" );
            }
            //else kdDebug() << "KoParagLayout::KoParagLayout setting style to " << style << " " << style->name() << endl;
        }
        else
        {
            kdError(32001) << "Missing NAME tag in paragraph LAYOUT - using Standard" << endl;
            style = doc->styleCollection()->findStyle( "Standard" );
        }
        Q_ASSERT(style);
        layout.style = style;
    }

    KoParagLayout::loadParagLayout( layout, parentElem, doc->syntaxVersion() );

    return layout;
}

void KWTextParag::join( KoTextParag *parag )
{
    m_layout.pageBreaking &= ~(KoParagLayout::HardFrameBreakBefore|KoParagLayout::HardFrameBreakAfter);
    KoTextParag::join( parag );
}

void KWTextParag::loadOasis( const QDomElement& paragElement, KoOasisContext& context, KoStyleCollection *styleCollection, uint& pos )
{
    KoTextParag::loadOasis( paragElement, context, styleCollection, pos );

    KWDocument * doc = kwTextDocument()->textFrameSet()->kWordDocument();
    QString& currentMasterPageRef = doc->loadingInfo()->m_currentMasterPage;
    QDomElement* paragraphStyle = context.oasisStyles().styles()[paragElement.attributeNS( KoXmlNS::text, "style-name", QString::null )];
    QString masterPageName = paragraphStyle ? paragraphStyle->attributeNS( KoXmlNS::style, "master-page-name", QString::null ) : QString::null;
    if ( masterPageName.isEmpty() )
        masterPageName = "Standard"; // Seems to be a builtin name for the default layout...
    if ( masterPageName != currentMasterPageRef )
    {
        // Detected a change in the master page -> this means we have to use a new page layout
        // and insert a frame break if not on the first paragraph.
        // In KWord we don't support sections so the first paragraph is the one that determines the page layout.
        if ( currentMasterPageRef.isEmpty() ) {
            currentMasterPageRef = masterPageName; // do this first to avoid recursion
            // Disabled. See loadOasis, we do this up front.
            //doc->loadOasisPageLayout( masterPageName, context );
        }
        else
        {
            currentMasterPageRef = masterPageName;
            // [see also KoParagLayout for the 'normal' way to insert page breaks]
            m_layout.pageBreaking |= KoParagLayout::HardFrameBreakBefore;
            // We have no way to load/use the new page layout, KWord doesn't have "sections".
        }
    }
}

void KWTextParag::saveOasis( KoXmlWriter& writer, KoSavingContext& context,
                             int from, int to, bool saveAnchorsFramesets ) const
{
    // Special case for inline tables that are alone in their paragraph:
    // save <table> instead of <p>.
    if ( string()->length() == 2 /*&& saveAnchorsFramesets*/ ) {
        KoTextStringChar &ch = string()->at( 0 );
        if ( ch.isCustom() && dynamic_cast<KWAnchor*>( ch.customItem() )) {
            KWFrameSet* fs = static_cast<KWAnchor *>( ch.customItem() )->frameSet();
            if ( fs->type() == FT_TABLE ) {
                // TODO maybe save parag style? extract a common method out of KoTextStringChar::saveOasis
                fs->saveOasis( writer, context, true );
                return;
            }
        }
    }
    KoTextParag::saveOasis( writer, context, from, to, saveAnchorsFramesets );
}
