/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/


#ifdef _MSC_VER
#pragma hdrstop
#endif

#include "eeitem.hxx"
#include "eeitemid.hxx"

#include <tstpitem.hxx>
#include <fontitem.hxx>
#include <crsditem.hxx>
#include <fhgtitem.hxx>
#include <postitem.hxx>
#include <kernitem.hxx>
#include <wrlmitem.hxx>
#include <wghtitem.hxx>
#include <udlnitem.hxx>
#include <cntritem.hxx>
#include <escpitem.hxx>
#include <shdditem.hxx>
#include <akrnitem.hxx>
#include <cscoitem.hxx>
#include <langitem.hxx>
#include <emphitem.hxx>
#include <charreliefitem.hxx>

#include <vcl/outdev.hxx>

#include <editdoc.hxx>
#include <eerdll.hxx>
#include <eerdll2.hxx>

#include <tools/stream.hxx>

#include <tools/shl.hxx>

#include <com/sun/star/i18n/ScriptType.hpp>

#include <stdlib.h> // qsort
namespace binfilter {

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


// ------------------------------------------------------------

/*N*/ USHORT GetScriptItemId( USHORT nItemId, short nScriptType )
/*N*/ {
/*N*/   USHORT nId = nItemId;
/*N*/
/*N*/   if ( ( nScriptType == i18n::ScriptType::ASIAN ) ||
/*N*/        ( nScriptType == i18n::ScriptType::COMPLEX ) )
/*N*/   {
/*N*/       switch ( nItemId )
/*N*/       {
/*N*/           case EE_CHAR_LANGUAGE:
/*N*/               nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL;
/*N*/           break;
/*N*/           case EE_CHAR_FONTINFO:
/*N*/               nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL;
/*N*/           break;
/*N*/           case EE_CHAR_FONTHEIGHT:
/*N*/               nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL;
/*N*/           break;
/*N*/           case EE_CHAR_WEIGHT:
/*N*/               nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL;
/*N*/           break;
/*N*/           case EE_CHAR_ITALIC:
/*N*/               nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL;
/*N*/           break;
/*N*/       }
/*N*/   }
/*N*/
/*N*/   return nId;
/*N*/ }

/*N*/ BOOL IsScriptItemValid( USHORT nItemId, short nScriptType )
/*N*/ {
/*N*/   BOOL bValid = TRUE;
/*N*/
/*N*/   switch ( nItemId )
/*N*/   {
/*N*/       case EE_CHAR_LANGUAGE:
/*N*/           bValid = nScriptType == i18n::ScriptType::LATIN;
/*N*/       break;
/*N*/       case EE_CHAR_LANGUAGE_CJK:
/*N*/           bValid = nScriptType == i18n::ScriptType::ASIAN;
/*N*/       break;
/*N*/       case EE_CHAR_LANGUAGE_CTL:
/*N*/           bValid = nScriptType == i18n::ScriptType::COMPLEX;
/*N*/       break;
/*N*/       case EE_CHAR_FONTINFO:
/*N*/           bValid = nScriptType == i18n::ScriptType::LATIN;
/*N*/       break;
/*N*/       case EE_CHAR_FONTINFO_CJK:
/*N*/           bValid = nScriptType == i18n::ScriptType::ASIAN;
/*N*/       break;
/*N*/       case EE_CHAR_FONTINFO_CTL:
/*N*/           bValid = nScriptType == i18n::ScriptType::COMPLEX;
/*N*/       break;
/*N*/       case EE_CHAR_FONTHEIGHT:
/*N*/           bValid = nScriptType == i18n::ScriptType::LATIN;
/*N*/       break;
/*N*/       case EE_CHAR_FONTHEIGHT_CJK:
/*N*/           bValid = nScriptType == i18n::ScriptType::ASIAN;
/*N*/       break;
/*N*/       case EE_CHAR_FONTHEIGHT_CTL:
/*N*/           bValid = nScriptType == i18n::ScriptType::COMPLEX;
/*N*/       break;
/*N*/       case EE_CHAR_WEIGHT:
/*N*/           bValid = nScriptType == i18n::ScriptType::LATIN;
/*N*/       break;
/*N*/       case EE_CHAR_WEIGHT_CJK:
/*N*/           bValid = nScriptType == i18n::ScriptType::ASIAN;
/*N*/       break;
/*N*/       case EE_CHAR_WEIGHT_CTL:
/*N*/           bValid = nScriptType == i18n::ScriptType::COMPLEX;
/*N*/       break;
/*N*/       case EE_CHAR_ITALIC:
/*N*/           bValid = nScriptType == i18n::ScriptType::LATIN;
/*N*/       break;
/*N*/       case EE_CHAR_ITALIC_CJK:
/*N*/           bValid = nScriptType == i18n::ScriptType::ASIAN;
/*N*/       break;
/*N*/       case EE_CHAR_ITALIC_CTL:
/*N*/           bValid = nScriptType == i18n::ScriptType::COMPLEX;
/*N*/       break;
/*N*/   }
/*N*/
/*N*/   return bValid;
/*N*/ }


// ------------------------------------------------------------

// Sollte spaeter zentral nach TOOLS/STRING (Aktuell: 303)
// fuer Grep: WS_TARGET

/*N*/ DBG_NAME( EE_TextPortion )
/*N*/ DBG_NAME( EE_EditLine )
/*N*/ DBG_NAME( EE_ContentNode )
/*N*/ DBG_NAME( EE_CharAttribList )

/*N*/ SfxItemInfo aItemInfos[EDITITEMCOUNT] = {
/*N*/       { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE },         // EE_PARA_WRITINGDIR
/*N*/       { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_XMLATTRIBS
/*N*/       { SID_ATTR_PARA_HANGPUNCTUATION, SFX_ITEM_POOLABLE },   // EE_PARA_HANGINGPUNCTUATION
/*N*/       { SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_PARA_SCRIPTSPACE, SFX_ITEM_POOLABLE },       // EE_PARA_ASIANCJKSPACING
/*N*/       { SID_ATTR_NUMBERING_RULE, SFX_ITEM_POOLABLE },         // EE_PARA_NUMBULL
/*N*/       { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_HYPHENATE
/*N*/       { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_BULLETSTATE
/*N*/       { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_OUTLLRSPACE
/*N*/       { SID_ATTR_PARA_OUTLLEVEL, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE },
/*N*/         { SID_ATTR_CHAR_SCALEWIDTH, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_ESCAPEMENT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_AUTOKERN, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_KERNING, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE },
/*N*/       { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE },
/*N*/       { 0, SFX_ITEM_POOLABLE },                           // EE_CHAR_RUBI_DUMMY
/*N*/       { 0, SFX_ITEM_POOLABLE },                           // EE_CHAR_XMLATTRIBS
/*N*/       { 0, SFX_ITEM_POOLABLE },                           // EE_FEATURE_TAB
/*N*/       { 0, SFX_ITEM_POOLABLE },                           // EE_FEATURE_LINEBR
/*N*/       { SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEM_POOLABLE },  // EE_FEATURE_NOTCONV
/*N*/       { SID_FIELD, SFX_ITEM_POOLABLE }
/*N*/ };

/*N*/ USHORT aV1Map[] = {
/*N*/   3999, 4001, 4002, 4003, 4004, 4005, 4006,
/*N*/   4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019?
/*N*/ };

/*N*/ USHORT aV2Map[] = {
/*N*/   3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009,
/*N*/   4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020
/*N*/ };

/*N*/ USHORT aV3Map[] = {
/*N*/   3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007,
/*N*/   4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019,
/*N*/   4020, 4021
/*N*/ };

/*N*/ USHORT aV4Map[] = {
/*N*/   3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
/*N*/   4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
/*N*/   4014, 4015, 4016, 4017, 4018,
/*N*/   /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */
/*N*/   4034, 4035, 4036, 4037
/*N*/ };

/*N*/ SV_IMPL_PTRARR( ContentList, ContentNode* );
/*N*/ SV_IMPL_VARARR( ScriptTypePosInfos, ScriptTypePosInfo );
/*N*/ SV_IMPL_VARARR( WritingDirectionInfos, WritingDirectionInfo );
// SV_IMPL_VARARR( ExtraCharInfos, ExtraCharInfo );


/*N*/ int SAL_CALL CompareStart( const void* pFirst, const void* pSecond )
/*N*/ {
/*N*/   if ( (*((EditCharAttrib**)pFirst))->GetStart() < (*((EditCharAttrib**)pSecond))->GetStart() )
/*N*/       return (-1);
/*N*/   else if ( (*((EditCharAttrib**)pFirst))->GetStart() > (*((EditCharAttrib**)pSecond))->GetStart() )
/*N*/       return (1);
/*N*/   return 0;
/*N*/ }

/*N*/ EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, USHORT nS, USHORT nE )
/*N*/ {
/*N*/   // das neue Attribut im Pool anlegen
/*N*/   const SfxPoolItem& rNew = rPool.Put( rAttr );
/*N*/
/*N*/   EditCharAttrib* pNew = 0;
/*N*/   switch( rNew.Which() )
/*N*/   {
/*N*/       case EE_CHAR_LANGUAGE:
/*N*/       case EE_CHAR_LANGUAGE_CJK:
/*N*/       case EE_CHAR_LANGUAGE_CTL:
/*N*/       {
/*N*/           pNew = new EditCharAttribLanguage( (const SvxLanguageItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_COLOR:
/*N*/       {
/*N*/           pNew = new EditCharAttribColor( (const SvxColorItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_FONTINFO:
/*N*/       case EE_CHAR_FONTINFO_CJK:
/*N*/       case EE_CHAR_FONTINFO_CTL:
/*N*/       {
/*N*/           pNew = new EditCharAttribFont( (const SvxFontItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_FONTHEIGHT:
/*N*/       case EE_CHAR_FONTHEIGHT_CJK:
/*N*/       case EE_CHAR_FONTHEIGHT_CTL:
/*N*/       {
/*N*/           pNew = new EditCharAttribFontHeight( (const SvxFontHeightItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_FONTWIDTH:
/*N*/       {
/*N*/           pNew = new EditCharAttribFontWidth( (const SvxCharScaleWidthItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_WEIGHT:
/*N*/       case EE_CHAR_WEIGHT_CJK:
/*N*/       case EE_CHAR_WEIGHT_CTL:
/*N*/       {
/*N*/           pNew = new EditCharAttribWeight( (const SvxWeightItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_UNDERLINE:
/*N*/       {
/*N*/           pNew = new EditCharAttribUnderline( (const SvxUnderlineItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_EMPHASISMARK:
/*N*/       {
/*N*/           pNew = new EditCharAttribEmphasisMark( (const SvxEmphasisMarkItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_RELIEF:
/*N*/       {
/*N*/           pNew = new EditCharAttribRelief( (const SvxCharReliefItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_STRIKEOUT:
/*N*/       {
/*N*/           pNew = new EditCharAttribStrikeout( (const SvxCrossedOutItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_ITALIC:
/*N*/       case EE_CHAR_ITALIC_CJK:
/*N*/       case EE_CHAR_ITALIC_CTL:
/*N*/       {
/*N*/           pNew = new EditCharAttribItalic( (const SvxPostureItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_OUTLINE:
/*N*/       {
/*N*/           pNew = new EditCharAttribOutline( (const SvxContourItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_SHADOW:
/*N*/       {
/*N*/           pNew = new EditCharAttribShadow( (const SvxShadowedItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_ESCAPEMENT:
/*N*/       {
/*N*/           pNew = new EditCharAttribEscapement( (const SvxEscapementItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_PAIRKERNING:
/*N*/       {
/*N*/           pNew = new EditCharAttribPairKerning( (const SvxAutoKernItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_KERNING:
/*N*/       {
/*N*/           pNew = new EditCharAttribKerning( (const SvxKerningItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_WLM:
/*N*/       {
/*N*/           pNew = new EditCharAttribWordLineMode( (const SvxWordLineModeItem&)rNew, nS, nE );
/*N*/       }
/*N*/       break;
/*N*/       case EE_CHAR_XMLATTRIBS:
/*N*/       {
/*?*/           pNew = new EditCharAttrib( rNew, nS, nE );  // Attrib is only for holding XML information...
/*N*/       }
/*N*/       break;
/*N*/       case EE_FEATURE_TAB:
/*N*/       {
/*N*/           pNew = new EditCharAttribTab( (const SfxVoidItem&)rNew, nS );
/*N*/       }
/*N*/       break;
/*N*/       case EE_FEATURE_LINEBR:
/*N*/       {
/*N*/           pNew = new EditCharAttribLineBreak( (const SfxVoidItem&)rNew, nS );
/*N*/       }
/*N*/       break;
/*N*/       case EE_FEATURE_FIELD:
/*N*/       {
/*N*/           pNew = new EditCharAttribField( (const SvxFieldItem&)rNew, nS );
/*N*/       }
/*N*/       break;
/*N*/       default:
/*N*/       {
/*N*/           OSL_FAIL( "Ungueltiges Attribut!" );
/*N*/       }
/*N*/   }
/*N*/   return pNew;
/*N*/ }

// -------------------------------------------------------------------------
// class EditLine
// -------------------------------------------------------------------------

/*N*/ EditLine::EditLine()
/*N*/ {
/*N*/   DBG_CTOR( EE_EditLine, 0 );
/*N*/
/*N*/   nStart = nEnd = 0;
/*N*/   nStartPortion = 0;              // damit in ungueltiger Zeile ohne Portions von einer gueltigen Zeile mit der Portion Nr0 unterscieden werden kann.
/*N*/   nEndPortion = 0;
/*N*/   nHeight = 0;
/*N*/   nStartPosX = 0;
/*N*/   nTxtHeight = 0;
/*N*/     nTxtWidth = 0;
/*N*/   nCrsrHeight = 0;
/*N*/   nMaxAscent = 0;
/*N*/   bHangingPunctuation = FALSE;
/*N*/   bInvalid = TRUE;
/*N*/ }

/*N*/ EditLine::EditLine( const EditLine& r )
/*N*/ {
/*N*/   DBG_CTOR( EE_EditLine, 0 );
/*N*/
/*N*/   nEnd = r.nEnd;
/*N*/   nStart = r.nStart;
/*N*/   nStartPortion = r.nStartPortion;
/*N*/   nEndPortion = r.nEndPortion;
/*N*/   bHangingPunctuation = r.bHangingPunctuation;
/*N*/
/*N*/   nHeight = 0;
/*N*/   nStartPosX = 0;
/*N*/   nTxtHeight = 0;
/*N*/     nTxtWidth = 0;
/*N*/   nCrsrHeight = 0;
/*N*/   nMaxAscent = 0;
/*N*/   bInvalid = TRUE;
/*N*/ }

/*N*/ EditLine::~EditLine()
/*N*/ {
/*N*/   DBG_DTOR( EE_EditLine, 0 );
/*N*/ }


/*N*/ BOOL operator == ( const EditLine& r1,  const EditLine& r2  )
/*N*/ {
/*N*/   if ( r1.nStart != r2.nStart )
/*N*/       return FALSE;
/*N*/
/*N*/   if ( r1.nEnd != r2.nEnd )
/*N*/       return FALSE;
/*N*/
/*N*/   if ( r1.nStartPortion != r2.nStartPortion )
/*N*/       return FALSE;
/*N*/
/*N*/   if ( r1.nEndPortion != r2.nEndPortion )
/*N*/       return FALSE;
/*N*/
/*N*/   return TRUE;
/*N*/ }

/*N*/ EditLine& EditLine::operator = ( const EditLine& r )
/*N*/ {
/*N*/   nEnd = r.nEnd;
/*N*/   nStart = r.nStart;
/*N*/   nEndPortion = r.nEndPortion;
/*N*/   nStartPortion = r.nStartPortion;
/*N*/   return *this;
/*N*/ }



/*N*/ Size EditLine::CalcTextSize( ParaPortion& rParaPortion )
/*N*/ {
/*N*/   Size aSz;
/*N*/   Size aTmpSz;
/*N*/   TextPortion* pPortion;
/*N*/
/*N*/   USHORT nIndex = GetStart();
/*N*/
/*N*/   DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize vor CreatePortions !" );
/*N*/
/*N*/   for ( USHORT n = nStartPortion; n <= nEndPortion; n++ )
/*N*/   {
/*N*/       pPortion = rParaPortion.GetTextPortions().GetObject(n);
/*N*/       switch ( pPortion->GetKind() )
/*N*/       {
/*N*/           case PORTIONKIND_TEXT:
/*N*/           case PORTIONKIND_FIELD:
/*N*/           case PORTIONKIND_HYPHENATOR:
/*N*/           {
/*N*/               aTmpSz = pPortion->GetSize();
/*N*/               aSz.Width() += aTmpSz.Width();
/*N*/               if ( aSz.Height() < aTmpSz.Height() )
/*N*/                   aSz.Height() = aTmpSz.Height();
/*N*/           }
/*N*/           break;
/*N*/           case PORTIONKIND_TAB:
/*N*/ //            case PORTIONKIND_EXTRASPACE:
/*N*/           {
/*N*/               aSz.Width() += pPortion->GetSize().Width();
/*N*/           }
/*N*/           break;
/*N*/       }
/*N*/       nIndex += pPortion->GetLen();
/*N*/   }
/*N*/
/*N*/   SetHeight( (USHORT)aSz.Height() );
/*N*/   return aSz;
/*N*/ }

// -------------------------------------------------------------------------
// class EditLineList
// -------------------------------------------------------------------------
/*N*/ EditLineList::EditLineList()
/*N*/ {
/*N*/ }

/*N*/ EditLineList::~EditLineList()
/*N*/ {
/*N*/   Reset();
/*N*/ }

/*N*/ void EditLineList::Reset()
/*N*/ {
/*N*/   for ( USHORT nLine = 0; nLine < Count(); nLine++ )
/*N*/       delete GetObject(nLine);
/*N*/   Remove( 0, Count() );
/*N*/ }

/*N*/ void EditLineList::DeleteFromLine( USHORT nDelFrom )
/*N*/ {
/*N*/   DBG_ASSERT( nDelFrom <= (Count() - 1), "DeleteFromLine: Out of range" );
/*N*/   for ( USHORT nL = nDelFrom; nL < Count(); nL++ )
/*N*/       delete GetObject(nL);
/*N*/   Remove( nDelFrom, Count()-nDelFrom );
/*N*/ }


// -------------------------------------------------------------------------
// class EditSelection
// -------------------------------------------------------------------------

/*N*/ EditSelection::EditSelection()
/*N*/ {
/*N*/ }

/*N*/ EditSelection::EditSelection( const EditPaM& rStartAndAnd )
/*N*/ {
/*N*/   // koennte noch optimiert werden!
/*N*/   // nicht erst Def-CTOR vom PaM rufen!
/*N*/   aStartPaM = rStartAndAnd;
/*N*/   aEndPaM = rStartAndAnd;
/*N*/ }

/*N*/ EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd )
/*N*/ {
/*N*/   // koennte noch optimiert werden!
/*N*/   aStartPaM = rStart;
/*N*/   aEndPaM = rEnd;
/*N*/ }

/*N*/ EditSelection& EditSelection::operator = ( const EditPaM& rPaM )
/*N*/ {
/*N*/   aStartPaM = rPaM;
/*N*/   aEndPaM = rPaM;
/*N*/   return *this;
/*N*/ }

/*N*/ BOOL EditSelection::Adjust( const ContentList& rNodes )
/*N*/ {
/*N*/   DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in Adjust(1)" );
/*N*/   DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in Adjust(2)" );
/*N*/
/*N*/   ContentNode* pStartNode = aStartPaM.GetNode();
/*N*/   ContentNode* pEndNode = aEndPaM.GetNode();
/*N*/
/*N*/   USHORT nStartNode = rNodes.GetPos( pStartNode );
/*N*/   USHORT nEndNode = rNodes.GetPos( pEndNode );
/*N*/
/*N*/   DBG_ASSERT( nStartNode != USHRT_MAX, "Node im Wald in Adjust(1)" );
/*N*/   DBG_ASSERT( nEndNode != USHRT_MAX, "Node im Wald in Adjust(2)" );
/*N*/
/*N*/   BOOL bSwap = FALSE;
/*N*/   if ( nStartNode > nEndNode )
/*N*/       bSwap = TRUE;
/*N*/   else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) )
/*N*/       bSwap = TRUE;
/*N*/
/*N*/   if ( bSwap )
/*N*/   {
/*?*/       EditPaM aTmpPaM( aStartPaM );
/*?*/       aStartPaM = aEndPaM;
/*?*/       aEndPaM = aTmpPaM;
/*N*/   }
/*N*/
/*N*/   return bSwap;
/*N*/ }


// -------------------------------------------------------------------------
// class EditPaM
// -------------------------------------------------------------------------
/*N*/ BOOL operator == ( const EditPaM& r1,  const EditPaM& r2  )
/*N*/ {
/*N*/   if ( r1.GetNode() != r2.GetNode() )
/*N*/       return FALSE;
/*N*/
/*N*/   if ( r1.GetIndex() != r2.GetIndex() )
/*N*/       return FALSE;
/*N*/
/*N*/   return TRUE;
/*N*/ }

/*N*/ EditPaM& EditPaM::operator = ( const EditPaM& rPaM )
/*N*/ {
/*N*/   nIndex = rPaM.nIndex;
/*N*/   pNode = rPaM.pNode;
/*N*/   return *this;
/*N*/ }

/*N*/ BOOL operator != ( const EditPaM& r1,  const EditPaM& r2  )
/*N*/ {
/*N*/   return !( r1 == r2 );
/*N*/ }


// -------------------------------------------------------------------------
// class ContentNode
// -------------------------------------------------------------------------
/*N*/ ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool )
/*N*/ {
/*N*/   DBG_CTOR( EE_ContentNode, 0 );
/*N*/ }

/*N*/ ContentNode::ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ) :
/*N*/   XubString( rStr ), aContentAttribs( rContentAttribs )
/*N*/ {
/*N*/   DBG_CTOR( EE_ContentNode, 0 );
/*N*/ }

/*N*/ ContentNode::~ContentNode()
/*N*/ {
/*N*/   DBG_DTOR( EE_ContentNode, 0 );
/*N*/ }

/*N*/ void ContentNode::ExpandAttribs( USHORT nIndex, USHORT nNew, SfxItemPool& rItemPool )
/*N*/ {
/*N*/   if ( !nNew )
/*N*/       return;
/*N*/
/*N*/   // Da Features anders behandelt werden als normale Zeichenattribute,
/*N*/   // kann sich hier auch die Sortierung der Start-Liste aendern!
/*N*/   // In jedem if..., in dem weiter (n) Moeglichkeiten aufgrund von
/*N*/   // bFeature oder Spezialfall existieren,
/*N*/   // muessen (n-1) Moeglichkeiten mit bResort versehen werden.
/*N*/   // Die wahrscheinlichste Moeglichkeit erhaelt kein bResort,
/*N*/   // so dass nicht neu sortiert wird, wenn sich alle Attribute
/*N*/   // gleich verhalten.
/*N*/   BOOL bResort = FALSE;
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
/*N*/   while ( pAttrib )
/*N*/   {
/*N*/       if ( pAttrib->GetEnd() >= nIndex )
/*N*/       {
/*N*/           // Alle Attribute hinter der Einfuegeposition verschieben...
/*N*/           if ( pAttrib->GetStart() > nIndex )
/*N*/           {
/*N*/               pAttrib->MoveForward( nNew );
/*N*/           }
/*N*/           // 0: Leeres Attribut expandieren, wenn an Einfuegestelle
/*N*/           else if ( pAttrib->IsEmpty() )
/*N*/           {
/*?*/               // Index nicht pruefen, leeres durfte nur dort liegen.
/*?*/               // Wenn spaeter doch Ueberpruefung:
/*?*/               //   Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch!
/*?*/               // Start <= nIndex, End >= nIndex => Start=End=nIndex!
/*?*/ //                if ( pAttrib->GetStart() == nIndex )
/*?*/                   pAttrib->Expand( nNew );
/*N*/           }
/*N*/           // 1: Attribut startet davor, geht bis Index...
/*N*/           else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen
/*N*/           {
/*N*/               // Nur expandieren, wenn kein Feature,
/*N*/               // und wenn nicht in ExcludeListe!
/*N*/               // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren
/*N*/ //                if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) )
/*N*/               if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
/*N*/               {
/*?*/                   if ( !pAttrib->IsEdge() )
/*?*/                       pAttrib->Expand( nNew );
/*N*/               }
/*N*/               else
/*N*/                   bResort = TRUE;
/*N*/           }
/*N*/           // 2: Attribut startet davor, geht hinter Index...
/*N*/           else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
/*N*/           {
/*?*/               DBG_ASSERT( !pAttrib->IsFeature(), "Grosses Feature?!" );
/*?*/               pAttrib->Expand( nNew );
/*N*/           }
/*N*/           // 3: Attribut startet auf Index...
/*N*/           else if ( pAttrib->GetStart() == nIndex )
/*N*/           {
/*?*/               if ( pAttrib->IsFeature() )
/*?*/               {
/*?*/                   pAttrib->MoveForward( nNew );
/*?*/                   bResort = TRUE;
/*?*/               }
/*?*/               else
/*?*/               {
/*?*/                   if ( nIndex == 0 )
/*?*/                   {
/*?*/                       pAttrib->Expand( nNew );
/*?*/                       bResort = TRUE;
/*?*/                   }
/*?*/                   else
/*?*/                       pAttrib->MoveForward( nNew );
/*?*/               }
/*N*/           }
/*N*/       }
/*N*/
/*N*/       if ( pAttrib->IsEdge() )
/*?*/           pAttrib->SetEdge( FALSE );
/*N*/
/*N*/       DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
/*N*/
/*N*/       DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" );
/*N*/       DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attrib groesser als Absatz!" );
/*N*/       if ( pAttrib->IsEmpty() )
/*N*/       {
/*?*/           OSL_FAIL( "Leeres Attribut nach ExpandAttribs?" );
/*?*/           bResort = TRUE;
/*?*/           aCharAttribList.GetAttribs().Remove( nAttr );
/*?*/           rItemPool.Remove( *pAttrib->GetItem() );
/*?*/           delete pAttrib;
/*?*/           nAttr--;
/*N*/       }
/*N*/       nAttr++;
/*N*/       pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
/*N*/   }
/*N*/
/*N*/   if ( bResort )
/*N*/       aCharAttribList.ResortAttribs();
/*N*/
/*N*/ #ifdef EDITDEBUG
/*N*/   DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Expand: Start-Liste verdreht" );
/*N*/ #endif
/*N*/ }

/*N*/ void ContentNode::CollapsAttribs( USHORT nIndex, USHORT nDeleted, SfxItemPool& rItemPool )
/*N*/ {
/*N*/   if ( !nDeleted )
/*N*/       return;
/*N*/
/*N*/   // Da Features anders behandelt werden als normale Zeichenattribute,
/*N*/   // kann sich hier auch die Sortierung der Start-Liste aendern!
/*N*/   BOOL bResort = FALSE;
/*N*/   BOOL bDelAttr = FALSE;
/*N*/   USHORT nEndChanges = nIndex+nDeleted;
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
/*N*/   while ( pAttrib )
/*N*/   {
/*N*/       bDelAttr = FALSE;
/*N*/       if ( pAttrib->GetEnd() >= nIndex )
/*N*/       {
/*N*/           // Alles Attribute hinter der Einfuegeposition verschieben...
/*N*/           if ( pAttrib->GetStart() >= nEndChanges )
/*N*/           {
/*N*/               pAttrib->MoveBackward( nDeleted );
/*N*/           }
/*N*/           // 1. Innenliegende Attribute loeschen...
/*N*/           else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
/*N*/           {
/*N*/               // Spezialfall: Attrubt deckt genau den Bereich ab
/*N*/               // => als leeres Attribut behalten.
/*N*/               if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
/*?*/                   pAttrib->GetEnd() = nIndex; // leer
/*N*/               else
/*N*/                   bDelAttr = TRUE;
/*N*/           }
/*N*/           // 2. Attribut beginnt davor, endet drinnen oder dahinter...
/*N*/           else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
/*N*/           {
/*?*/               DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" );
/*?*/               if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen
/*?*/                   pAttrib->GetEnd() = nIndex;
/*?*/               else
/*?*/                   pAttrib->Collaps( nDeleted );       // endet dahinter
/*N*/           }
/*N*/           // 3. Attribut beginnt drinnen, endet dahinter...
/*N*/           else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
/*N*/           {
/*?*/               // Features duerfen nicht expandieren!
/*?*/               if ( pAttrib->IsFeature() )
/*?*/               {
/*?*/                   pAttrib->MoveBackward( nDeleted );
/*?*/                   bResort = TRUE;
/*?*/               }
/*?*/               else
/*?*/               {
/*?*/                   pAttrib->GetStart() = nEndChanges;
/*?*/                   pAttrib->MoveBackward( nDeleted );
/*?*/               }
/*N*/           }
/*N*/       }
/*N*/       DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
/*N*/
/*N*/       DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" );
/*N*/       DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" );
/*N*/       if ( bDelAttr /* || pAttrib->IsEmpty() */ )
/*N*/       {
/*N*/           bResort = TRUE;
/*N*/           aCharAttribList.GetAttribs().Remove( nAttr );
/*N*/           rItemPool.Remove( *pAttrib->GetItem() );
/*N*/           delete pAttrib;
/*N*/           nAttr--;
/*N*/       }
/*N*/       else if ( pAttrib->IsEmpty() )
/*?*/           aCharAttribList.HasEmptyAttribs() = TRUE;
/*N*/
/*N*/       nAttr++;
/*N*/       pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
/*N*/   }
/*N*/
/*N*/   if ( bResort )
/*N*/       aCharAttribList.ResortAttribs();
/*N*/
/*N*/ #ifdef EDITDEBUG
/*N*/   DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Collaps: Start-Liste verdreht" );
/*N*/ #endif
/*N*/ }

/*N*/ void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, BOOL bKeepEndingAttribs )
/*N*/ {
/*N*/   DBG_ASSERT( pPrevNode, "kopieren von Attributen auf einen NULL-Pointer ?" );
/*N*/
/*N*/   xub_StrLen nCut = pPrevNode->Len();
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   while ( pAttrib )
/*N*/   {
/*N*/       if ( pAttrib->GetEnd() < nCut )
/*N*/       {
/*N*/           // bleiben unveraendert....
/*N*/           ;
/*N*/       }
/*N*/       else if ( pAttrib->GetEnd() == nCut )
/*N*/       {
/*N*/           // muessen als leeres Attribut kopiert werden.
/*N*/           if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
/*N*/           {
/*?*/               EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 );
/*?*/               DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" );
/*?*/               aCharAttribList.InsertAttrib( pNewAttrib );
/*N*/           }
/*N*/       }
/*N*/       else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) )
/*N*/       {
/*?*/           // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben!
/*?*/           // muessen kopiert und geaendert werden
/*?*/           EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut );
/*?*/           DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" );
/*?*/           aCharAttribList.InsertAttrib( pNewAttrib );
/*?*/           // stutzen:
/*?*/           pAttrib->GetEnd() = nCut;
/*N*/       }
/*N*/       else
/*N*/       {
/*?*/           // alle dahinter verschieben in den neuen Node (this)
/*?*/ //            pPrevNode->GetCharAttribs().RemoveAttrib( pAttrib );
/*?*/           pPrevNode->GetCharAttribs().GetAttribs().Remove( nAttr );
/*?*/           aCharAttribList.InsertAttrib( pAttrib );
/*?*/           DBG_ASSERT( pAttrib->GetStart() >= nCut, "Start < nCut!" );
/*?*/           DBG_ASSERT( pAttrib->GetEnd() >= nCut, "End < nCut!" );
/*?*/           pAttrib->GetStart() -= nCut;
/*?*/           pAttrib->GetEnd() -= nCut;
/*?*/           nAttr--;
/*N*/       }
/*N*/       nAttr++;
/*N*/       pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   }
/*N*/ }

/*N*/ void ContentNode::AppendAttribs( ContentNode* pNextNode )
/*N*/ {
/*N*/   DBG_ASSERT( pNextNode, "kopieren von Attributen von einen NULL-Pointer ?" );
/*N*/
/*N*/   USHORT nNewStart = Len();
/*N*/
/*N*/ #ifdef EDITDEBUG
/*N*/   DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" );
/*N*/ #endif
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   while ( pAttrib )
/*N*/   {
/*?*/       // alle Attribute verschieben in den aktuellen Node (this)
/*?*/       BOOL bMelted = FALSE;
/*?*/       if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) )
/*?*/       {
/*?*/           // Evtl koennen Attribute zusammengefasst werden:
/*?*/           USHORT nTmpAttr = 0;
/*?*/           EditCharAttrib* pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
/*?*/           while ( !bMelted && pTmpAttrib )
/*?*/           {
/*?*/               if ( pTmpAttrib->GetEnd() == nNewStart )
/*?*/               {
/*?*/                   if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
/*?*/                        ( *(pTmpAttrib->GetItem()) == *(pAttrib->GetItem() ) ) )
/*?*/                   {
/*?*/                       pTmpAttrib->GetEnd() += pAttrib->GetLen();
/*?*/                       pNextNode->GetCharAttribs().GetAttribs().Remove( nAttr );
/*?*/                       // Vom Pool abmelden ?!
/*?*/                       delete pAttrib;
/*?*/                       bMelted = TRUE;
/*?*/                   }
/*?*/               }
/*?*/               ++nTmpAttr;
/*?*/               pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
/*?*/           }
/*?*/       }
/*?*/
/*?*/       if ( !bMelted )
/*?*/       {
/*?*/           pAttrib->GetStart() += nNewStart;
/*?*/           pAttrib->GetEnd() += nNewStart;
/*?*/           aCharAttribList.InsertAttrib( pAttrib );
/*?*/           ++nAttr;
/*?*/       }
/*?*/       pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   }
/*N*/   // Fuer die Attribute, die nur ruebergewandert sind:
/*N*/   pNextNode->GetCharAttribs().Clear();
/*N*/
/*N*/ #ifdef EDITDEBUG
/*N*/   DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" );
/*N*/ #endif
/*N*/ }

/*N*/ void ContentNode::CreateDefFont()
/*N*/ {
/*N*/   // Erst alle Informationen aus dem Style verwenden...
/*N*/   SfxStyleSheet* pS = aContentAttribs.GetStyleSheet();
/*N*/   if ( pS )
/*N*/       CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
/*N*/
/*N*/   // ... dann die harte Absatzformatierung rueberbuegeln...
/*N*/   CreateFont( GetCharAttribs().GetDefFont(),
/*N*/       GetContentAttribs().GetItems(), ( pS ? FALSE : TRUE ) );
/*N*/ }

/*N*/ void ContentNode::SetStyleSheet( SfxStyleSheet* pS, BOOL bRecalcFont )
/*N*/ {
/*N*/   aContentAttribs.SetStyleSheet( pS );
/*N*/   if ( bRecalcFont )
/*N*/       CreateDefFont();
/*N*/ }


// -------------------------------------------------------------------------
// class ContentAttribs
// -------------------------------------------------------------------------
/*N*/ ContentAttribs::ContentAttribs( SfxItemPool& rPool ) :
/*N*/                   aAttribSet( rPool, EE_PARA_START, EE_CHAR_END )
/*N*/ {
/*N*/   pStyle = 0;
/*N*/ }

/*N*/ ContentAttribs::ContentAttribs( const ContentAttribs& rRef ) :
/*N*/                   aAttribSet( rRef.aAttribSet )
/*N*/ {
/*N*/   pStyle = rRef.pStyle;
/*N*/ }

/*N*/ ContentAttribs::~ContentAttribs()
/*N*/ {
/*N*/ }

/*N*/ SvxTabStop ContentAttribs::FindTabStop( long nCurPos, USHORT nDefTab )
/*N*/ {
/*N*/   const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS );
/*N*/   for ( USHORT i = 0; i < rTabs.Count(); i++ )
/*N*/   {
/*N*/       const SvxTabStop& rTab = rTabs[i];
/*N*/       if ( rTab.GetTabPos() > nCurPos  )
/*N*/           return rTab;
/*N*/   }
/*N*/
/*N*/   // DefTab ermitteln...
/*N*/   SvxTabStop aTabStop;
/*N*/   long x = nCurPos / nDefTab + 1;
/*N*/   aTabStop.GetTabPos() = nDefTab * x;
/*N*/   return aTabStop;
/*N*/ }

/*N*/ void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
/*N*/ {
/*N*/     BOOL bStyleChanged = ( pStyle != pS );
/*N*/   pStyle = pS;
/*N*/     // #104799# Only when other style sheet, not when current style sheet modified
/*N*/   if ( pStyle && bStyleChanged )
/*N*/   {
/*N*/       // Gezielt die Attribute aus der Absatzformatierung entfernen, die im Style
/*N*/       // spezifiziert sind, damit die Attribute des Styles wirken koennen.
/*N*/       const SfxItemSet& rStyleAttribs = pStyle->GetItemSet();
/*N*/       for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
/*N*/       {
/*N*/             // #99635# Don't change bullet on/off
/*N*/           if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) )
/*N*/               aAttribSet.ClearItem( nWhich );
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ const SfxPoolItem& ContentAttribs::GetItem( USHORT nWhich )
/*N*/ {
/*N*/   // Harte Absatzattribute haben Vorrang!
/*N*/   SfxItemSet* pTakeFrom = &aAttribSet;
/*N*/   if ( pStyle && ( aAttribSet.GetItemState( nWhich, FALSE ) != SFX_ITEM_ON  ) )
/*N*/       pTakeFrom = &pStyle->GetItemSet();
/*N*/
/*N*/   return pTakeFrom->Get( nWhich );
/*N*/ }

/*N*/ BOOL ContentAttribs::HasItem( USHORT nWhich )
/*N*/ {
/*N*/   BOOL bHasItem = FALSE;
/*N*/   if ( aAttribSet.GetItemState( nWhich, FALSE ) == SFX_ITEM_ON  )
/*N*/       bHasItem = TRUE;
/*N*/   else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON )
/*N*/       bHasItem = TRUE;
/*N*/
/*N*/   return bHasItem;
/*N*/ }



// ----------------------------------------------------------------------
//  class ItemList
//  ----------------------------------------------------------------------

// -------------------------------------------------------------------------
// class EditDoc
// -------------------------------------------------------------------------
/*N*/ EditDoc::EditDoc( SfxItemPool* pPool )
/*N*/ {
/*N*/   if ( pPool )
/*N*/   {
/*N*/       pItemPool = pPool;
/*N*/       bOwnerOfPool = FALSE;
/*N*/   }
/*N*/   else
/*N*/   {
/*?*/       pItemPool = new EditEngineItemPool( FALSE );
/*?*/       bOwnerOfPool = TRUE;
/*N*/   }
/*N*/
/*N*/   nDefTab = DEFTAB;
/*N*/   bIsVertical = FALSE;
/*N*/
/*N*/   // Don't create a empty node, Clear() will be called in EditEngine-CTOR
/*N*/
/*N*/   SetModified( FALSE );
/*N*/ };

/*N*/ EditDoc::~EditDoc()
/*N*/ {
/*N*/   ImplDestroyContents();
/*N*/   if ( bOwnerOfPool )
/*?*/       delete pItemPool;
/*N*/ }

/*N*/ void EditDoc::ImplDestroyContents()
/*N*/ {
/*N*/   for ( USHORT nNode = Count(); nNode; )
/*N*/       RemoveItemsFromPool( GetObject( --nNode ) );
/*N*/   DeleteAndDestroy( 0, Count() );
/*N*/ }

/*N*/ void EditDoc::RemoveItemsFromPool( ContentNode* pNode )
/*N*/ {
/*N*/   for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
/*N*/   {
/*N*/       EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[nAttr];
/*N*/       GetItemPool().Remove( *pAttr->GetItem() );
/*N*/   }
/*N*/ }

/*N*/ void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, BOOL bSearchInParent, short nScriptType )
/*N*/ {
/*N*/   Font aPrevFont( rFont );
/*N*/   rFont.SetAlign( ALIGN_BASELINE );
/*N*/   rFont.SetTransparent( TRUE );
/*N*/
/*N*/     USHORT nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
/*N*/     USHORT nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType );
/*N*/     USHORT nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType );
/*N*/     USHORT nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType );
/*N*/     USHORT nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType );
/*N*/
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SFX_ITEM_ON ) )
/*N*/   {
/*N*/       const SvxFontItem& rFontItem = (const SvxFontItem&)rSet.Get( nWhich_FontInfo );
/*N*/       rFont.SetName( rFontItem.GetFamilyName() );
/*N*/       rFont.SetFamily( rFontItem.GetFamily() );
/*N*/       rFont.SetPitch( rFontItem.GetPitch() );
/*N*/       rFont.SetCharSet( rFontItem.GetCharSet() );
/*N*/   }
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetLanguage( ((const SvxLanguageItem&)rSet.Get( nWhich_Language )).GetLanguage() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetColor( ((const SvxColorItem&)rSet.Get( EE_CHAR_COLOR )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem&)rSet.Get( nWhich_FontHeight ) ).GetHeight() ) );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetWeight( ((const SvxWeightItem&)rSet.Get( nWhich_Weight )).GetWeight() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetUnderline( ((const SvxUnderlineItem&)rSet.Get( EE_CHAR_UNDERLINE )).GetUnderline() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetStrikeout( ((const SvxCrossedOutItem&)rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetItalic( ((const SvxPostureItem&)rSet.Get( nWhich_Italic )).GetPosture() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetOutline( ((const SvxContourItem&)rSet.Get( EE_CHAR_OUTLINE )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetShadow( ((const SvxShadowedItem&)rSet.Get( EE_CHAR_SHADOW )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SFX_ITEM_ON ) )
/*N*/   {
/*N*/         const SvxEscapementItem& rEsc = (const SvxEscapementItem&) rSet.Get( EE_CHAR_ESCAPEMENT );
/*N*/
/*N*/         USHORT nProp = rEsc.GetProp();
/*N*/       rFont.SetPropr( (BYTE)nProp );
/*N*/
/*N*/         short nEsc = rEsc.GetEsc();
/*N*/       if ( nEsc == DFLT_ESC_AUTO_SUPER )
/*N*/           nEsc = 100 - nProp;
/*N*/       else if ( nEsc == DFLT_ESC_AUTO_SUB )
/*N*/           nEsc = -( 100 - nProp );
/*N*/       rFont.SetEscapement( nEsc );
/*N*/   }
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetKerning( ((const SvxAutoKernItem&)rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetFixKerning( ((const SvxKerningItem&)rSet.Get( EE_CHAR_KERNING )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetWordLineMode( ((const SvxWordLineModeItem&)rSet.Get( EE_CHAR_WLM )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem&)rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() );
/*N*/   if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SFX_ITEM_ON ) )
/*N*/       rFont.SetRelief( (FontRelief)((const SvxCharReliefItem&)rSet.Get( EE_CHAR_RELIEF )).GetValue() );
/*N*/
/*N*/   // Ob ich jetzt den ganzen Font vergleiche, oder vor jeder Aenderung
/*N*/   // pruefe, ob der Wert sich aendert, bleibt sich relativ gleich.
/*N*/   // So ggf ein MakeUniqFont im Font mehr, dafuer bei Aenderung schnellerer
/*N*/   // Abbruch der Abfrage, oder ich musste noch jedesmal ein bChanged pflegen.
/*N*/   if ( rFont == aPrevFont  )
/*N*/       rFont = aPrevFont;  // => Gleicher ImpPointer fuer IsSameInstance
/*N*/ }

/*N*/ void EditDoc::CreateDefFont( BOOL bUseStyles )
/*N*/ {
/*N*/   SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END );
/*N*/   CreateFont( aDefFont, aTmpSet );
/*N*/   aDefFont.SetVertical( IsVertical() );
/*N*/   aDefFont.SetOrientation( IsVertical() ? 2700 : 0 );
/*N*/
/*N*/   for ( USHORT nNode = 0; nNode < Count(); nNode++ )
/*N*/   {
/*N*/       ContentNode* pNode = GetObject( nNode );
/*N*/       pNode->GetCharAttribs().GetDefFont() = aDefFont;
/*N*/       if ( bUseStyles )
/*?*/           pNode->CreateDefFont();
/*N*/   }
/*N*/ }

/*N*/ static const sal_Unicode aCR[] = { 0x0d, 0x00 };
/*N*/ static const sal_Unicode aLF[] = { 0x0a, 0x00 };
/*N*/ static const sal_Unicode aCRLF[] = { 0x0d, 0x0a, 0x00 };

/*N*/ XubString EditDoc::GetSepStr( LineEnd eEnd )
/*N*/ {
/*N*/   XubString aSep;
/*N*/   if ( eEnd == LINEEND_CR )
/*N*/       aSep = aCR;
/*N*/   else if ( eEnd == LINEEND_LF )
/*N*/       aSep = aLF;
/*N*/   else
/*N*/       aSep = aCRLF;
/*N*/   return aSep;
/*N*/ }

/*N*/ XubString EditDoc::GetText( LineEnd eEnd ) const
/*N*/ {
/*N*/   ULONG nLen = GetTextLen();
/*N*/   USHORT nNodes = Count();
/*N*/
/*N*/   String aSep = EditDoc::GetSepStr( eEnd );
/*N*/   USHORT nSepSize = aSep.Len();
/*N*/
/*N*/   if ( nSepSize )
/*N*/       nLen += nNodes * nSepSize;
/*N*/   if ( nLen > 0xFFFb / sizeof(xub_Unicode) )
/*N*/   {
/*?*/       OSL_FAIL( "Text zu gross fuer String" );
/*?*/       return XubString();
/*N*/   }
/*N*/   xub_Unicode* pStr = new xub_Unicode[nLen+1];
/*N*/   xub_Unicode* pCur = pStr;
/*N*/   USHORT nLastNode = nNodes-1;
/*N*/   for ( USHORT nNode = 0; nNode < nNodes; nNode++ )
/*N*/   {
/*N*/       XubString aTmp( GetParaAsString( GetObject(nNode) ) );
/*N*/       memcpy( pCur, aTmp.GetBuffer(), aTmp.Len()*sizeof(sal_Unicode) );
/*N*/       pCur += aTmp.Len();
/*N*/       if ( nSepSize && ( nNode != nLastNode ) )
/*N*/       {
/*N*/           memcpy( pCur, aSep.GetBuffer(), nSepSize*sizeof(sal_Unicode ) );
/*N*/           pCur += nSepSize;
/*N*/       }
/*N*/   }
/*N*/   *pCur = '\0';
/*N*/   XubString aASCIIText( pStr );
/*N*/   delete[] pStr;
/*N*/   return aASCIIText;
/*N*/ }

/*N*/ XubString EditDoc::GetParaAsString( USHORT nNode ) const
/*N*/ {
/*N*/   return GetParaAsString( SaveGetObject( nNode ) );
/*N*/ }

/*N*/ XubString EditDoc::GetParaAsString( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, BOOL bResolveFields ) const
/*N*/ {
/*N*/   if ( nEndPos > pNode->Len() )
/*N*/       nEndPos = pNode->Len();
/*N*/
/*N*/   DBG_ASSERT( nStartPos <= nEndPos, "Start und Ende vertauscht?" );
/*N*/
/*N*/   USHORT nIndex = nStartPos;
/*N*/   XubString aStr;
/*N*/   EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex );
/*N*/   while ( nIndex < nEndPos )
/*N*/   {
/*N*/       USHORT nEnd = nEndPos;
/*N*/       if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
/*N*/           nEnd = pNextFeature->GetStart();
/*N*/       else
/*N*/           pNextFeature = 0;   // Feature interessiert unten nicht
/*N*/
/*N*/
/*N*/       DBG_ASSERT( nEnd >= nIndex, "Ende vorm Index?" );
/*N*/       aStr += XubString( *pNode, nIndex, nEnd-nIndex );
/*N*/
/*N*/       if ( pNextFeature )
/*N*/       {
/*N*/           switch ( pNextFeature->GetItem()->Which() )
/*N*/           {
/*N*/               case EE_FEATURE_TAB:    aStr += '\t';
/*N*/               break;
/*N*/               case EE_FEATURE_LINEBR: aStr += '\x0A';
/*N*/               break;
/*N*/               case EE_FEATURE_FIELD:  if ( bResolveFields )
/*N*/                                           aStr += ((EditCharAttribField*)pNextFeature)->GetFieldValue();
/*N*/               break;
/*N*/               default:    OSL_FAIL( "Was fuer ein Feature ?" );
/*N*/           }
/*N*/           pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd );
/*N*/       }
/*N*/       nIndex = nEnd;
/*N*/   }
/*N*/   return aStr;
/*N*/ }

/*N*/ ULONG EditDoc::GetTextLen() const
/*N*/ {
/*N*/   ULONG nLen = 0;
/*N*/   for ( USHORT nNode = 0; nNode < Count(); nNode++ )
/*N*/   {
/*N*/       ContentNode* pNode = GetObject( nNode );
/*N*/       nLen += pNode->Len();
/*N*/       // Felder k?nnen laenger sein als der Platzhalter im Node.
/*N*/       const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs();
/*N*/       for ( USHORT nAttr = rAttrs.Count(); nAttr; )
/*N*/       {
/*N*/           EditCharAttrib* pAttr = rAttrs[--nAttr];
/*N*/           if ( pAttr->Which() == EE_FEATURE_FIELD )
/*N*/           {
/*N*/               USHORT nFieldLen = ((EditCharAttribField*)pAttr)->GetFieldValue().Len();
/*N*/               if ( !nFieldLen )
/*N*/                   nLen--;
/*N*/               else
/*N*/                   nLen += nFieldLen-1;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   return nLen;
/*N*/ }

/*N*/ EditPaM EditDoc::Clear()
/*N*/ {
/*N*/   ImplDestroyContents();
/*N*/
/*N*/   ContentNode* pNode = new ContentNode( GetItemPool() );
/*N*/   Insert( pNode, 0 );
/*N*/
/*N*/   CreateDefFont( FALSE );
/*N*/
/*N*/   SetModified( FALSE );
/*N*/
/*N*/   EditPaM aPaM( pNode, 0 );
/*N*/   return aPaM;
/*N*/ }
/*N*/
/*N*/ void EditDoc::SetModified( BOOL b )
/*N*/ {
/*N*/     bModified = b;
/*N*/     if ( bModified )
/*N*/     {
/*N*/         aModifyHdl.Call( NULL );
/*N*/     }
/*N*/ }

/*N*/ EditPaM EditDoc::RemoveText()
/*N*/ {
/*N*/   // Das alte ItemSetmerken, damit z.B. im Chart Font behalten bleibt
/*N*/   ContentNode* pPrevFirstNode = GetObject(0);
/*N*/   SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet();
/*N*/   SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() );
/*N*/   Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() );
/*N*/
/*N*/   ImplDestroyContents();
/*N*/
/*N*/   ContentNode* pNode = new ContentNode( GetItemPool() );
/*N*/   Insert( pNode, 0 );
/*N*/
/*N*/   pNode->SetStyleSheet( pPrevStyle, FALSE );
/*N*/   pNode->GetContentAttribs().GetItems().Set( aPrevSet );
/*N*/   pNode->GetCharAttribs().GetDefFont() = aPrevFont;
/*N*/
/*N*/   SetModified( TRUE );
/*N*/
/*N*/   EditPaM aPaM( pNode, 0 );
/*N*/   return aPaM;
/*N*/ }

/*N*/ EditPaM EditDoc::InsertText( EditPaM aPaM, const XubString& rStr )
/*N*/ {
/*N*/   DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
/*N*/   DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
/*N*/   DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
/*N*/   DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" );
/*N*/
/*N*/   aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() );
/*N*/   aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.Len(), GetItemPool() );
/*N*/   aPaM.GetIndex() += rStr.Len();
/*N*/
/*N*/   SetModified( TRUE );
/*N*/
/*N*/   return aPaM;
/*N*/ }

/*N*/ EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, BOOL bKeepEndingAttribs )
/*N*/ {
/*N*/   DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" );
/*N*/   ContentNode* pCurNode = aPaM.GetNode();
/*N*/   USHORT nPos = GetPos( pCurNode );
/*N*/   XubString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() );
/*N*/   aPaM.GetNode()->Erase( aPaM.GetIndex() );
/*N*/
/*N*/   // ContenNode-CTOR kopiert auch die Absatzattribute
/*N*/   ContentNode* pNode = new ContentNode( aStr, aPaM.GetNode()->GetContentAttribs());
/*N*/   // Den Default-Font kopieren
/*N*/   pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont();
/*N*/   SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet();
/*N*/   if ( pStyle )
/*N*/   {
/*N*/       XubString aFollow( pStyle->GetFollow() );
/*N*/       if ( aFollow.Len() && ( aFollow != pStyle->GetName() ) )
/*N*/       {
/*?*/           SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() );
/*?*/           pNode->SetStyleSheet( (SfxStyleSheet*)pNext );
/*N*/       }
/*N*/   }
/*N*/
/*N*/   // Zeichenattribute muessen ggf. kopiert bzw gestutzt werden:
/*N*/   pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs );
/*N*/
/*N*/   Insert( pNode, nPos+1 );
/*N*/
/*N*/   SetModified( TRUE );
/*N*/
/*N*/   aPaM.SetNode( pNode );
/*N*/   aPaM.SetIndex( 0 );
/*N*/   return aPaM;
/*N*/ }

/*N*/ EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem  )
/*N*/ {
/*N*/   DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" );
/*N*/
/*N*/   aPaM.GetNode()->Insert( CH_FEATURE, aPaM.GetIndex() );
/*N*/   aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() );
/*N*/
/*N*/   // Fuer das Feature ein Feature-Attribut anlegen...
/*N*/   EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 );
/*N*/   DBG_ASSERT( pAttrib, "Warum kann ich kein Feature anlegen ?" );
/*N*/   aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib );
/*N*/
/*N*/   SetModified( TRUE );
/*N*/
/*N*/   aPaM.GetIndex()++;
/*N*/   return aPaM;
/*N*/ }

/*N*/ EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight )
/*N*/ {
/*N*/   const EditPaM aPaM( pLeft, pLeft->Len() );
/*N*/
/*N*/   // Erst die Attribute, da sonst nLen nicht stimmt!
/*N*/   pLeft->AppendAttribs( pRight );
/*N*/   // Dann den Text...
/*N*/   *pLeft += *pRight;
/*N*/
/*N*/   // der rechte verschwindet.
/*N*/   RemoveItemsFromPool( pRight );
/*N*/   USHORT nRight = GetPos( pRight );
/*N*/   Remove( nRight );
/*N*/   delete pRight;
/*N*/
/*N*/   SetModified( TRUE );
/*N*/
/*N*/   return aPaM;
/*N*/ }

/*N*/ EditPaM EditDoc::RemoveChars( EditPaM aPaM, USHORT nChars )
/*N*/ {
/*N*/   // Evtl. Features entfernen!
/*N*/   aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars );
/*N*/   aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() );
/*N*/
/*N*/   SetModified( TRUE );
/*N*/
/*N*/   return aPaM;
/*N*/ }

/*N*/ void EditDoc::InsertAttribInSelection( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem )
/*N*/ {
/*N*/   DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
/*N*/   DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
/*N*/
/*N*/   // fuer Optimierung:
/*N*/   // dieses endet am Anfang der Selektion => kann erweitert werden
/*N*/   EditCharAttrib* pEndingAttrib = 0;
/*N*/   // dieses startet am Ende der Selektion => kann erweitert werden
/*N*/   EditCharAttrib* pStartingAttrib = 0;
/*N*/
/*N*/   DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
/*N*/
/*N*/   RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
/*N*/
/*N*/   if ( pStartingAttrib && pEndingAttrib &&
/*N*/        ( *(pStartingAttrib->GetItem()) == rPoolItem ) &&
/*N*/        ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
/*N*/   {
/*?*/       // wird ein groesses Attribut.
/*?*/       pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
/*?*/       GetItemPool().Remove( *(pStartingAttrib->GetItem()) );
/*?*/       pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) );
/*?*/       delete pStartingAttrib;
/*N*/   }
/*N*/   else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
/*?*/       pStartingAttrib->GetStart() = nStart;
/*N*/   else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
/*N*/       pEndingAttrib->GetEnd() = nEnd;
/*N*/   else
/*N*/       InsertAttrib( rPoolItem, pNode, nStart, nEnd );
/*N*/
/*N*/   if ( pStartingAttrib )
/*?*/       pNode->GetCharAttribs().ResortAttribs();
/*N*/
/*N*/   SetModified( TRUE );
/*N*/ }


/*N*/ BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, USHORT nWhich )
/*N*/ {
/*N*/   DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
/*N*/   DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
/*N*/
/*N*/   // dieses endet am Anfang der Selektion => kann erweitert werden
/*N*/   rpEnding = 0;
/*N*/   // dieses startet am Ende der Selektion => kann erweitert werden
/*N*/   rpStarting = 0;
/*N*/
/*N*/   BOOL bChanged = FALSE;
/*N*/
/*N*/   DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
/*N*/
/*N*/   // ueber die Attribute iterieren...
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   while ( pAttr )
/*N*/   {
/*N*/       BOOL bRemoveAttrib = FALSE;
/*N*/       // MT 11.9.97:
/*N*/       // Ich denke dass in dieser Methode generell keine Features geloescht
/*N*/       // werden sollen.
/*N*/       // => Dann koennen die Feature-Abfragen weiter unten entfallen
/*N*/       USHORT nAttrWhich = pAttr->Which();
/*N*/       if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) )
/*N*/       {
/*N*/           // Attribut beginnt in Selection
/*N*/           if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
/*N*/           {
/*?*/               bChanged = TRUE;
/*?*/               if ( pAttr->GetEnd() > nEnd )
/*?*/               {
/*?*/                   pAttr->GetStart() = nEnd;   // dann faengt es dahinter an
/*?*/                   rpStarting = pAttr;
/*?*/                   break;  // es kann kein weiteres Attrib hier liegen
/*?*/               }
/*?*/               else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
/*?*/               {
/*?*/                   // Feature nur loeschen, wenn genau an der Stelle
/*?*/                   bRemoveAttrib = TRUE;
/*?*/               }
/*N*/           }
/*N*/
/*N*/           // Attribut endet in Selection
/*N*/           else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
/*N*/           {
/*N*/               bChanged = TRUE;
/*N*/               if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
/*N*/               {
/*N*/                   pAttr->GetEnd() = nStart;   // dann hoert es hier auf
/*N*/                   rpEnding = pAttr;
/*N*/               }
/*N*/               else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
/*N*/               {
/*N*/                   // Feature nur loeschen, wenn genau an der Stelle
/*N*/                   bRemoveAttrib = TRUE;
/*N*/               }
/*N*/           }
/*N*/           // Attribut ueberlappt die Selektion
/*N*/           else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
/*N*/           {
/*?*/               bChanged = TRUE;
/*?*/               if ( pAttr->GetStart() == nStart )
/*?*/               {
/*?*/                   pAttr->GetStart() = nEnd;
/*?*/                   rpStarting = pAttr;
/*?*/                   break;  // es kann weitere Attribute geben!
/*?*/               }
/*?*/               else if ( pAttr->GetEnd() == nEnd )
/*?*/               {
/*?*/                   pAttr->GetEnd() = nStart;
/*?*/                   rpEnding = pAttr;
/*?*/                   break;  // es kann weitere Attribute geben!
/*?*/               }
/*?*/               else // Attribut muss gesplittet werden...
/*?*/               {
/*?*/                   USHORT nOldEnd = pAttr->GetEnd();
/*?*/                   pAttr->GetEnd() = nStart;
/*?*/                   rpEnding = pAttr;
/*?*/                   InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
/*?*/                   break;  // es kann weitere Attribute geben!
/*?*/               }
/*N*/           }
/*N*/       }
/*N*/       if ( bRemoveAttrib )
/*N*/       {
/*?*/           DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Loeschen und behalten des gleichen Attributs ?" );
/*?*/           DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" );
/*?*/           pNode->GetCharAttribs().GetAttribs().Remove(nAttr);
/*?*/           GetItemPool().Remove( *pAttr->GetItem() );
/*?*/           delete pAttr;
/*?*/           nAttr--;
/*N*/       }
/*N*/       nAttr++;
/*N*/       pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   }
/*N*/
/*N*/   if ( bChanged )
/*N*/       SetModified( TRUE );
/*N*/
/*N*/   return bChanged;
/*N*/ }

/*N*/ void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, USHORT nStart, USHORT nEnd )
/*N*/ {
/*N*/   // Diese Methode prueft nicht mehr, ob ein entspr. Attribut
/*N*/   // schon an der Stelle existiert!
/*N*/
/*N*/   EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd );
/*N*/   DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" );
/*N*/   pNode->GetCharAttribs().InsertAttrib( pAttrib );
/*N*/
/*N*/   SetModified( TRUE );
/*N*/ }

/*N*/ void EditDoc::InsertAttrib( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem )
/*N*/ {
/*N*/   if ( nStart != nEnd )
/*N*/   {
/*N*/       InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       // Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle:
/*N*/       EditCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart );
/*N*/       if ( pAttr )
/*N*/       {
/*?*/           // Attribut entfernen....
/*?*/           pNode->GetCharAttribs().GetAttribs().Remove(
/*?*/               pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) );
/*N*/       }
/*N*/
/*N*/       // pruefen, ob ein 'gleiches' Attribut an der Stelle liegt.
/*N*/       pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart );
/*N*/       if ( pAttr )
/*N*/       {
/*?*/           if ( pAttr->IsInside( nStart ) )    // splitten
/*?*/           {
/*?*/               // ???????????????????????????????
/*?*/               // eigentlich noch pruefen, ob wirklich splittet, oder return !
/*?*/               // ???????????????????????????????
/*?*/               USHORT nOldEnd = pAttr->GetEnd();
/*?*/               pAttr->GetEnd() = nStart;
/*?*/               pAttr = MakeCharAttrib( GetItemPool(), *(pAttr->GetItem()), nStart, nOldEnd );
/*?*/               pNode->GetCharAttribs().InsertAttrib( pAttr );
/*?*/           }
/*?*/           else if ( pAttr->GetEnd() == nStart )
/*?*/           {
/*?*/               DBG_ASSERT( !pAttr->IsEmpty(), "Doch noch ein leeres Attribut?" );
/*?*/               // pruefen, ob genau das gleiche Attribut
/*?*/               if ( *(pAttr->GetItem()) == rPoolItem )
/*?*/                   return;
/*?*/           }
/*N*/       }
/*N*/       InsertAttrib( rPoolItem, pNode, nStart, nStart );
/*N*/   }
/*N*/
/*N*/   SetModified( TRUE );
/*N*/ }

/*N*/ void EditDoc::FindAttribs( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet )
/*N*/ {
/*N*/   DBG_ASSERT( pNode, "Wo soll ich suchen ?" );
/*N*/   DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" );
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/   // keine Selection...
/*N*/   if ( nStartPos == nEndPos )
/*N*/   {
/*N*/       while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
/*N*/       {
/*N*/           const SfxPoolItem* pItem = 0;
/*N*/           // Attribut liegt dadrueber...
/*N*/           if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
/*?*/               pItem = pAttr->GetItem();
/*N*/           // Attribut endet hier, ist nicht leer
/*N*/           else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
/*N*/           {
/*?*/               if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) )
/*?*/                   pItem = pAttr->GetItem();
/*N*/           }
/*N*/           // Attribut endet hier, ist leer
/*N*/           else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
/*N*/           {
/*?*/               pItem = pAttr->GetItem();
/*N*/           }
/*N*/           // Attribut beginnt hier
/*N*/           else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
/*N*/           {
/*N*/               if ( nStartPos == 0 )   // Sonderfall
/*N*/                   pItem = pAttr->GetItem();
/*N*/           }
/*N*/
/*N*/           if ( pItem )
/*N*/           {
/*N*/               USHORT nWhich = pItem->Which();
/*N*/               if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
/*N*/               {
/*N*/                   rCurSet.Put( *pItem );
/*N*/               }
/*N*/               else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
/*N*/               {
/*?*/                   const SfxPoolItem& rItem = rCurSet.Get( nWhich );
/*?*/                   if ( rItem != *pItem )
/*?*/                   {
/*?*/                       rCurSet.InvalidateItem( nWhich );
/*?*/                   }
/*N*/               }
/*N*/           }
/*N*/           nAttr++;
/*N*/           pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/       }
/*N*/   }
/*N*/   else    // Selektion
/*N*/   {
/*N*/       while ( pAttr && ( pAttr->GetStart() < nEndPos) )
/*N*/       {
/*N*/           const SfxPoolItem* pItem = 0;
/*N*/           // Attribut liegt dadrueber...
/*N*/           if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
/*N*/               pItem = pAttr->GetItem();
/*N*/           // Attribut startet mitten drin...
/*N*/           else if ( pAttr->GetStart() >= nStartPos )
/*N*/           {
/*N*/               // !!! pItem = pAttr->GetItem();
/*N*/               // einfach nur pItem reicht nicht, da ich z.B. bei Shadow
/*N*/               // niemals ein ungleiches Item finden wuerde, da ein solche
/*N*/               // seine Anwesenheit durch Abwesenheit repraesentiert!
/*N*/               // if ( ... )
/*N*/               // Es muesste geprueft werden, on genau das gleiche Attribut
/*N*/               // an der Bruchstelle aufsetzt, was recht aufwendig ist.
/*N*/               // Da ich beim Einfuegen von Attributen aber etwas optimiere
/*N*/               // tritt der Fall nicht so schnell auf...
/*N*/               // Also aus Geschwindigkeitsgruenden:
/*N*/               rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
/*N*/
/*N*/           }
/*N*/           // Attribut endet mitten drin...
/*N*/           else if ( pAttr->GetEnd() > nStartPos )
/*N*/           {
/*N*/               // pItem = pAttr->GetItem();
/*N*/               // s.o.
                /* Ist falsch, wenn das gleiche Attribut sofort wieder
                 eingestellt wird!
                 => Sollte am besten nicht vorkommen, also gleich beim
                    Setzen von Attributen richtig machen! */
/*?*/               rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
/*N*/           }
/*N*/
/*N*/           if ( pItem )
/*N*/           {
/*N*/               USHORT nWhich = pItem->Which();
/*N*/               if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
/*N*/               {
/*N*/                   rCurSet.Put( *pItem );
/*N*/               }
/*N*/               else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
/*N*/               {
/*?*/                   const SfxPoolItem& rItem = rCurSet.Get( nWhich );
/*?*/                   if ( rItem != *pItem )
/*?*/                   {
/*?*/                       rCurSet.InvalidateItem( nWhich );
/*?*/                   }
/*N*/               }
/*N*/           }
/*N*/           nAttr++;
/*N*/           pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
/*N*/       }
/*N*/   }
/*N*/ }


// -------------------------------------------------------------------------
// class EditCharAttribList
// -------------------------------------------------------------------------

/*N*/ CharAttribList::CharAttribList()
/*N*/ {
/*N*/   DBG_CTOR( EE_CharAttribList, 0 );
/*N*/   bHasEmptyAttribs = FALSE;
/*N*/ }

/*N*/ CharAttribList::~CharAttribList()
/*N*/ {
/*N*/   DBG_DTOR( EE_CharAttribList, 0 );
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
/*N*/   while ( pAttr )
/*N*/   {
/*N*/       delete pAttr;
/*N*/       ++nAttr;
/*N*/       pAttr = GetAttrib( aAttribs, nAttr );
/*N*/   }
/*N*/   Clear();
/*N*/ }

/*N*/ void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
/*N*/ {
/*N*/ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/*N*/ // optimieren: binaere Suche ? !
/*N*/ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/*N*/
/*N*/   // Vielleicht aber auch einfach nur rueckwaerts iterieren:
/*N*/   // Der haeufigste und kritischste Fall: Attribute kommen bereits
/*N*/   // sortiert an (InsertBinTextObject!)
/*N*/   // Hier waere auch binaere Suche nicht optimal.
/*N*/   // => Wuerde einiges bringen!
/*N*/
/*N*/   const USHORT nCount = Count();
/*N*/   const USHORT nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt.
/*N*/
/*N*/   if ( pAttrib->IsEmpty() )
/*N*/       bHasEmptyAttribs = TRUE;
/*N*/
/*N*/   BOOL bInserted = FALSE;
/*N*/   for ( USHORT x = 0; x < nCount; x++ )
/*N*/   {
/*N*/       EditCharAttribPtr pCurAttrib = aAttribs[x];
/*N*/       if ( pCurAttrib->GetStart() > nStart )
/*N*/       {
/*N*/           aAttribs.Insert( pAttrib, x );
/*N*/           bInserted = TRUE;
/*N*/           break;
/*N*/       }
/*N*/   }
/*N*/   if ( !bInserted )
/*N*/       aAttribs.Insert( pAttrib, nCount );
/*N*/ }

/*N*/ void CharAttribList::ResortAttribs()
/*N*/ {
/*N*/   if ( Count() )
/*N*/   {
/*N*/       qsort( (void*)aAttribs.GetData(), aAttribs.Count(), sizeof( EditCharAttrib* ), CompareStart );
/*N*/   }
/*N*/ }

/*N*/ void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool )
/*N*/ {
/*N*/   for ( USHORT n = 0; n < aAttribs.Count(); n++ )
/*N*/   {
/*N*/         EditCharAttrib* pAttr = aAttribs.GetObject( n );
/*N*/         for ( USHORT nNext = n+1; nNext < aAttribs.Count(); nNext++ )
/*N*/         {
/*N*/             EditCharAttrib* p = aAttribs.GetObject( nNext );
/*N*/             if ( !pAttr->IsFeature() && ( p->GetStart() == pAttr->GetEnd() ) && ( p->Which() == pAttr->Which() ) )
/*N*/             {
/*N*/                 if ( *p->GetItem() == *pAttr->GetItem() )
/*N*/                 {
/*N*/                     pAttr->GetEnd() = p->GetEnd();
/*N*/                     aAttribs.Remove( nNext );
/*N*/                     rItemPool.Remove( *p->GetItem() );
/*N*/                     delete p;
/*N*/                 }
/*N*/                 break;  // only 1 attr with same which can start here.
/*N*/             }
/*N*/             else if ( p->GetStart() > pAttr->GetEnd() )
/*N*/             {
/*N*/                 break;
/*N*/             }
/*N*/         }
/*N*/   }
/*N*/ }

/*N*/ EditCharAttrib* CharAttribList::FindAttrib( USHORT nWhich, USHORT nPos )
/*N*/ {
/*N*/   // Rueckwaerts, falls eins dort endet, das naechste startet.
/*N*/   // => Das startende gilt...
/*N*/   USHORT nAttr = aAttribs.Count()-1;
/*N*/   EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
/*N*/   while ( pAttr )
/*N*/   {
/*N*/       if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) )
/*N*/           return pAttr;
/*N*/       pAttr = GetAttrib( aAttribs, --nAttr );
/*N*/   }
/*N*/   return 0;
/*N*/ }

/*N*/ EditCharAttrib* CharAttribList::FindNextAttrib( USHORT nWhich, USHORT nFromPos ) const
/*N*/ {
/*N*/   DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
/*N*/   const USHORT nAttribs = aAttribs.Count();
/*N*/   for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
/*N*/   {
/*N*/       EditCharAttrib* pAttr = aAttribs[ nAttr ];
/*N*/       if ( ( pAttr->GetStart() >= nFromPos ) && ( pAttr->Which() == nWhich ) )
/*N*/           return pAttr;
/*N*/   }
/*N*/   return 0;
/*N*/ }




/*N*/ BOOL CharAttribList::HasBoundingAttrib( USHORT nBound )
/*N*/ {
/*N*/   // Rueckwaerts, falls eins dort endet, das naechste startet.
/*N*/   // => Das startende gilt...
/*N*/   USHORT nAttr = aAttribs.Count()-1;
/*N*/   EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
/*N*/   while ( pAttr && ( pAttr->GetEnd() >= nBound ) )
/*N*/   {
/*?*/       if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) )
/*?*/           return TRUE;
/*?*/       pAttr = GetAttrib( aAttribs, --nAttr );
/*N*/   }
/*N*/   return FALSE;
/*N*/ }

/*N*/ EditCharAttrib* CharAttribList::FindEmptyAttrib( USHORT nWhich, USHORT nPos )
/*N*/ {
/*N*/   if ( !bHasEmptyAttribs )
/*N*/       return 0;
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
/*N*/   while ( pAttr && ( pAttr->GetStart() <= nPos ) )
/*N*/   {
/*N*/       if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) )
/*N*/           return pAttr;
/*N*/       nAttr++;
/*N*/       pAttr = GetAttrib( aAttribs, nAttr );
/*N*/   }
/*N*/   return 0;
/*N*/ }

/*N*/ EditCharAttrib*   CharAttribList::FindFeature( USHORT nPos ) const
/*N*/ {
/*N*/
/*N*/   USHORT nAttr = 0;
/*N*/   EditCharAttrib* pNextAttrib = GetAttrib( aAttribs, nAttr );
/*N*/
/*N*/   // erstmal zur gewuenschten Position...
/*N*/   while ( pNextAttrib && ( pNextAttrib->GetStart() < nPos ) )
/*N*/   {
/*N*/       nAttr++;
/*N*/       pNextAttrib = GetAttrib( aAttribs, nAttr );
/*N*/   }
/*N*/
/*N*/   // jetzt das Feature suchen...
/*N*/   while ( pNextAttrib && !pNextAttrib->IsFeature() )
/*N*/   {
/*N*/       nAttr++;
/*N*/       pNextAttrib = GetAttrib( aAttribs, nAttr );
/*N*/   }
/*N*/
/*N*/   return pNextAttrib;
/*N*/ }












/*N*/ EditEngineItemPool::EditEngineItemPool( BOOL bPersistenRefCounts )
/*N*/   : SfxItemPool( String( "EditEngineItemPool", RTL_TEXTENCODING_ASCII_US ), EE_ITEMS_START, EE_ITEMS_END,
/*N*/                   aItemInfos, 0, bPersistenRefCounts )
/*N*/ {
/*N*/   SetVersionMap( 1, 3999, 4015, aV1Map );
/*N*/   SetVersionMap( 2, 3999, 4019, aV2Map );
/*N*/   SetVersionMap( 3, 3997, 4020, aV3Map );
/*N*/   SetVersionMap( 4, 3994, 4022, aV4Map );
/*N*/
/*N*/   DBG_ASSERT( EE_DLL(), "EditDLL?!" );
/*N*/   SfxPoolItem** ppDefItems = EE_DLL()->GetGlobalData()->GetDefItems();
/*N*/   SetDefaults( ppDefItems );
/*N*/ }

/*N*/ EditEngineItemPool::~EditEngineItemPool()
/*N*/ {
/*N*/ }

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
