/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <hintids.hxx>
#include <tools/list.hxx>
#include <tools/cachestr.hxx>
#include <svtools/rtftoken.h>
#include <svl/itemiter.hxx>
#include <editeng/prntitem.hxx>
#include <editeng/opaqitem.hxx>
#include <editeng/protitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <fmtfsize.hxx>
#include <fmtanchr.hxx>
#include <fmtpdsc.hxx>
#include <fmtsrnd.hxx>
#include <fmtclds.hxx>
#include <fmtcntnt.hxx>
#include <frmatr.hxx>
#include <doc.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <shellio.hxx>
#include <swparrtf.hxx>
#include <grfatr.hxx>
#include <paratr.hxx>
#include <rtf.hxx>
#include <ndgrf.hxx>
#include <pagedesc.hxx>
#include <swtable.hxx>
#include <txtflcnt.hxx>
#include <fmtflcnt.hxx>
#include <fltini.hxx>
#include <unoframe.hxx>
#include <deque>
#include <map>
#include <utility>
#include <fmtwrapinfluenceonobjpos.hxx>
#include <editeng/brshitem.hxx>
#include <fmtfollowtextflow.hxx>
#include "dcontact.hxx"
#include <drawdoc.hxx>

using namespace ::com::sun::star;

#define ANCHOR(p) 	((SwFmtAnchor*)p)

// steht in shellio.hxx
extern SwCntntNode* GoNextNds( SwNodeIndex * pIdx, sal_Bool bChk );

SV_IMPL_PTRARR( SwFlySaveArr, SwFlySave* )

inline const SwFmtFrmSize GetFrmSize(const SfxItemSet& rSet, sal_Bool bInP=sal_True)
{
    return (const SwFmtFrmSize&)rSet.Get(RES_FRM_SIZE,bInP);
}

SwFlySave::SwFlySave(const SwPaM& rPam, SfxItemSet& rSet)
	: aFlySet(rSet), nSttNd(rPam.GetPoint()->nNode), nEndNd(nSttNd), nEndCnt(0),
     nPageWidth(ATT_MIN_SIZE), nDropLines(0), nDropAnchor(0)
{
}

int SwFlySave::IsEqualFly( const SwPaM& rPos, SfxItemSet& rSet )
{
	if( rSet.Count() != aFlySet.Count() || nDropAnchor )
		return sal_False;

	// nur TextNodes zusammenfassen
	if( nSttNd == nEndNd && nEndNd.GetNode().IsNoTxtNode() )
		return sal_False;

	// teste auf gleiche / naechste Position
	if( rPos.GetPoint()->nNode.GetIndex() == nEndNd.GetIndex() )
	{
		if( 1 < (rPos.GetPoint()->nContent.GetIndex() - nEndCnt) )
			return sal_False;
	}
	else if( rPos.GetPoint()->nContent.GetIndex() )
		return sal_False;
	else
	{
		SwNodeIndex aIdx( nEndNd );
        SwCntntNode *const pCNd = aIdx.GetNode().GetCntntNode();
		if( !GoNextNds( &aIdx, sal_True ) ||
			aIdx.GetIndex() != rPos.GetPoint()->nNode.GetIndex() ||
			( pCNd && pCNd->Len() != nEndCnt ))
		{
			return sal_False;
		}
	}

	if( rSet.Count() )
	{
		SfxItemIter aIter( rSet );
		const SfxPoolItem *pItem, *pCurr = aIter.GetCurItem();
		while( sal_True )
		{
			if( SFX_ITEM_SET != aFlySet.GetItemState( pCurr->Which(),
				sal_False, &pItem ) ||
				// Ankerattribute gesondert behandeln
				( RES_ANCHOR == pCurr->Which()
					? (ANCHOR(pCurr)->GetAnchorId() != ANCHOR(pItem)->GetAnchorId() ||
					   ANCHOR(pCurr)->GetPageNum() != ANCHOR(pItem)->GetPageNum())
					: *pItem != *pCurr ))
						return sal_False;

			if( aIter.IsAtEnd() )
				break;
			pCurr = aIter.NextItem();
		}
	}
	return sal_True;
}

void SwFlySave::SetFlySize( const SwTableNode& rTblNd )
{
	// sollte der Fly kleiner als diese Tabelle sein, dann
	// korrigiere diesen (nur bei abs. Angaben!)
	SwTwips nWidth = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth();
	const SwFmtFrmSize& rSz = GetFrmSize( aFlySet );
	if( nWidth > rSz.GetWidth() )
        aFlySet.Put( SwFmtFrmSize( rSz.GetHeightSizeType(), nWidth, rSz.GetHeight() ));
}

sal_Bool lcl_HasBreakAttrs( const SwCntntNode& rNd )
{
	sal_Bool bRet = sal_False;
	const SfxItemSet& rSet = rNd.GetSwAttrSet();
	const SfxPoolItem* pItem;
	if( SFX_ITEM_SET == rSet.GetItemState( RES_BREAK, sal_True, &pItem ) &&
		SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
		bRet = sal_True;
	else if( SFX_ITEM_SET == rSet.GetItemState( RES_PAGEDESC, sal_True, &pItem )&&
		 0 != ((SwFmtPageDesc*)pItem)->GetPageDesc() )
		bRet = sal_True;
	return bRet;
}


void lcl_CpyBreakAttrs( SwCntntNode* pSrcNd, SwCntntNode* pDstNd,
						SwNodeIndex* pNewIdx )
{
    const SfxItemSet* pSet;
	if( pSrcNd && pDstNd && 0 != ( pSet = pSrcNd->GetpSwAttrSet() ) )
	{
		const SfxPoolItem *pDescItem, *pBreakItem;

		if( SFX_ITEM_SET != pSet->GetItemState( RES_BREAK,
										sal_False, &pBreakItem ) )
			pBreakItem = 0;

		if( SFX_ITEM_SET != pSet->GetItemState( RES_PAGEDESC,
										sal_False, &pDescItem ) )
			pDescItem = 0;

		if( pDescItem || pBreakItem )
		{
			if( lcl_HasBreakAttrs( *pDstNd ))
			{
				SwPosition aPos( *pDstNd, SwIndex( pDstNd ));
				aPos.nNode--;
				pDstNd->GetDoc()->AppendTxtNode( aPos );
				if( pNewIdx )
					*pNewIdx = aPos.nNode;

				SwCntntNode* pOldNd = pDstNd;
				pDstNd = aPos.nNode.GetNode().GetCntntNode();
				pDstNd->ChgFmtColl( pOldNd->GetFmtColl() );
                if( pDstNd->HasSwAttrSet() )
				{
					SfxItemSet aSet( *pDstNd->GetpSwAttrSet() );
					aSet.ClearItem( RES_BREAK );
					aSet.ClearItem( RES_PAGEDESC );
					pDstNd->SetAttr( aSet );
				}
			}
			if( pBreakItem )
			{
				pDstNd->SetAttr( *pBreakItem );
				pSrcNd->ResetAttr( RES_BREAK );
			}
			if( pDescItem )
			{
				pDstNd->SetAttr( *pDescItem );
				pSrcNd->ResetAttr( RES_PAGEDESC );
			}
		}
	}
}

void SwRTFParser::SetFlysInDoc()
{
	// !! von Oben abarbeiten, CntntPos ist kein Index !
	SwNodes & rNds = pDoc->GetNodes();
    typedef std::pair<SwFlyFrmFmt*, SwFmtAnchor> frameEntry;
    typedef std::deque<frameEntry> rtfframesAtIndex;
    typedef std::map<const SwNode*, rtfframesAtIndex> rtfFmtMap;
    rtfFmtMap aPrevFmts;

	SwFrmFmt* pParent = pDoc->GetFrmFmtFromPool( RES_POOLFRM_FRAME );
	for( sal_uInt16 n = 0; n < aFlyArr.Count(); ++n )
	{
		SwFlySave* pFlySave = aFlyArr[ n ];

		ASSERT( !pFlySave->nSttNd.GetNode().FindFlyStartNode(),
				"Content vom Fly steht in einem Fly" );
		ASSERT( pFlySave->nSttNd.GetIndex() <= pFlySave->nEndNd.GetIndex(),
				"Fly hat falschen Bereich" );



		//JP 21.09.98: wenn ein DropCap ist, dann Text im Node belassen, am
		//				Absatz das Absatz Attribut setzen. Ggfs noch die
		//				FontSize zuruecksetzen, damit das DropCap nicht zu
		//				gro? wird.
		if( pFlySave->nDropAnchor )
		{
			SwTxtNode* pSttNd = pFlySave->nSttNd.GetNode().GetTxtNode();
			SwTxtNode* pEndNd = pFlySave->nEndNd.GetNode().GetTxtNode();
			if( pSttNd && pEndNd &&
				pSttNd->GetIndex() + 1 == pEndNd->GetIndex()
				&& pSttNd->GetTxt().Len()>0 /* #i38227# leave drop caps with no content as fly frames */ )
			{
				sal_uLong nPos = pSttNd->GetIndex();
				SwDoc * pDoc1 = pSttNd->GetDoc();

				sal_Bool bJoined;
				{
					SwPaM aTmp( *pSttNd, pSttNd->GetTxt().Len(), *pEndNd, 0 );
					bJoined = pDoc1->DeleteAndJoin( aTmp );
				}

				SwTxtNode * pNd = (pDoc1->GetNodes()[nPos])->GetTxtNode();

				if( bJoined && pNd != NULL)
				{
					SwFmtDrop aDropCap;
					aDropCap.GetLines() = (sal_uInt8)pFlySave->nDropLines;
					aDropCap.GetChars() = 1;

					SwIndex aIdx( pEndNd );
					pNd->RstTxtAttr( aIdx, 1, RES_CHRATR_FONTSIZE );
                    pNd->SetAttr( aDropCap );
				}
				delete pFlySave;
				continue;
			}
		}

		// liegt Ende und Start vom Naechsten im gleichen Node, dann muss
		// gesplittet werden
        if (((static_cast<size_t>(n) + 1) < aFlyArr.Count()) &&
            pFlySave->nEndCnt &&
			pFlySave->nEndNd == aFlyArr[ n + 1 ]->nSttNd )
		{
            SwCntntNode *const pCNd = pFlySave->nEndNd.GetNode().GetCntntNode();
			if( pCNd )
			{
				SwPosition aPos( pFlySave->nEndNd,
								SwIndex( pCNd, pFlySave->nEndCnt ));
				pDoc->SplitNode( aPos, false );
				pFlySave->nEndNd--;
			}
			else
				pFlySave->nEndCnt = 0;
		}

		// verschiebe den Inhalt von diesem Anchor in den Auto-TextBereich
		// und erzeuge dadurch den richtigen SwG-Rahmen
		SwNodeRange aRg(pFlySave->nSttNd, 0, pFlySave->nEndNd, 0);
        //Make a new section, unless there is no content at all
		const bool bMakeEmptySection = aRg.aStart < aRg.aEnd || ((aRg.aStart == aRg.aEnd) && pFlySave->nEndCnt);

		{
			// Nur TextNodes koennen in Tabellen stehen !!
			const SwNode* pNd = &pFlySave->nSttNd.GetNode();
			if( pNd->IsNoTxtNode() )
			{
				// die Size muss noch korrigiert werden!
				nAktPageDesc = 0;		// Standart PageDesc
				if( SFX_ITEM_SET != pFlySave->aFlySet.GetItemState(
					RES_FRM_SIZE, sal_False ) )
					_SetPictureSize( *(SwNoTxtNode*)pNd, aRg.aStart,
									pFlySave->aFlySet );
				if( 0 != ( pNd = pNd->FindTableNode() ) )
					pFlySave->SetFlySize( *(SwTableNode*)pNd );
			}
			else
			{
				// Take care for table nodes
				pNd = pNd->GetNodes()[ pNd->GetIndex() - 2 ]->GetTableNode();
				if( pNd ) // if the table starts immediately before aRg -> expand aRg
					aRg.aStart = *pNd;

				if( bMakeEmptySection )
				{
					pNd = &aRg.aEnd.GetNode();
					sal_uLong nSectEnd = pNd->EndOfSectionIndex()+1;

					if (!pNd->IsTableNode() && 0 !=(pNd = pNd->FindTableNode())
                        && (pNd->GetIndex() >= aRg.aStart.GetNode().GetIndex()) )
					{
						const SwNode* pTblBxNd;

						// Ende der Tabelle ist hinter dieser Box ??
						if( pNd->EndOfSectionIndex() == nSectEnd )
							aRg.aEnd = nSectEnd+1;
						// is the end in the first box of the table, then
						// move before the table (Bug 67663)
                        // but the range must not become emtpy, i.e. aStart==aEnd
                        // because otherwise we will get a crash (126506) later on
						else if( 0 != ( pTblBxNd = aRg.aEnd.GetNode().
												FindTableBoxStartNode()) &&
								 pTblBxNd->GetIndex() - 1 == pNd->GetIndex() &&
                                 &aRg.aStart.GetNode() != pNd )
							aRg.aEnd = *pNd;
						else
						{
							// Tabelle ist noch groesser, also splitte sie hier.
							rNds.SplitTable( aRg.aEnd, sal_True );
							aRg.aEnd = pNd->EndOfSectionIndex() + 1;
						}
					}
				}
			}
		}

		// vorm verschieben muss sich der Index auf die alte Position
		// gemerkt werden, der Index wird mit verschoben !!!

		SwNodeIndex aTmpIdx( rNds.GetEndOfAutotext() );
		SwStartNode* pSttNd = bMakeEmptySection
				? rNds.MakeEmptySection( aTmpIdx, SwFlyStartNode )
				: rNds.MakeTextSection( aTmpIdx, SwFlyStartNode,
						(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );

		// das ist die Verankerungs-Position (fuers Layout!)
		pFlySave->nSttNd = aRg.aStart.GetIndex()-1;
		if( bMakeEmptySection )
		{
			// check: the move does not clear the surrounded section. If all
			// nodes moved away, then create a new TxtNode
			{
                // i76403: an empty selection is not a good idea
                if( aRg.aStart == aRg.aEnd && aRg.aStart.GetNode().GetTxtNode() )
                    aRg.aEnd++;
				SwNodeIndex aPrev( aRg.aStart, -1 );
				if( aPrev.GetNode().IsStartNode() &&
					aPrev.GetNode().EndOfSectionNode() == &aRg.aEnd.GetNode())
				{
					// create new txtnode, because the section does never be empty
					pDoc->GetNodes().MakeTxtNode( aRg.aEnd,
							(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
					aRg.aEnd--;
				}
			}
			aTmpIdx = *pSttNd->EndOfSectionNode();
            pDoc->MoveNodeRange( aRg, aTmpIdx,
                IDocumentContentOperations::DOC_MOVEDEFAULT );
        }

		// patch from cmc for #i52542#
        if (pSttNd->GetIndex() + 1 == pSttNd->EndOfSectionIndex())
        {
            ASSERT(sal_False, "nothing in this frame, not legal");
            delete pFlySave;
            continue;
        }

		pFlySave->aFlySet.Put( SwFmtCntnt( pSttNd ));

		CalculateFlySize( pFlySave->aFlySet, pFlySave->nSttNd,
						  pFlySave->nPageWidth );

                // THIS >>>>>
		// if the section only contains one Node and this has a
		// border or background, then put it to the frame
		// Not in our own RTF-Format!
                // <<<<< DOES NOT MAKE SENSE TO ME (flr)
		// #102781#. Added support for transparent frames.
		if( pSttNd->GetIndex() + 1 != pSttNd->EndOfSectionIndex() &&
			!bSwPageDesc )
		{
			SwCntntNode* pSrcNd = pDoc->GetNodes()[ pSttNd->GetIndex() + 1 ]->GetCntntNode();
			SfxItemSet aTmpSet( pDoc->GetAttrPool(),
									RES_BACKGROUND, RES_BOX );
            const SvxBrushItem* pBackgroundBrush = (const SvxBrushItem*)pFlySave->aFlySet.GetItem(RES_BACKGROUND, sal_False);
			if( pSrcNd && pSrcNd->HasSwAttrSet() )
				aTmpSet.Put( *pSrcNd->GetpSwAttrSet() );
			if (pBackgroundBrush)
			{
				aTmpSet.Put(*pBackgroundBrush, RES_BACKGROUND);
			}
            else
            {
                pBackgroundBrush = (const SvxBrushItem*)aTmpSet.GetItem(RES_BACKGROUND, sal_False);
                if (pBackgroundBrush)
                {
                    Color& rBackgroundColor = const_cast<SvxBrushItem*>(pBackgroundBrush)->GetColor();
                    rBackgroundColor.SetTransparency(0xFE);
                }
                else
                {
                    Color aColor = Color(0xff, 0xff, 0xff);
                    aColor.SetTransparency( 0xFE);
                    SvxBrushItem aBrush(aColor, RES_BACKGROUND);
                    aTmpSet.Put(aBrush, RES_BACKGROUND);
                }
            }
			// #117914# Topic 6.
			pFlySave->aFlySet.Put( aTmpSet );
            if( pSrcNd && pSrcNd->HasSwAttrSet() )
			{
				pSrcNd->ResetAttr( RES_BACKGROUND, RES_BOX );
			}
		}

		SwFlyFrmFmt* pFmt = pDoc->MakeFlyFrmFmt( aEmptyStr, pParent );
        pFmt->SetFmtAttr( pFlySave->aFlySet );
		const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
        if (FLY_AS_CHAR != rAnchor.GetAnchorId())
        {
			// korrigiere noch den Absatz, ist immer der vorhergehende !
			// JP 20.09.95: wenn es diesen gibt! (DocAnfang!)

			//JP 02.08.99: that is wrong. The anchor is ever the NEXT!
			//JP 05.08.99: there are an Bug in the ExportFilter which will
			//				be fixed in the Version 517 - by SWG-Export
			//				the fly will be after the paragraph - but in RTF
			// 				the	flys will be before the paragraph.
			if( !bSwPageDesc || 5430 < GetVersionNo() )
				pFlySave->nSttNd++;

//            if( !pFlySave->nSttNd.GetNode().IsCntntNode() )
			{
				// Seitenumbrueche in den Bodybereich verschieben!
				SwCntntNode* pSrcNd = aRg.aStart.GetNode().GetCntntNode();
				SwCntntNode* pDstNd = pFlySave->nSttNd.GetNode().GetCntntNode();
				if( !pDstNd )
					pDstNd = pDoc->GetNodes().GoNext( &pFlySave->nSttNd );

				::lcl_CpyBreakAttrs( pSrcNd, pDstNd, &pFlySave->nSttNd );
			}

            const SwNodeIndex aSttNd(*pSttNd);
            SwNodeIndex aEndNd(*pSttNd->EndOfSectionNode());
            aEndNd--;

            SwPosition aPos( pFlySave->nSttNd );
            SwFmtAnchor aAnchor(rAnchor);
            aAnchor.SetAnchor(&aPos);

            const SwNode *pCurrentAnchor = &(pFlySave->nSttNd.GetNode());
            aPrevFmts[pCurrentAnchor].push_back(frameEntry(pFmt, aAnchor));

            while (aEndNd > aSttNd)
            {
                typedef rtfframesAtIndex::iterator myIter;
                rtfframesAtIndex &rDeque = aPrevFmts[&(aEndNd.GetNode())];
                myIter aEnd = rDeque.end();
                for (myIter aIter = rDeque.begin(); aIter != aEnd; ++aIter)
                {
                    aIter->second.SetAnchor(&aPos);
                    // --> OD 2004-06-30 #i27767# - push on front to keep order
                    // of objects for the correct object positioning
                    //aPrevFmts[pCurrentAnchor].push_back(*aIter);
                    aPrevFmts[pCurrentAnchor].push_front(*aIter);
                }
                rDeque.clear();
                aEndNd--;
           }
		}

        // --> OD, FLR 2006-02-16 #131205#
		// Create draw contact object, which also creates a <SdrObject> instance,
		// in order to set the order number.
		// The order number is assumed to be the order of the text flow.
        SwFlyDrawContact* pContact =
                new SwFlyDrawContact( pFmt,
                                      pFmt->GetDoc()->GetOrCreateDrawModel() );
        pContact->GetMaster()->SetOrdNum( n );
        // <--

		delete pFlySave;
	}

    typedef rtfFmtMap::reverse_iterator myriter;
    myriter aEnd = aPrevFmts.rend();
    for(myriter aIter = aPrevFmts.rbegin(); aIter != aEnd; ++aIter)
    {
        rtfframesAtIndex &rDeque = aIter->second;
        typedef rtfframesAtIndex::iterator myIter;
        myIter aQEnd = rDeque.end();
        for (myIter aQIter = rDeque.begin(); aQIter != aQEnd; ++aQIter)
        {
            frameEntry &rEntry = *aQIter;
            SwFlyFrmFmt *pFrm = rEntry.first;
            SwFmtAnchor &rAnchor = rEntry.second;
            pFrm->SetFmtAttr(rAnchor);
        }
    }

    aFlyArr.Remove(0, aFlyArr.Count());
}

// clips the text box to the min or max position if it is outside our min or max boundary
long SwRTFParser::GetSafePos(long nPos)
{
    if(nPos > SHRT_MAX)
        nPos = SHRT_MAX;
    else if(nPos < SHRT_MIN)
        nPos = SHRT_MIN;

    return nPos;
}

void SwRTFParser::ReadFly( int nToken, SfxItemSet* pSet )
{
	// ein Set fuer die FrmFmt-Attribute
	SfxItemSet aSet( pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
	if( !IsNewDoc() )
		Reader::ResetFrmFmtAttrs( aSet );

	// der Fly beginnt immer in einem neuen Absatz
	if( pPam->GetPoint()->nContent.GetIndex() )
		InsertPara();

	// RTF-Defaults setzen:
    // --> OD 2004-06-24 #i27767#
    SwFmtAnchor aAnchor( FLY_AT_PARA );

    SwFmtHoriOrient aHori( 0, text::HoriOrientation::LEFT, text::RelOrientation::FRAME );
    SwFmtVertOrient aVert( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME );
    // <--
    SvxFrameDirectionItem aFrmDir( FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );

	sal_uInt16 nCols = USHRT_MAX, nColSpace = USHRT_MAX, nAktCol = 0;
	SvUShorts aColumns;

	sal_Bool bChkDropCap = 0 == pSet;
	sal_uInt16 nDropCapLines = 0, nDropCapAnchor = 0;
	int nNumOpenBrakets = GetOpenBrakets();

	if( !pSet )
    {
		pSet = &aSet;
    }
	else
	{
		// die Werte aus dem uebergebenen!
		aAnchor = (SwFmtAnchor&)pSet->Get( RES_ANCHOR );
		aHori = (SwFmtHoriOrient&)pSet->Get( RES_HORI_ORIENT );
		aVert = (SwFmtVertOrient&)pSet->Get( RES_VERT_ORIENT );
	}

	// dann sammel mal alle Attribute zusammen
	int bWeiter = sal_True;
    int nAppliedProps=0;
	do {
		sal_uInt16 nVal = sal_uInt16(nTokenValue);
        /*
        #i5263#
        Assume that a property genuinely contributes towards creating a frame,
        and if turns out to be a non contributing one reduce the count.
        */
        ++nAppliedProps;
		switch( nToken )
		{
		case RTF_ABSW:
			{
				SwFmtFrmSize aSz( ATT_MIN_SIZE, nTokenValue, 0 );
				const SfxPoolItem* pItem;
				if( SFX_ITEM_SET == pSet->GetItemState( RES_FRM_SIZE, sal_True,
					&pItem ))
				{
                    aSz.SetHeightSizeType( ((SwFmtFrmSize*)pItem)->GetHeightSizeType() );
					aSz.SetHeight( ((SwFmtFrmSize*)pItem)->GetHeight() );
				}
				if( MINFLY > nTokenValue )	nTokenValue = MINFLY;
				aSet.Put( aSz );
			}
			break;
		case RTF_ABSH:
			{
				SwFmtFrmSize aSz( ATT_MIN_SIZE, 0, MINFLY );
				const SfxPoolItem* pItem;
				if( SFX_ITEM_SET == pSet->GetItemState( RES_FRM_SIZE, sal_True,
					&pItem ))
				{
					aSz.SetWidth( ((SwFmtFrmSize*)pItem)->GetWidth() );
				}

				if( 0 > nTokenValue )
				{
					nTokenValue = -nTokenValue;
                    aSz.SetHeightSizeType( ATT_FIX_SIZE );
				}
				if( MINFLY > nTokenValue )	nTokenValue = MINFLY;
				aSz.SetHeight( nTokenValue );
				aSet.Put( aSz );
			}
			break;

		case RTF_NOWRAP:
			{
				pSet->Put( SwFmtSurround( SURROUND_NONE ));
			}
			break;
		case RTF_DXFRTEXT:
				{
                    SvxULSpaceItem aUL( RES_UL_SPACE );
                    SvxLRSpaceItem aLR( RES_LR_SPACE );
					aUL.SetUpper( nVal );	aUL.SetLower( nVal );
					aLR.SetLeft( nVal );	aLR.SetRight( nVal );
					pSet->Put( aUL );
					pSet->Put( aLR );
				}
				break;

		case RTF_DFRMTXTX:
				{
                    SvxLRSpaceItem aLR( RES_LR_SPACE );
					aLR.SetLeft( nVal );	aLR.SetRight( nVal );
					pSet->Put( aLR );
				}
				break;
		case RTF_DFRMTXTY:
				{
                    SvxULSpaceItem aUL( RES_UL_SPACE );
					aUL.SetUpper( nVal );	aUL.SetLower( nVal );
					pSet->Put( aUL );
				}
				break;

		case RTF_POSNEGX:
        case RTF_POSX:      aHori.SetHoriOrient( text::HoriOrientation::NONE );
							aHori.SetPos( GetSafePos((long)nTokenValue) );
							break;
        case RTF_POSXC:     aHori.SetHoriOrient( text::HoriOrientation::CENTER );     break;
        case RTF_POSXI:     aHori.SetHoriOrient( text::HoriOrientation::LEFT );
							aHori.SetPosToggle( sal_True );
							break;
        case RTF_POSXO:     aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
							aHori.SetPosToggle( sal_True );
							break;
        case RTF_POSXL:     aHori.SetHoriOrient( text::HoriOrientation::LEFT );       break;
        case RTF_POSXR:     aHori.SetHoriOrient( text::HoriOrientation::RIGHT );      break;

		case RTF_POSNEGY:
        case RTF_POSY:      aVert.SetVertOrient( text::VertOrientation::NONE );
							aVert.SetPos( GetSafePos((long)nTokenValue) );
							break;
        case RTF_POSYT:     aVert.SetVertOrient( text::VertOrientation::TOP );    break;
        case RTF_POSYB:     aVert.SetVertOrient( text::VertOrientation::BOTTOM ); break;
        case RTF_POSYC:     aVert.SetVertOrient( text::VertOrientation::CENTER ); break;

        case RTF_PHMRG:     aHori.SetRelationOrient( text::RelOrientation::PAGE_PRINT_AREA ); break;
        case RTF_PVMRG:     aVert.SetRelationOrient( text::RelOrientation::PAGE_PRINT_AREA ); break;
        case RTF_PHPG:      aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); break;
        case RTF_PVPG:      aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME );break;
        case RTF_PHCOL:     aHori.SetRelationOrient( text::RelOrientation::FRAME ); break;
        case RTF_PVPARA:    aVert.SetRelationOrient( text::RelOrientation::FRAME ); break;

		case RTF_POSYIL:
            break;
		case RTF_ABSLOCK:
            /*
            #i5263#
            Not sufficient to make a frame at least word won't do it with just
            an abslock
            */
            --nAppliedProps;
            break;
		case RTF_FRMTXLRTB:
			aFrmDir.SetValue( FRMDIR_HORI_LEFT_TOP );
			break;
		case RTF_FRMTXTBRL:
			aFrmDir.SetValue( FRMDIR_HORI_RIGHT_TOP );
			break;
		case RTF_FRMTXLRTBV:
			aFrmDir.SetValue( FRMDIR_VERT_TOP_LEFT );
			break;
		case RTF_FRMTXTBRLV:
			aFrmDir.SetValue( FRMDIR_VERT_TOP_RIGHT );
			break;

		case RTF_DROPCAPLI:							// Dropcaps !!
				if( bChkDropCap )
				{
					nDropCapLines = sal_uInt16( nTokenValue );
					if( !nDropCapAnchor )
						nDropCapAnchor = 1;
				}
				break;
		case RTF_DROPCAPT:
				if( bChkDropCap )
				{
					nDropCapAnchor = sal_uInt16( nTokenValue );
					if( !nDropCapLines )
						nDropCapLines = 3;
				}
				break;


		// fuer die "alten" Writer - haben die Spaltigkeit falsch heraus-
		// geschrieben
		case RTF_COLS:			nCols = sal_uInt16( nTokenValue );		break;
		case RTF_COLSX:			nColSpace = sal_uInt16( nTokenValue );	break;
		case RTF_COLNO:
			nAktCol = sal_uInt16( nTokenValue );
			if( RTF_COLW == GetNextToken() )
			{
				sal_uInt16 nWidth = sal_uInt16( nTokenValue ), nSpace = 0;
				if( RTF_COLSR == GetNextToken() )
					nSpace = sal_uInt16( nTokenValue );
				else
					SkipToken( -1 );		// wieder zurueck

				if( --nAktCol == ( aColumns.Count() / 2 ) )
				{
					aColumns.Insert( nWidth + nSpace, aColumns.Count() );
					aColumns.Insert( nSpace, aColumns.Count() );
				}
			}
			break;

		case '{':
			{
				short nSkip = 0;
				if( RTF_IGNOREFLAG != ( nToken = GetNextToken() ))
				{
					if( RTF_SHADINGDEF == (nToken & ~0xff) )
					{
						ReadBackgroundAttr( nToken, aSet );
						GetNextToken();		// Klammer ueberlesen
					}
					else
						nSkip = -1;
				}
				else if( RTF_APOCTL ==
					((nToken = GetNextToken() ) & ~(0xff | RTF_SWGDEFS)) )
				{
                    bReadSwFly = true;      // alles kommt in den akt. Fly
                    SvxLRSpaceItem aLR( RES_LR_SPACE );
                    SvxULSpaceItem aUL( RES_UL_SPACE );
					nCols = USHRT_MAX;		// neu aufsetzen
					nColSpace = USHRT_MAX;
					do {
					nVal = sal_uInt16(nTokenValue);
					switch( nToken )
					{
					// Swg-Frame-Tokens
					case RTF_FLYPRINT:
						{
							pSet->Put( SvxPrintItem( RES_PRINT, sal_False ));
						}
						break;
					case RTF_FLYOPAQUE:
						{
							pSet->Put( SvxOpaqueItem( RES_OPAQUE, sal_False ));
						}
						break;

					case RTF_FLYPRTCTD:
						{
							RTFProtect aP( (sal_uInt8)nTokenValue );
                            SvxProtectItem aProtectItem( RES_PROTECT );
							aProtectItem.SetCntntProtect( aP.GetCntnt() );
							aProtectItem.SetSizeProtect( aP.GetSize() );
							aProtectItem.SetPosProtect( aP.GetPos() );
							pSet->Put( aProtectItem );
						}
						break;

					case RTF_FLYMAINCNT:
						{
							RTFSurround aMC( (sal_uInt8)nTokenValue );
							SwFmtSurround aSurr( (SwSurround)aMC.GetOrder());
							if( aMC.GetGoldCut() )
								aSurr.SetSurround( SURROUND_IDEAL );
							pSet->Put( aSurr );
						}
						break;
					case RTF_FLYVERT:
						{
							RTFVertOrient aVO( nVal );
                            aVert.SetVertOrient( aVO.GetOrient() );
                            aVert.SetRelationOrient( aVO.GetRelation() );
						}
						break;
					case RTF_FLYHORZ:
						{
							RTFHoriOrient aHO( nVal );
                            aHori.SetHoriOrient( aHO.GetOrient() );
                            aHori.SetRelationOrient( aHO.GetRelation() );
						}
						break;
					case RTF_FLYOUTLEFT:		aLR.SetLeft( nVal );		break;
					case RTF_FLYOUTRIGHT:		aLR.SetRight( nVal );		break;
					case RTF_FLYOUTUPPER:		aUL.SetUpper( nVal );		break;
					case RTF_FLYOUTLOWER:		aUL.SetLower( nVal );		break;
					case RTF_FLYANCHOR:
							switch( GetNextToken() )
							{
							case RTF_FLY_PAGE:
                                aAnchor.SetType( FLY_AT_PAGE );
								aAnchor.SetPageNum( sal_uInt16(nTokenValue));
								aAnchor.SetAnchor( 0 );
								break;

							case RTF_FLY_CNTNT:
								{
									SwNodeIndex aIdx( pPam->GetPoint()->nNode );
									pDoc->GetNodes().GoPrevious( &aIdx );
									SwPosition aPos( aIdx );
                                    aAnchor.SetType( FLY_AT_PARA );
									aAnchor.SetAnchor( &aPos );
								}
								break;

// JP 26.09.94: die Bindung an die Spalte gibt es nicht mehr !!
//							case RTF_FLY_COLUMN:
							}
							break;
					case RTF_COLS:	nCols = sal_uInt16( nTokenValue );		break;
					case RTF_COLSX:	nColSpace = sal_uInt16( nTokenValue );	break;
					case RTF_COLNO:
						nAktCol = sal_uInt16( nTokenValue );
						if( RTF_COLW == GetNextToken() )
						{
							sal_uInt16 nWidth = sal_uInt16( nTokenValue ), nSpace = 0;
							if( RTF_COLSR == GetNextToken() )
								nSpace = sal_uInt16( nTokenValue );
							else
								SkipToken( -1 );		// wieder zurueck

							if( --nAktCol == ( aColumns.Count() / 2 ) )
							{
								aColumns.Insert( nWidth + nSpace, aColumns.Count() );
								aColumns.Insert( nSpace, aColumns.Count() );
							}
						}
						break;

					case '{':
						if( RTF_BRDBOX == ( nToken = GetNextToken() ) )
							ReadBorderAttr( nToken, aSet );
						else if( RTF_SHADINGDEF == (nToken & ~0xff ) )
							ReadBackgroundAttr( nToken, aSet );
						else if( RTF_IGNOREFLAG == nToken )
						{
							int bSkipGrp = sal_True;
							switch( nToken = GetNextToken() )
							{
							case RTF_SHADOW:
							case RTF_BRDBOX:
								ReadAttr( SkipToken( -2 ), &aSet );
								bSkipGrp = sal_False;
								break;

							case RTF_BRDRT:
							case RTF_BRDRB:
							case RTF_BRDRR:
							case RTF_BRDRL:
								bSkipGrp = sal_False;
								ReadBorderAttr( SkipToken( -2 ), aSet );
								break;
							}

								// keine weitere Klammer mehr ueberlesen!!!
							if( !bSkipGrp )
								break;

							SkipGroup();
						}
						else
							SkipGroup();
						GetNextToken();		// Klammer ueberlesen
						break;
					}
					} while( IsParserWorking() &&
								'}' != ( nToken = GetNextToken() ));

					if( aUL.GetUpper() || aUL.GetLower() )
						pSet->Put( aUL );
					if( aLR.GetLeft() || aLR.GetRight() )
						pSet->Put( aLR );
				}
				else if( RTF_BRDBOX == nToken )
					ReadBorderAttr( nToken, aSet );
				else if( RTF_SHADOW == nToken )
					ReadAttr( SkipToken( -2 ), &aSet );
				else if( RTF_SHADINGDEF == (nToken & ~0xff ) )
					ReadBackgroundAttr( nToken, aSet );
				else if( RTF_UNKNOWNCONTROL == nToken )
					SkipGroup();
				else
					nSkip = -2;

				if( nSkip )
				{
					nToken = SkipToken( nSkip );
					bWeiter = sal_False;
				}
			}
			break;

		default:
            --nAppliedProps; //Not sufficient to make a frame
			bWeiter = sal_False;
		}

		if( bWeiter )
			nToken = GetNextToken();
	} while( bWeiter && IsParserWorking() );

    pSet->Put( aAnchor );
	pSet->Put( aHori );
	pSet->Put( aVert );

    // --> OD 2004-06-30 #i27767# - set wrapping style influence
    // --> OD 2004-10-18 #i35017# - constant name has changed
    pSet->Put( SwFmtWrapInfluenceOnObjPos(
                    text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ));
    // <--

    SwFmtFollowTextFlow aFollowTextFlow( sal_False );
	pSet->Put( aFollowTextFlow );

	if( !( aFrmDir == pSet->Get( RES_FRAMEDIR )) )
		pSet->Put( aFrmDir );

	if( nCols && USHRT_MAX != nCols )
	{
		SwFmtCol aCol;
		if( USHRT_MAX == nColSpace )
			nColSpace = 720;

		sal_uLong nWidth = USHRT_MAX;
		aCol.Init( nCols, nColSpace, sal_uInt16( nWidth ) );
		if( nCols == ( aColumns.Count() / 2 ) )
		{
			for( sal_uInt16 n = 0, i = 0; n < aColumns.Count(); n += 2, ++i )
			{
				SwColumn* pCol = aCol.GetColumns()[ i ];
				sal_uLong nTmp = aColumns[ n ];
				nTmp *= USHRT_MAX;
				nTmp /= nWidth;
				pCol->SetWishWidth( sal_uInt16(nTmp) );
/*
	JP 07.07.95: der Dialog kennt nur eine Breite fuer alle Spalten
				 darum hier nicht weiter beachten
				nTmp = aColumns[ n+1 ];
				if( nTmp )
					pCol->SetRight( sal_uInt16(nTmp) );
				else
					pCol->SetRight( 0 );
				pCol->SetLeft( 0 );
*/
			}
		}
		pSet->Put( aCol );
	}

	if( pSet != &aSet )			// wurde der Set uebergeben, dann wars das
		return ;

    // ein neues FlyFormat anlegen oder das alte benutzen ?
    // (teste ob es die selben Attribute besitzt!)
    SwFlySave* pFlySave = 0;
    sal_uInt16 nFlyArrCnt = aFlyArr.Count();
    /*
    #i5263#
    There were not enough frame properties found to actually justify creating
    an absolutely positioned frame.
    */
    if (nAppliedProps)
    {
        if( !nFlyArrCnt ||
            !( pFlySave = aFlyArr[ nFlyArrCnt-1 ])->IsEqualFly( *pPam, aSet ))
        {
            pFlySave = new SwFlySave( *pPam, aSet );
            Size aPgSize;
            GetPageSize( aPgSize );
            pFlySave->nPageWidth = aPgSize.Width();

            if( nDropCapAnchor )
            {
                pFlySave->nDropAnchor = nDropCapAnchor;
                pFlySave->nDropLines = nDropCapLines;
            }
            if (nFlyArrCnt >0){
                SwFlySave* pFlySavePrev = aFlyArr[nFlyArrCnt-1];
                if (pFlySave->nSttNd.GetIndex() < pFlySavePrev->nEndNd.GetIndex())
                {
                 	pFlySavePrev->nEndNd=pFlySave->nSttNd;
                }
            }
            aFlyArr.Insert(  pFlySave, nFlyArrCnt++ );
            // --> OD 2008-12-22 #i83368# - reset
            mbReadCellWhileReadSwFly = false;
            // <--
        }
    }

	SetPardTokenRead( sal_False );
	const SwTableNode* pTblNd = pPam->GetNode()->FindTableNode();

	while( !IsPardTokenRead() && IsParserWorking() )
	{
		if( RTF_PARD == nToken || nNumOpenBrakets > GetOpenBrakets() )
			break;

		NextToken( nToken );

		if( !IsPardTokenRead() )
		{
			// #102781#. Added support for transparent frames.
			if (nToken == RTF_CBPAT && nFlyArrCnt > 0)
			{
				sal_uInt16 _index=sal_uInt16(nTokenValue);
				const Color& rColor = GetColor(_index);
                SvxBrushItem aBrush(rColor, RES_BACKGROUND);
				SwFlySave* pFS = aFlyArr[nFlyArrCnt-1];
				pFS->aFlySet.Put(aBrush, RES_BACKGROUND);
			}

			nToken = GetNextToken();

			// BUG 22036: kommt zwischen Fly-Attributen ein unbekanntes,
			//				dann erzeuge nie 2 FlyFrames, sondern fasse
			//				beide zusammen !!!
			while( RTF_APOCTL == ( nToken & ~(0xff | RTF_SWGDEFS) ))
			{
				if( RTF_FLY_INPARA == nToken )
					break;

				if( RTF_IGNOREFLAG == SkipToken( -1 ) )
				{
					if( '{' == SkipToken( -1 ) )
						nToken = '{';
					else
						SkipToken( 2 );
				}
				else
					SkipToken( 1 );

                ReadFly( nToken, pFlySave ? &pFlySave->aFlySet : 0);
				nToken = GetNextToken();
			}
		}
	}

    /*
    #i5263#
    There were enough frame properties found to actually justify creating
    an absolutely positioned frame.
    */
    if (!nAppliedProps)
    {
        bReadSwFly = false;
	    SkipToken( -1 );
        return;
    }

	if( pTblNd && !pPam->GetPoint()->nContent.GetIndex() &&
		pTblNd->EndOfSectionIndex() + 1 ==
			pPam->GetPoint()->nNode.GetIndex() )
	{
		// nicht mehr in der Tabelle, sondern dahinter ?
		// Dann aber wieder zurueck in die Tabelle
		pPam->Move( fnMoveBackward );
	}
	else
		pTblNd = 0;

	// wurde garnichts eingefuegt?
	if( !pTblNd &&
		pPam->GetPoint()->nNode == pFlySave->nSttNd &&
		!pPam->GetPoint()->nContent.GetIndex() )
	{
//		// dann erzeuge mindestens einen leeren TextNode
//		pDoc->AppendTxtNode(*pPam);
		// dann zerstoere den FlySave wieder.
		aFlyArr.DeleteAndDestroy( --nFlyArrCnt );

	}
	else
	{
		sal_Bool bMovePaM = 0 != pTblNd;

		pFlySave->nEndNd = pPam->GetPoint()->nNode;
		pFlySave->nEndCnt = pPam->GetPoint()->nContent.GetIndex();

		if( bMovePaM )
			pPam->Move( fnMoveForward );

		pTblNd = pFlySave->nSttNd.GetNode().FindTableNode();
		if( pTblNd && !pFlySave->nEndCnt &&
			pTblNd == pFlySave->nEndNd.GetNode().FindTableNode() )
		{
			// dann teste mal, ob das \pard nicht zu spaet kam und
			// eigentlich in die vorherige Zelle gehoert
			const SwStartNode* pSttBoxNd = pFlySave->nSttNd.GetNode().
											FindTableBoxStartNode(),
							* pEndBoxNd = pFlySave->nEndNd.GetNode().
											FindTableBoxStartNode();
			if( pSttBoxNd && pEndBoxNd &&
				bMovePaM ? ( pSttBoxNd == pEndBoxNd )
						 : ( pSttBoxNd->EndOfSectionIndex() + 1 ==
								pEndBoxNd->GetIndex() &&
								pEndBoxNd->GetIndex() + 1 ==
								pFlySave->nEndNd.GetIndex() ))
			{
				// dann gehoert das Ende in die vorherige Box!
				SwPosition aPos( *pPam->GetPoint() );
				pPam->GetPoint()->nNode = *pSttBoxNd->EndOfSectionNode();
				pPam->Move( fnMoveBackward, fnGoNode );

				DelLastNode();

				pPam->GetPoint()->nNode = *pSttBoxNd->EndOfSectionNode();
				pPam->Move( fnMoveBackward, fnGoNode );

				pFlySave->nEndNd = pPam->GetPoint()->nNode;
				pFlySave->nEndCnt = pPam->GetPoint()->nContent.GetIndex();

				*pPam->GetPoint() = aPos;
			}
		}
		else if( !bReadSwFly && !pFlySave->nEndCnt &&
			pFlySave->nSttNd.GetIndex() + 1 == pFlySave->nEndNd.GetIndex() &&
			pFlySave->nSttNd.GetNode().IsTxtNode() )
		{

			SwTxtNode* pTxtNd = pFlySave->nSttNd.GetNode().GetTxtNode();
			SwTxtFlyCnt* pFlyCnt = 0;
			if( 1 == pTxtNd->GetTxt().Len() &&
                0 != (pFlyCnt = static_cast<SwTxtFlyCnt*>(
                        pTxtNd->GetTxtAttrForCharAt(0, RES_TXTATR_FLYCNT))) &&
				pFlyCnt->GetFlyCnt().GetFrmFmt() )
			{
				// then move the content into the surrounded fly
				SwFrmFmt* pFlyFmt = pFlyCnt->GetFlyCnt().GetFrmFmt();
				const SwNodeIndex* pFlySNd = pFlyFmt->GetCntnt().GetCntntIdx();
				SwNodeRange aRg( *pFlySNd, 1,
								 *pFlySNd->GetNode().EndOfSectionNode(), 0 );

				// merge the itemsets
				SwFmtFrmSize aSz1( (SwFmtFrmSize&)pFlyFmt->GetAttrSet().
												Get( RES_FRM_SIZE ));
				SwFmtFrmSize aSz2( (SwFmtFrmSize&)pFlySave->aFlySet.
												Get( RES_FRM_SIZE ));
				// if
				if( !aRg.aStart.GetNode().IsNoTxtNode() ||
					!aSz1.GetHeight() || !aSz1.GetWidth() ||
					!aSz2.GetHeight() || !aSz2.GetWidth() ||
					( aSz1.GetHeight() == aSz2.GetHeight() &&
					  aSz1.GetWidth() == aSz2.GetWidth() ) )
				{
					SfxItemSet aDiffs( pFlyFmt->GetAttrSet() );
					aDiffs.ClearItem( RES_ANCHOR );
					aDiffs.ClearItem( RES_FRM_SIZE );
					aDiffs.ClearItem( RES_CNTNT );
					aDiffs.Differentiate( pFlySave->aFlySet );
					pFlySave->aFlySet.Put( aDiffs );

					sal_Bool bSet = sal_False;
					if( aSz1.GetHeight() && !aSz2.GetHeight() )
					{
						bSet = sal_True;
						aSz2.SetHeight( aSz1.GetHeight() );
					}
					if( aSz1.GetWidth() && !aSz2.GetWidth() )
					{
						bSet = sal_True;
						aSz2.SetWidth( aSz1.GetWidth() );
					}
					if( bSet )
						pFlySave->aFlySet.Put( aSz2 );

					// move any PageBreak/Desc Attr to the next Para
					{
						SwCntntNode* pSrcNd = pFlySave->nSttNd.GetNode().GetCntntNode();
						SwCntntNode* pDstNd = pFlySave->nEndNd.GetNode().GetCntntNode();

						::lcl_CpyBreakAttrs( pSrcNd, pDstNd, &pFlySave->nEndNd );
					}

					// create new txtnode, because the section does never be empty
					pDoc->GetNodes().MakeTxtNode( aRg.aStart,
								(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );

					SwNodeIndex aTmp( pFlySave->nSttNd, +1 );
                    pDoc->MoveNodeRange( aRg, aTmp,
                            IDocumentContentOperations::DOC_MOVEDEFAULT );

					// now delete the redundant txtnode
					pDoc->GetNodes().Delete( pFlySave->nSttNd, 1 );
				}
			}
		}
	}

    bReadSwFly = false;
	SkipToken( -1 );
}


void SwRTFParser::InsPicture( const String& rGrfNm, const Graphic* pGrf,
								const SvxRTFPictureType* pPicType )
{
	// kennzeichen fuer Swg-Dokumente:
	// (dann ist das FlyFmt fuer die Grafik!)
	SwGrfNode * pGrfNd;
    // --> OD 2008-12-22 #i83368#
    // Assure that graphic node is enclosed by fly frame node.
//    if( bReadSwFly )
    if ( bReadSwFly && !mbReadCellWhileReadSwFly )
    // <--
	{
        OSL_ENSURE(aFlyArr.Count(),
            "SwRTFParser::InsPicture: fly array empty.");
        if (aFlyArr.Count())
        {
		    // erzeuge nur einen normalen GrafikNode und ersetze diesen gegen
		    // den vorhandenen Textnode
		    SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
		    pGrfNd = pDoc->GetNodes().MakeGrfNode( rIdx,
					    rGrfNm, aEmptyStr,    // Name der Graphic !!
					    pGrf,
					    (SwGrfFmtColl*)pDoc->GetDfltGrfFmtColl() );

		    if( pGrfAttrSet )
			    pGrfNd->SetAttr( *pGrfAttrSet );

		    SwFlySave* pFlySave = aFlyArr[ aFlyArr.Count()-1 ];
		    pFlySave->nSttNd = rIdx.GetIndex() - 1;

		    if( 1 < aFlyArr.Count() )
		    {
			    pFlySave = aFlyArr[ aFlyArr.Count() - 2 ];
			    if( pFlySave->nEndNd == rIdx )
				    pFlySave->nEndNd = rIdx.GetIndex() - 1;
		    }
        }
	}
	else
	{
		// wenn normale RTF-Grafik, dann steht diese im Textfluss !
		SwAttrSet aFlySet( pDoc->GetAttrPool(), RES_OPAQUE, /*RES_OPAQUE,
												RES_VERT_ORIENT,*/ RES_ANCHOR );
		const SwPosition* pPos = pPam->GetPoint();

        SwFmtAnchor aAnchor( FLY_AS_CHAR );
		aAnchor.SetAnchor( pPos );
		aFlySet.Put( aAnchor );
        aFlySet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP ));

		if (pDoc->IsInHeaderFooter(pPos->nNode))
		{
			SvxOpaqueItem aOpaqueItem(RES_OPAQUE, sal_False);
			SwFmtSurround aSurroundItem(SURROUND_THROUGHT);
			aFlySet.Put(aOpaqueItem);
			aFlySet.Put(aSurroundItem);
		}

        SwFlyFrmFmt* pFlyFmt = pDoc->Insert( *pPam,
					rGrfNm, aEmptyStr,		// Name der Graphic !!
					pGrf,
					&aFlySet,				// Attribute fuer den FlyFrm
					pGrfAttrSet, NULL );			// Attribute fuer die Grafik

		pGrfNd = pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx()->
											GetIndex()+1 ]->GetGrfNode();

		_SetPictureSize( *pGrfNd, pPos->nNode,
						(SfxItemSet&)pFlyFmt->GetAttrSet(),
						pPicType );
        if( pPicType )
        {
            PictPropertyNameValuePairs::const_iterator aIt = pPicType->aPropertyPairs.begin();
            PictPropertyNameValuePairs::const_iterator aEnd = pPicType->aPropertyPairs.end();
            while( aIt != aEnd)
            {
                if( aIt->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "wzDescription") ))
                {
                    SwXFrame::GetOrCreateSdrObject( pFlyFmt );
                    pDoc->SetFlyFrmDescription( *(pFlyFmt), aIt->second );
                }
                else if( aIt->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "wzName") ))
                {
                    SwXFrame::GetOrCreateSdrObject( pFlyFmt );
                    pDoc->SetFlyFrmTitle( *(pFlyFmt), aIt->second );
                }
                ++aIt;
            }
        }

    }

	if( pGrfAttrSet )
		DELETEZ( pGrfAttrSet );
}

void SwRTFParser::_SetPictureSize( const SwNoTxtNode& rNd,
									const SwNodeIndex& rAnchor,
									SfxItemSet& rSet,
									const SvxRTFPictureType* pPicType )
{
	Size aSize( ((SwNoTxtNode&)rNd).GetTwipSize() );
	if( pPicType )
	{
		if( rNd.IsGrfNode() )
		{
			if( SvxRTFPictureType::WIN_METAFILE != pPicType->eStyle &&
				pPicType->nGoalWidth && pPicType->nGoalHeight )
			{
				aSize.Width() = pPicType->nGoalWidth;
				aSize.Height() =pPicType->nGoalHeight;
			}
			else if( SvxRTFPictureType::MAC_QUICKDRAW == pPicType->eStyle )
			{
				// IMMER auf 72 DPI bezogen, also 1pt == 20 Twip !!
				aSize.Width() = pPicType->nWidth * 20;
				aSize.Height() = pPicType->nHeight * 20;
			}
			else
			{
				// von 100TH_MM nach TWIP umrechenen!
				// #117879# when \picwgoal resp \pichgoal are present, then use them.
				//          The values of \picwgoal and \picwgoal are already given in twips.
				aSize.Width() = (pPicType->nGoalWidth?pPicType->nGoalWidth:(pPicType->nWidth*144)/254);
				aSize.Height() = (pPicType->nGoalHeight?pPicType->nGoalHeight:(pPicType->nHeight*144)/254);
			}
			((SwGrfNode&)rNd).SetTwipSize( aSize );
		}

		if( 100 != pPicType->nScalX )
			aSize.Width() = (((long)pPicType->nScalX) * ( aSize.Width() -
						( pPicType->nCropL + pPicType->nCropR ))) / 100L;

		if( 100 != pPicType->nScalY )
			aSize.Height() = (((long)pPicType->nScalY) * ( aSize.Height() -
						( pPicType->nCropT + pPicType->nCropB ))) / 100L;
	}

	//steht der Fly etwa in einer Tabelle ?
    const SwNode* pAnchorNd = & rAnchor.GetNode();
	const SwTableNode* pTblNd = pAnchorNd->FindTableNode();
	if( pTblNd )
	{
		// Box feststellen:
		const SwTableBox* pBox = pTblNd->GetTable().GetTblBox(
								pAnchorNd->StartOfSectionIndex() );
		if( pBox )
		{
			long nBoxWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
			if( aSize.Width() > nBoxWidth )
				aSize.Width() = nBoxWidth;
		}
	}

	//JP 8.11.2001: bug 94450 - if no size exist, then the size is set by
	//				the swapin of the graphic.
	SwGrfNode* pGrfNd;
	if( !aSize.Width() && !aSize.Height() &&
		0 != (pGrfNd = (SwGrfNode*)rNd.GetGrfNode() ) && pGrfNd->IsGrfLink() )
		pGrfNd->SetChgTwipSize( sal_True );

		// min. Werte einhalten !!
	if( aSize.Width() < MINFLY )
		aSize.Width() = MINFLY;
	if( aSize.Height() < MINFLY)
		aSize.Height() = MINFLY;

	if( pPicType )
	{
		sal_Bool bChg = sal_False;
		SwCropGrf aCrop;

/*
 JP 28.07.99: Bug 67800 - no crop by MAC_QUICKDRAW. At time i dont know why
							it has been coded. But this has used for any
							RTF-File, but i dont found them.
		if( SvxRTFPictureType::MAC_QUICKDRAW == pPicType->eStyle )
		{
			// evt. ein wenig Croppen ??
			// IMMER auf 72 DPI bezogen, also 1pt == 20 Twip !!
			long nTmp = pPicType->nWidth * 20;
			if( nTmp != aSize.Width() )
			{
				// in der Breite (also rechts) croppen
				aCrop.Right() = nTmp - aSize.Width();
				aSize.Width() = nTmp;
				bChg = sal_True;
			}

			nTmp = pPicType->nHeight * 20;
			if( nTmp != aSize.Height() )
			{
				// in der Hoehe (also unten) croppen
				aCrop.Bottom() = nTmp - aSize.Height();
				aSize.Height() = nTmp;
				bChg = sal_True;
			}
		}
*/
		if( pPicType->nCropT )
		{
			aCrop.SetTop( pPicType->nCropT );
			bChg = sal_True;
		}
		if( pPicType->nCropB )
		{
			aCrop.SetBottom( pPicType->nCropB );
			bChg = sal_True;
		}
		if( pPicType->nCropL )
		{
			aCrop.SetLeft( pPicType->nCropL );
			bChg = sal_True;
		}
		if( pPicType->nCropR )
		{
			aCrop.SetRight( pPicType->nCropR );
			bChg = sal_True;
		}

		if( bChg )
		{
			// dann mal an die CropWerte an die GrafikSize anpassen.
			((SwNoTxtNode&)rNd).SetAttr( aCrop );
		}
	}
	rSet.Put( SwFmtFrmSize( ATT_FIX_SIZE, aSize.Width(), aSize.Height() ));
}

void SwRTFParser::GetPageSize( Size& rSize )
{
    ASSERT(!maSegments.empty(), "not possible");
    if (maSegments.empty())
    {
        rSize.Width() = 12240 - 1800 - 1800;
        rSize.Height() = 15840 - 1440 - 1440;
        return;
    }

    const rtfSection &rSect = maSegments.back();

	rSize.Width() = rSect.maPageInfo.mnPgwsxn - rSect.maPageInfo.mnMarglsxn - rSect.maPageInfo.mnMargrsxn;
	rSize.Height() = rSect.maPageInfo.mnPghsxn - rSect.maPageInfo.mnMargtsxn - rSect.maPageInfo.mnMargbsxn;

    long nCols = rSect.NoCols();
	if (1 < nCols)
	{
		rSize.Width() /= nCols;
		rSize.Height() /= nCols;
	}
}

void SwRTFParser::ReadBitmapData()
{
	Graphic aGrf;
	SvxRTFPictureType aPicType;
	if( ReadBmpData( aGrf, aPicType ) )
		InsPicture( aEmptyStr, &aGrf, &aPicType );
}

#ifdef READ_OLE_OBJECT
void SwRTFParser::ReadOLEData()
{
	SvCacheStream aTmpFile( 0xA000 );
	Graphic aGrf;
	SvxRTFPictureType aPicType, aOleType;

	int nToken, bValidOle = sal_True, bWeiter = sal_True;
	int nOpenBrakets = 1;		// die erste wurde schon vorher erkannt !!

	String* pStr = 0;
	String sObjClass, sObjName, sObjData;

	while( nOpenBrakets && IsParserWorking() && bWeiter && bValidOle )
	{
		nToken = GetNextToken();
		sal_uInt16 nVal = sal_uInt16( nTokenValue );
		switch( nToken )
		{
		case '}':		--nOpenBrakets;	pStr = 0; break;
		case '{':
			{
				if( RTF_IGNOREFLAG != GetNextToken() )
					nToken = SkipToken( -1 );
				else if( RTF_UNKNOWNCONTROL != GetNextToken() )
					nToken = SkipToken( -2 );
				else
				{
					// gleich herausfiltern
					ReadUnknownData();
					nToken = GetNextToken();
					if( '}' != nToken )
						eState = SVPAR_ERROR;
					break;
				}
				++nOpenBrakets;
			}
			break;

		case RTF_OBJECT:
		case RTF_OBJEMB:		// default ist embedded
		case RTF_LINKSELF:		// ??
		case RTF_OBJLOCK:		// ??
		case RTF_OBJUPDATE:		// ??
		case RTF_OBJTIME:		// ??
		case RTF_OBJSETSIZE:
		case RTF_OBJALIGN:
		case RTF_OBJTRANSY:
		case RTF_OBJATTPH:
			break;

		case RTF_OBJLINK:		// ?? welche Daten sind das ??
		case RTF_OBJAUTLINK:	// ??       -""-            ??
		case RTF_OBJSUB:
		case RTF_OBJPUB:
		case RTF_OBJICEMB:
		case RTF_OBJOCX:
		case RTF_OBJHTML:
		case RTF_OBJALIAS:
		case RTF_OBJSECT:
			bValidOle = sal_False;		// diese Typen koennen wir nicht
			break;

		case RTF_OBJCLASS:
			// Daten lesen
			pStr = &sObjClass;
			break;

		case RTF_OBJNAME:
			// Daten lesen
			pStr = &sObjName;
			break;

		case RTF_OBJDATA:
			pStr = &sObjData;
			break;

		case RTF_RESULT:
			{
				// hier weitermachen, wenn das OLE-Object ungueltig ist
				bWeiter = sal_False;
			}
			break;
		case RTF_RSLTBMP:			// diese sollten wir ignorieren
		case RTF_RSLTMERGE:
		case RTF_RSLTPICT:
		case RTF_RSLTRTF:
		case RTF_RSLTTXT:
			break;

		case RTF_OBJW:			aOleType.nWidth = nVal; break;
		case RTF_OBJH:			aOleType.nHeight = nVal; break;
		case RTF_OBJCROPT:		aOleType.nCropT = (short)nTokenValue; break;
		case RTF_OBJCROPB:		aOleType.nCropB = (short)nTokenValue; break;
		case RTF_OBJCROPL:		aOleType.nCropL = (short)nTokenValue; break;
		case RTF_OBJCROPR:		aOleType.nCropR = (short)nTokenValue; break;
		case RTF_OBJSCALEX:		aOleType.nScalX = nVal; break;
		case RTF_OBJSCALEY:		aOleType.nScalY = nVal; break;

		case RTF_TEXTTOKEN:
			if( 1 < nOpenBrakets && pStr )
			{
				if( pStr == &sObjData )
				{
					xub_StrLen nHexLen = HexToBin( aToken );
					if( STRING_NOTFOUND != nHexLen )
						bValidOle = sal_False;
					else
					{
						aTmpFile.Write( (sal_Char*)aToken.GetBuffer(), nHexLen );
						bValidOle = 0 == aTmpFile.GetError();
					}
				}
				else
					*pStr += aToken;
			}
			break;
		}
	}

	if( bValidOle )
	{
		bValidOle = sal_False; 		// erstmal
	}

	if( !bWeiter )		// dann stehen wir noch im Result
	{
		// ist das Ole-Object Ok?
		// -> dann solange SkipGroup rufen, bis zur letzten
		//		schliessenden Klammer
		// ansonsten alle Token verarbeiten, bis zur letzten
		//		schliessenden Klammer

		bWeiter = sal_True;
		while( nOpenBrakets && IsParserWorking() && bWeiter )
		{
			switch( nToken = GetNextToken() )
			{
			case '}':		--nOpenBrakets; break;
			case '{':		++nOpenBrakets;	 break;
			}
			if( nOpenBrakets && !bValidOle )
				NextToken( nToken );
		}
	}

	if( !bValidOle && '}' != nToken )
		SkipGroup();

	SkipToken( -1 );		// die schliesende Klammer wird "oben" ausgewertet
}
#endif

/* vi:set tabstop=4 shiftwidth=4 expandtab: */
