diff options
Diffstat (limited to 'editeng/source/editeng/editdoc.cxx')
-rw-r--r-- | editeng/source/editeng/editdoc.cxx | 2314 |
1 files changed, 2314 insertions, 0 deletions
diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx new file mode 100644 index 000000000000..9ac179a2a47f --- /dev/null +++ b/editeng/source/editeng/editdoc.cxx @@ -0,0 +1,2314 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/tstpitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <editeng/editids.hrc> + +#include <editdoc.hxx> +#include <editdbg.hxx> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <tools/stream.hxx> +#include <tools/debug.hxx> +#include <tools/shl.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <stdlib.h> // qsort + +using namespace ::com::sun::star; + + +// ------------------------------------------------------------ + +USHORT GetScriptItemId( USHORT nItemId, short nScriptType ) +{ + USHORT nId = nItemId; + + if ( ( nScriptType == i18n::ScriptType::ASIAN ) || + ( nScriptType == i18n::ScriptType::COMPLEX ) ) + { + switch ( nItemId ) + { + case EE_CHAR_LANGUAGE: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL; + break; + case EE_CHAR_FONTINFO: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL; + break; + case EE_CHAR_FONTHEIGHT: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL; + break; + case EE_CHAR_WEIGHT: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL; + break; + case EE_CHAR_ITALIC: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL; + break; + } + } + + return nId; +} + +BOOL IsScriptItemValid( USHORT nItemId, short nScriptType ) +{ + BOOL bValid = TRUE; + + switch ( nItemId ) + { + case EE_CHAR_LANGUAGE: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_LANGUAGE_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_LANGUAGE_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_FONTINFO: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_FONTINFO_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_FONTINFO_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_FONTHEIGHT: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_FONTHEIGHT_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_FONTHEIGHT_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_WEIGHT: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_WEIGHT_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_WEIGHT_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_ITALIC: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_ITALIC_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_ITALIC_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + } + + return bValid; +} + + +// ------------------------------------------------------------ + +// Sollte spaeter zentral nach TOOLS/STRING (Aktuell: 303) +// fuer Grep: WS_TARGET + +DBG_NAME( EE_TextPortion ); +DBG_NAME( EE_EditLine ); +DBG_NAME( EE_ContentNode ); +DBG_NAME( EE_CharAttribList ); + +SfxItemInfo aItemInfos[EDITITEMCOUNT] = { + { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE }, // EE_PARA_WRITINGDIR + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_XMLATTRIBS + { SID_ATTR_PARA_HANGPUNCTUATION, SFX_ITEM_POOLABLE }, // EE_PARA_HANGINGPUNCTUATION + { SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_SCRIPTSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_ASIANCJKSPACING + { SID_ATTR_NUMBERING_RULE, SFX_ITEM_POOLABLE }, // EE_PARA_NUMBULL + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_HYPHENATE + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_BULLETSTATE + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_OUTLLRSPACE + { SID_ATTR_PARA_OUTLLEVEL, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE }, + { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE }, + { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_SCALEWIDTH, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_ESCAPEMENT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_AUTOKERN, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_KERNING, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE }, + { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_RUBI_DUMMY + { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_XMLATTRIBS + { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE }, + { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_TAB + { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_LINEBR + { SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEM_POOLABLE }, // EE_FEATURE_NOTCONV + { SID_FIELD, SFX_ITEM_POOLABLE } +}; + +USHORT aV1Map[] = { + 3999, 4001, 4002, 4003, 4004, 4005, 4006, + 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019? +}; + +USHORT aV2Map[] = { + 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, + 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020 +}; + +USHORT aV3Map[] = { + 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, + 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, + 4020, 4021 +}; + +USHORT aV4Map[] = { + 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 4018, + /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */ + 4034, 4035, 4036, 4037 +}; + +USHORT aV5Map[] = { + 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, + 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, + /* EE_CHAR_OVERLINE inserted here */ + 4035, 4036, 4037, 4038 +}; + +SV_IMPL_PTRARR( DummyContentList, ContentNode* ); +SV_IMPL_VARARR( ScriptTypePosInfos, ScriptTypePosInfo ); +SV_IMPL_VARARR( WritingDirectionInfos, WritingDirectionInfo ); +// SV_IMPL_VARARR( ExtraCharInfos, ExtraCharInfo ); + + +int SAL_CALL CompareStart( const void* pFirst, const void* pSecond ) +{ + if ( (*((EditCharAttrib**)pFirst))->GetStart() < (*((EditCharAttrib**)pSecond))->GetStart() ) + return (-1); + else if ( (*((EditCharAttrib**)pFirst))->GetStart() > (*((EditCharAttrib**)pSecond))->GetStart() ) + return (1); + return 0; +} + +EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) +{ + // das neue Attribut im Pool anlegen + const SfxPoolItem& rNew = rPool.Put( rAttr ); + + EditCharAttrib* pNew = 0; + switch( rNew.Which() ) + { + case EE_CHAR_LANGUAGE: + case EE_CHAR_LANGUAGE_CJK: + case EE_CHAR_LANGUAGE_CTL: + { + pNew = new EditCharAttribLanguage( (const SvxLanguageItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_COLOR: + { + pNew = new EditCharAttribColor( (const SvxColorItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + pNew = new EditCharAttribFont( (const SvxFontItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + pNew = new EditCharAttribFontHeight( (const SvxFontHeightItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTWIDTH: + { + pNew = new EditCharAttribFontWidth( (const SvxCharScaleWidthItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + pNew = new EditCharAttribWeight( (const SvxWeightItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_UNDERLINE: + { + pNew = new EditCharAttribUnderline( (const SvxUnderlineItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_OVERLINE: + { + pNew = new EditCharAttribOverline( (const SvxOverlineItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_EMPHASISMARK: + { + pNew = new EditCharAttribEmphasisMark( (const SvxEmphasisMarkItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_RELIEF: + { + pNew = new EditCharAttribRelief( (const SvxCharReliefItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_STRIKEOUT: + { + pNew = new EditCharAttribStrikeout( (const SvxCrossedOutItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + pNew = new EditCharAttribItalic( (const SvxPostureItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_OUTLINE: + { + pNew = new EditCharAttribOutline( (const SvxContourItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_SHADOW: + { + pNew = new EditCharAttribShadow( (const SvxShadowedItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_ESCAPEMENT: + { + pNew = new EditCharAttribEscapement( (const SvxEscapementItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_PAIRKERNING: + { + pNew = new EditCharAttribPairKerning( (const SvxAutoKernItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_KERNING: + { + pNew = new EditCharAttribKerning( (const SvxKerningItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_WLM: + { + pNew = new EditCharAttribWordLineMode( (const SvxWordLineModeItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_XMLATTRIBS: + { + pNew = new EditCharAttrib( rNew, nS, nE ); // Attrib is only for holding XML information... + } + break; + case EE_FEATURE_TAB: + { + pNew = new EditCharAttribTab( (const SfxVoidItem&)rNew, nS ); + } + break; + case EE_FEATURE_LINEBR: + { + pNew = new EditCharAttribLineBreak( (const SfxVoidItem&)rNew, nS ); + } + break; + case EE_FEATURE_FIELD: + { + pNew = new EditCharAttribField( (const SvxFieldItem&)rNew, nS ); + } + break; + default: + { + DBG_ERROR( "Ungueltiges Attribut!" ); + } + } + return pNew; +} + +// ------------------------------------------------------------------------- +// class EditLine +// ------------------------------------------------------------------------- + +EditLine::EditLine() +{ + DBG_CTOR( EE_EditLine, 0 ); + + nStart = nEnd = 0; + nStartPortion = 0; // damit in ungueltiger Zeile ohne Portions von einer gueltigen Zeile mit der Portion Nr0 unterscieden werden kann. + nEndPortion = 0; + nHeight = 0; + nStartPosX = 0; + nTxtHeight = 0; + nTxtWidth = 0; + nCrsrHeight = 0; + nMaxAscent = 0; + bHangingPunctuation = FALSE; + bInvalid = TRUE; +} + +EditLine::EditLine( const EditLine& r ) +{ + DBG_CTOR( EE_EditLine, 0 ); + + nEnd = r.nEnd; + nStart = r.nStart; + nStartPortion = r.nStartPortion; + nEndPortion = r.nEndPortion; + bHangingPunctuation = r.bHangingPunctuation; + + nHeight = 0; + nStartPosX = 0; + nTxtHeight = 0; + nTxtWidth = 0; + nCrsrHeight = 0; + nMaxAscent = 0; + bInvalid = TRUE; +} + +EditLine::~EditLine() +{ + DBG_DTOR( EE_EditLine, 0 ); +} + +EditLine* EditLine::Clone() const +{ + EditLine* pL = new EditLine; + if ( aPositions.Count() ) + { + pL->aPositions.Insert (aPositions.GetData(), aPositions.Count(), 0); + } + pL->nStartPosX = nStartPosX; + pL->nStart = nStart; + pL->nEnd = nEnd; + pL->nStartPortion = nStartPortion; + pL->nEndPortion = nEndPortion; + pL->nHeight = nHeight; + pL->nTxtWidth = nTxtWidth; + pL->nTxtHeight = nTxtHeight; + pL->nCrsrHeight = nCrsrHeight; + pL->nMaxAscent = nMaxAscent; + + return pL; +} + +BOOL operator == ( const EditLine& r1, const EditLine& r2 ) +{ + if ( r1.nStart != r2.nStart ) + return FALSE; + + if ( r1.nEnd != r2.nEnd ) + return FALSE; + + if ( r1.nStartPortion != r2.nStartPortion ) + return FALSE; + + if ( r1.nEndPortion != r2.nEndPortion ) + return FALSE; + + return TRUE; +} + +EditLine& EditLine::operator = ( const EditLine& r ) +{ + nEnd = r.nEnd; + nStart = r.nStart; + nEndPortion = r.nEndPortion; + nStartPortion = r.nStartPortion; + return *this; +} + + +BOOL operator != ( const EditLine& r1, const EditLine& r2 ) +{ + return !( r1 == r2 ); +} + +Size EditLine::CalcTextSize( ParaPortion& rParaPortion ) +{ + Size aSz; + Size aTmpSz; + TextPortion* pPortion; + + USHORT nIndex = GetStart(); + + DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize vor CreatePortions !" ); + + for ( USHORT n = nStartPortion; n <= nEndPortion; n++ ) + { + pPortion = rParaPortion.GetTextPortions().GetObject(n); + switch ( pPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + { + aTmpSz = pPortion->GetSize(); + aSz.Width() += aTmpSz.Width(); + if ( aSz.Height() < aTmpSz.Height() ) + aSz.Height() = aTmpSz.Height(); + } + break; + case PORTIONKIND_TAB: +// case PORTIONKIND_EXTRASPACE: + { + aSz.Width() += pPortion->GetSize().Width(); + } + break; + } + nIndex = nIndex + pPortion->GetLen(); + } + + SetHeight( (USHORT)aSz.Height() ); + return aSz; +} + +// ------------------------------------------------------------------------- +// class EditLineList +// ------------------------------------------------------------------------- +EditLineList::EditLineList() +{ +} + +EditLineList::~EditLineList() +{ + Reset(); +} + +void EditLineList::Reset() +{ + for ( USHORT nLine = 0; nLine < Count(); nLine++ ) + delete GetObject(nLine); + Remove( 0, Count() ); +} + +void EditLineList::DeleteFromLine( USHORT nDelFrom ) +{ + DBG_ASSERT( nDelFrom <= (Count() - 1), "DeleteFromLine: Out of range" ); + for ( USHORT nL = nDelFrom; nL < Count(); nL++ ) + delete GetObject(nL); + Remove( nDelFrom, Count()-nDelFrom ); +} + +USHORT EditLineList::FindLine( USHORT nChar, BOOL bInclEnd ) +{ + for ( USHORT nLine = 0; nLine < Count(); nLine++ ) + { + EditLine* pLine = GetObject( nLine ); + if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || + ( pLine->GetEnd() > nChar ) ) + { + return nLine; + } + } + + DBG_ASSERT( !bInclEnd, "Zeile nicht gefunden: FindLine" ); + return ( Count() - 1 ); +} + +// ------------------------------------------------------------------------- +// class EditSelection +// ------------------------------------------------------------------------- +BOOL EditPaM::DbgIsBuggy( EditDoc& rDoc ) +{ + if ( !pNode ) + return TRUE; + if ( rDoc.GetPos( pNode ) >= rDoc.Count() ) + return TRUE; + if ( nIndex > pNode->Len() ) + return TRUE; + + return FALSE; +} + +BOOL EditSelection::DbgIsBuggy( EditDoc& rDoc ) +{ + if ( aStartPaM.DbgIsBuggy( rDoc ) ) + return TRUE; + if ( aEndPaM.DbgIsBuggy( rDoc ) ) + return TRUE; + + return FALSE; +} + +EditSelection::EditSelection() +{ +} + +EditSelection::EditSelection( const EditPaM& rStartAndAnd ) +{ + // koennte noch optimiert werden! + // nicht erst Def-CTOR vom PaM rufen! + aStartPaM = rStartAndAnd; + aEndPaM = rStartAndAnd; +} + +EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd ) +{ + // koennte noch optimiert werden! + aStartPaM = rStart; + aEndPaM = rEnd; +} + +EditSelection& EditSelection::operator = ( const EditPaM& rPaM ) +{ + aStartPaM = rPaM; + aEndPaM = rPaM; + return *this; +} + +BOOL EditSelection::IsInvalid() const +{ + EditPaM aEmptyPaM; + + if ( aStartPaM == aEmptyPaM ) + return TRUE; + + if ( aEndPaM == aEmptyPaM ) + return TRUE; + + return FALSE; +} + +BOOL EditSelection::Adjust( const ContentList& rNodes ) +{ + DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in Adjust(1)" ); + DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in Adjust(2)" ); + + ContentNode* pStartNode = aStartPaM.GetNode(); + ContentNode* pEndNode = aEndPaM.GetNode(); + + USHORT nStartNode = rNodes.GetPos( pStartNode ); + USHORT nEndNode = rNodes.GetPos( pEndNode ); + + DBG_ASSERT( nStartNode != USHRT_MAX, "Node im Wald in Adjust(1)" ); + DBG_ASSERT( nEndNode != USHRT_MAX, "Node im Wald in Adjust(2)" ); + + BOOL bSwap = FALSE; + if ( nStartNode > nEndNode ) + bSwap = TRUE; + else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) ) + bSwap = TRUE; + + if ( bSwap ) + { + EditPaM aTmpPaM( aStartPaM ); + aStartPaM = aEndPaM; + aEndPaM = aTmpPaM; + } + + return bSwap; +} + + +// ------------------------------------------------------------------------- +// class EditPaM +// ------------------------------------------------------------------------- +BOOL operator == ( const EditPaM& r1, const EditPaM& r2 ) +{ + if ( r1.GetNode() != r2.GetNode() ) + return FALSE; + + if ( r1.GetIndex() != r2.GetIndex() ) + return FALSE; + + return TRUE; +} + +EditPaM& EditPaM::operator = ( const EditPaM& rPaM ) +{ + nIndex = rPaM.nIndex; + pNode = rPaM.pNode; + return *this; +} + +BOOL operator != ( const EditPaM& r1, const EditPaM& r2 ) +{ + return !( r1 == r2 ); +} + + +// ------------------------------------------------------------------------- +// class ContentNode +// ------------------------------------------------------------------------- +ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool ) +{ + DBG_CTOR( EE_ContentNode, 0 ); + pWrongList = NULL; +} + +ContentNode::ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ) : + XubString( rStr ), aContentAttribs( rContentAttribs ) +{ + DBG_CTOR( EE_ContentNode, 0 ); + pWrongList = NULL; +} + +ContentNode::~ContentNode() +{ + DBG_DTOR( EE_ContentNode, 0 ); +#ifndef SVX_LIGHT + delete pWrongList; +#endif +} + +void ContentNode::ExpandAttribs( USHORT nIndex, USHORT nNew, SfxItemPool& rItemPool ) +{ + if ( !nNew ) + return; + + // Da Features anders behandelt werden als normale Zeichenattribute, + // kann sich hier auch die Sortierung der Start-Liste aendern! + // In jedem if..., in dem weiter (n) Moeglichkeiten aufgrund von + // bFeature oder Spezialfall existieren, + // muessen (n-1) Moeglichkeiten mit bResort versehen werden. + // Die wahrscheinlichste Moeglichkeit erhaelt kein bResort, + // so dass nicht neu sortiert wird, wenn sich alle Attribute + // gleich verhalten. + BOOL bResort = FALSE; + BOOL bExpandedEmptyAtIndexNull = FALSE; + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + while ( pAttrib ) + { + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alle Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() > nIndex ) + { + pAttrib->MoveForward( nNew ); + } + // 0: Leeres Attribut expandieren, wenn an Einfuegestelle + else if ( pAttrib->IsEmpty() ) + { + // 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 ); + if ( pAttrib->GetStart() == 0 ) + bExpandedEmptyAtIndexNull = TRUE; + } + // 1: Attribut startet davor, geht bis Index... + else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen + { + // Nur expandieren, wenn kein Feature, + // und wenn nicht in ExcludeListe! + // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren +// if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) ) + if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) ) + { + if ( !pAttrib->IsEdge() ) + pAttrib->Expand( nNew ); + } + else + bResort = TRUE; + } + // 2: Attribut startet davor, geht hinter Index... + else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + DBG_ASSERT( !pAttrib->IsFeature(), "Grosses Feature?!" ); + pAttrib->Expand( nNew ); + } + // 3: Attribut startet auf Index... + else if ( pAttrib->GetStart() == nIndex ) + { + if ( pAttrib->IsFeature() ) + { + pAttrib->MoveForward( nNew ); + bResort = TRUE; + } + else + { + BOOL bExpand = FALSE; + if ( nIndex == 0 ) + { + bExpand = TRUE; + if( bExpandedEmptyAtIndexNull ) + { + // Check if this kind of attribut was empty and expanded here... + USHORT nW = pAttrib->GetItem()->Which(); + for ( USHORT nA = 0; nA < nAttr; nA++ ) + { + EditCharAttrib* pA = aCharAttribList.GetAttribs()[nA]; + if ( ( pA->GetStart() == 0 ) && ( pA->GetItem()->Which() == nW ) ) + { + bExpand = FALSE; + break; + } + } + + } + } + if ( bExpand ) + { + pAttrib->Expand( nNew ); + bResort = TRUE; + } + else + { + pAttrib->MoveForward( nNew ); + } + } + } + } + + if ( pAttrib->IsEdge() ) + pAttrib->SetEdge( FALSE ); + + DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attrib groesser als Absatz!" ); + if ( pAttrib->IsEmpty() ) + { + DBG_ERROR( "Leeres Attribut nach ExpandAttribs?" ); + bResort = TRUE; + aCharAttribList.GetAttribs().Remove( nAttr ); + rItemPool.Remove( *pAttrib->GetItem() ); + delete pAttrib; + nAttr--; + } + nAttr++; + pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + } + + if ( bResort ) + aCharAttribList.ResortAttribs(); + +#ifndef SVX_LIGHT + if ( pWrongList ) + { + BOOL bSep = ( GetChar( nIndex ) == ' ' ) || IsFeature( nIndex ); + pWrongList->TextInserted( nIndex, nNew, bSep ); + } +#endif // !SVX_LIGHT + +#ifdef EDITDEBUG + DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Expand: Start-Liste verdreht" ); +#endif +} + +void ContentNode::CollapsAttribs( USHORT nIndex, USHORT nDeleted, SfxItemPool& rItemPool ) +{ + if ( !nDeleted ) + return; + + // Da Features anders behandelt werden als normale Zeichenattribute, + // kann sich hier auch die Sortierung der Start-Liste aendern! + BOOL bResort = FALSE; + BOOL bDelAttr = FALSE; + USHORT nEndChanges = nIndex+nDeleted; + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + while ( pAttrib ) + { + bDelAttr = FALSE; + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alles Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() >= nEndChanges ) + { + pAttrib->MoveBackward( nDeleted ); + } + // 1. Innenliegende Attribute loeschen... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) ) + { + // Spezialfall: Attrubt deckt genau den Bereich ab + // => als leeres Attribut behalten. + if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) ) + pAttrib->GetEnd() = nIndex; // leer + else + bDelAttr = TRUE; + } + // 2. Attribut beginnt davor, endet drinnen oder dahinter... + else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" ); + if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen + pAttrib->GetEnd() = nIndex; + else + pAttrib->Collaps( nDeleted ); // endet dahinter + } + // 3. Attribut beginnt drinnen, endet dahinter... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) ) + { + // Features duerfen nicht expandieren! + if ( pAttrib->IsFeature() ) + { + pAttrib->MoveBackward( nDeleted ); + bResort = TRUE; + } + else + { + pAttrib->GetStart() = nEndChanges; + pAttrib->MoveBackward( nDeleted ); + } + } + } + DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" ); + if ( bDelAttr /* || pAttrib->IsEmpty() */ ) + { + bResort = TRUE; + aCharAttribList.GetAttribs().Remove( nAttr ); + rItemPool.Remove( *pAttrib->GetItem() ); + delete pAttrib; + nAttr--; + } + else if ( pAttrib->IsEmpty() ) + aCharAttribList.HasEmptyAttribs() = TRUE; + + nAttr++; + pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + } + + if ( bResort ) + aCharAttribList.ResortAttribs(); + +#ifndef SVX_LIGHT + if ( pWrongList ) + pWrongList->TextDeleted( nIndex, nDeleted ); +#endif // !SVX_LIGHT + +#ifdef EDITDEBUG + DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Collaps: Start-Liste verdreht" ); +#endif +} + +void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, BOOL bKeepEndingAttribs ) +{ + DBG_ASSERT( pPrevNode, "kopieren von Attributen auf einen NULL-Pointer ?" ); + + xub_StrLen nCut = pPrevNode->Len(); + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + if ( pAttrib->GetEnd() < nCut ) + { + // bleiben unveraendert.... + ; + } + else if ( pAttrib->GetEnd() == nCut ) + { + // muessen als leeres Attribut kopiert werden. + if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) ) + { + EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 ); + DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" ); + aCharAttribList.InsertAttrib( pNewAttrib ); + } + } + else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) ) + { + // 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; + } + else + { + // 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() = pAttrib->GetStart() - nCut; + pAttrib->GetEnd() = pAttrib->GetEnd() - nCut; + nAttr--; + } + nAttr++; + pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); + } +} + +void ContentNode::AppendAttribs( ContentNode* pNextNode ) +{ + DBG_ASSERT( pNextNode, "kopieren von Attributen von einen NULL-Pointer ?" ); + + USHORT nNewStart = Len(); + +#ifdef EDITDEBUG + DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" ); +#endif + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + // 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() = + 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() = pAttrib->GetStart() + nNewStart; + pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart; + aCharAttribList.InsertAttrib( pAttrib ); + ++nAttr; + } + pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); + } + // Fuer die Attribute, die nur ruebergewandert sind: + pNextNode->GetCharAttribs().Clear(); + +#ifdef EDITDEBUG + DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" ); +#endif +} + +void ContentNode::CreateDefFont() +{ + // Erst alle Informationen aus dem Style verwenden... + SfxStyleSheet* pS = aContentAttribs.GetStyleSheet(); + if ( pS ) + CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() ); + + // ... dann die harte Absatzformatierung rueberbuegeln... + CreateFont( GetCharAttribs().GetDefFont(), + GetContentAttribs().GetItems(), pS == NULL ); +} + +void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle ) +{ + aContentAttribs.SetStyleSheet( pS ); + + // Erst alle Informationen aus dem Style verwenden... + GetCharAttribs().GetDefFont() = rFontFromStyle; + // ... dann die harte Absatzformatierung rueberbuegeln... + CreateFont( GetCharAttribs().GetDefFont(), + GetContentAttribs().GetItems(), pS == NULL ); +} + +void ContentNode::SetStyleSheet( SfxStyleSheet* pS, BOOL bRecalcFont ) +{ + aContentAttribs.SetStyleSheet( pS ); + if ( bRecalcFont ) + CreateDefFont(); +} + +void ContentNode::DestroyWrongList() +{ +#ifndef SVX_LIGHT + delete pWrongList; +#endif + pWrongList = NULL; +} + +void ContentNode::CreateWrongList() +{ + DBG_ASSERT( !pWrongList, "WrongList existiert schon!" ); +#ifndef SVX_LIGHT + pWrongList = new WrongList; +#endif +} + +void ContentNode::SetWrongList( WrongList* p ) +{ + DBG_ASSERT( !pWrongList, "WrongList existiert schon!" ); + pWrongList = p; +} + +// ------------------------------------------------------------------------- +// class ContentAttribs +// ------------------------------------------------------------------------- +ContentAttribs::ContentAttribs( SfxItemPool& rPool ) : + aAttribSet( rPool, EE_PARA_START, EE_CHAR_END ) +{ + pStyle = 0; +} + +ContentAttribs::ContentAttribs( const ContentAttribs& rRef ) : + aAttribSet( rRef.aAttribSet ) +{ + pStyle = rRef.pStyle; +} + +ContentAttribs::~ContentAttribs() +{ +} + +SvxTabStop ContentAttribs::FindTabStop( long nCurPos, USHORT nDefTab ) +{ + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS ); + for ( USHORT i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + if ( rTab.GetTabPos() > nCurPos ) + return rTab; + } + + // DefTab ermitteln... + SvxTabStop aTabStop; + long x = nCurPos / nDefTab + 1; + aTabStop.GetTabPos() = nDefTab * x; + return aTabStop; +} + +void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS ) +{ + BOOL bStyleChanged = ( pStyle != pS ); + pStyle = pS; + // #104799# Only when other style sheet, not when current style sheet modified + if ( pStyle && bStyleChanged ) + { + // Gezielt die Attribute aus der Absatzformatierung entfernen, die im Style + // spezifiziert sind, damit die Attribute des Styles wirken koennen. + const SfxItemSet& rStyleAttribs = pStyle->GetItemSet(); + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + // #99635# Don't change bullet on/off + if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) ) + aAttribSet.ClearItem( nWhich ); + } + } +} + +const SfxPoolItem& ContentAttribs::GetItem( USHORT nWhich ) +{ + // Harte Absatzattribute haben Vorrang! + SfxItemSet* pTakeFrom = &aAttribSet; + if ( pStyle && ( aAttribSet.GetItemState( nWhich, FALSE ) != SFX_ITEM_ON ) ) + pTakeFrom = &pStyle->GetItemSet(); + + return pTakeFrom->Get( nWhich ); +} + +BOOL ContentAttribs::HasItem( USHORT nWhich ) +{ + BOOL bHasItem = FALSE; + if ( aAttribSet.GetItemState( nWhich, FALSE ) == SFX_ITEM_ON ) + bHasItem = TRUE; + else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON ) + bHasItem = TRUE; + + return bHasItem; +} + + + +// ---------------------------------------------------------------------- +// class ItemList +// ---------------------------------------------------------------------- +const SfxPoolItem* ItemList::FindAttrib( USHORT nWhich ) +{ + const SfxPoolItem* pItem = First(); + while ( pItem && ( pItem->Which() != nWhich ) ) + pItem = Next(); + + return pItem; +} + +// ------------------------------------------------------------------------- +// class EditDoc +// ------------------------------------------------------------------------- +EditDoc::EditDoc( SfxItemPool* pPool ) +{ + if ( pPool ) + { + pItemPool = pPool; + bOwnerOfPool = FALSE; + } + else + { + pItemPool = new EditEngineItemPool( FALSE ); + bOwnerOfPool = TRUE; + } + + nDefTab = DEFTAB; + bIsVertical = FALSE; + bIsFixedCellHeight = FALSE; + + // Don't create a empty node, Clear() will be called in EditEngine-CTOR + + SetModified( FALSE ); +}; + +EditDoc::~EditDoc() +{ + ImplDestroyContents(); + if ( bOwnerOfPool ) + SfxItemPool::Free(pItemPool); +} + +void EditDoc::ImplDestroyContents() +{ + for ( USHORT nNode = Count(); nNode; ) + RemoveItemsFromPool( GetObject( --nNode ) ); + DeleteAndDestroy( 0, Count() ); +} + +void EditDoc::RemoveItemsFromPool( ContentNode* pNode ) +{ + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[nAttr]; + GetItemPool().Remove( *pAttr->GetItem() ); + } +} + +void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, short nScriptType ) +{ + Font aPrevFont( rFont ); + rFont.SetAlign( ALIGN_BASELINE ); + rFont.SetTransparent( TRUE ); + + USHORT nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ); + USHORT nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); + USHORT nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ); + USHORT nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ); + USHORT nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType ); + + if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SFX_ITEM_ON ) ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)rSet.Get( nWhich_FontInfo ); + rFont.SetName( rFontItem.GetFamilyName() ); + rFont.SetFamily( rFontItem.GetFamily() ); + rFont.SetPitch( rFontItem.GetPitch() ); + rFont.SetCharSet( rFontItem.GetCharSet() ); + } + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SFX_ITEM_ON ) ) + rFont.SetLanguage( ((const SvxLanguageItem&)rSet.Get( nWhich_Language )).GetLanguage() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SFX_ITEM_ON ) ) + rFont.SetColor( ((const SvxColorItem&)rSet.Get( EE_CHAR_COLOR )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SFX_ITEM_ON ) ) + rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem&)rSet.Get( nWhich_FontHeight ) ).GetHeight() ) ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SFX_ITEM_ON ) ) + rFont.SetWeight( ((const SvxWeightItem&)rSet.Get( nWhich_Weight )).GetWeight() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SFX_ITEM_ON ) ) + rFont.SetUnderline( ((const SvxUnderlineItem&)rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SFX_ITEM_ON ) ) + rFont.SetOverline( ((const SvxOverlineItem&)rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SFX_ITEM_ON ) ) + rFont.SetStrikeout( ((const SvxCrossedOutItem&)rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SFX_ITEM_ON ) ) + rFont.SetItalic( ((const SvxPostureItem&)rSet.Get( nWhich_Italic )).GetPosture() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SFX_ITEM_ON ) ) + rFont.SetOutline( ((const SvxContourItem&)rSet.Get( EE_CHAR_OUTLINE )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SFX_ITEM_ON ) ) + rFont.SetShadow( ((const SvxShadowedItem&)rSet.Get( EE_CHAR_SHADOW )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SFX_ITEM_ON ) ) + { + const SvxEscapementItem& rEsc = (const SvxEscapementItem&) rSet.Get( EE_CHAR_ESCAPEMENT ); + + USHORT nProp = rEsc.GetProp(); + rFont.SetPropr( (BYTE)nProp ); + + short nEsc = rEsc.GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + nEsc = 100 - nProp; + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + rFont.SetEscapement( nEsc ); + } + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SFX_ITEM_ON ) ) + rFont.SetKerning( ((const SvxAutoKernItem&)rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SFX_ITEM_ON ) ) + rFont.SetFixKerning( ((const SvxKerningItem&)rSet.Get( EE_CHAR_KERNING )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SFX_ITEM_ON ) ) + rFont.SetWordLineMode( ((const SvxWordLineModeItem&)rSet.Get( EE_CHAR_WLM )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SFX_ITEM_ON ) ) + rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem&)rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SFX_ITEM_ON ) ) + rFont.SetRelief( (FontRelief)((const SvxCharReliefItem&)rSet.Get( EE_CHAR_RELIEF )).GetValue() ); + + // Ob ich jetzt den ganzen Font vergleiche, oder vor jeder Aenderung + // pruefe, ob der Wert sich aendert, bleibt sich relativ gleich. + // So ggf ein MakeUniqFont im Font mehr, dafuer bei Aenderung schnellerer + // Abbruch der Abfrage, oder ich musste noch jedesmal ein bChanged pflegen. + if ( rFont == aPrevFont ) + rFont = aPrevFont; // => Gleicher ImpPointer fuer IsSameInstance +} + +void EditDoc::CreateDefFont( BOOL bUseStyles ) +{ + SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END ); + CreateFont( aDefFont, aTmpSet ); + aDefFont.SetVertical( IsVertical() ); + aDefFont.SetOrientation( IsVertical() ? 2700 : 0 ); + + for ( USHORT nNode = 0; nNode < Count(); nNode++ ) + { + ContentNode* pNode = GetObject( nNode ); + pNode->GetCharAttribs().GetDefFont() = aDefFont; + if ( bUseStyles ) + pNode->CreateDefFont(); + } +} + +static const sal_Unicode aCR[] = { 0x0d, 0x00 }; +static const sal_Unicode aLF[] = { 0x0a, 0x00 }; +static const sal_Unicode aCRLF[] = { 0x0d, 0x0a, 0x00 }; + +XubString EditDoc::GetSepStr( LineEnd eEnd ) +{ + XubString aSep; + if ( eEnd == LINEEND_CR ) + aSep = aCR; + else if ( eEnd == LINEEND_LF ) + aSep = aLF; + else + aSep = aCRLF; + return aSep; +} + +XubString EditDoc::GetText( LineEnd eEnd ) const +{ + ULONG nLen = GetTextLen(); + USHORT nNodes = Count(); + + String aSep = EditDoc::GetSepStr( eEnd ); + USHORT nSepSize = aSep.Len(); + + if ( nSepSize ) + nLen += nNodes * nSepSize; + if ( nLen > 0xFFFb / sizeof(xub_Unicode) ) + { + DBG_ERROR( "Text zu gross fuer String" ); + return XubString(); + } + xub_Unicode* pStr = new xub_Unicode[nLen+1]; + xub_Unicode* pCur = pStr; + USHORT nLastNode = nNodes-1; + for ( USHORT nNode = 0; nNode < nNodes; nNode++ ) + { + XubString aTmp( GetParaAsString( GetObject(nNode) ) ); + memcpy( pCur, aTmp.GetBuffer(), aTmp.Len()*sizeof(sal_Unicode) ); + pCur += aTmp.Len(); + if ( nSepSize && ( nNode != nLastNode ) ) + { + memcpy( pCur, aSep.GetBuffer(), nSepSize*sizeof(sal_Unicode ) ); + pCur += nSepSize; + } + } + *pCur = '\0'; + XubString aASCIIText( pStr ); + delete[] pStr; + return aASCIIText; +} + +XubString EditDoc::GetParaAsString( USHORT nNode ) const +{ + return GetParaAsString( SaveGetObject( nNode ) ); +} + +XubString EditDoc::GetParaAsString( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, BOOL bResolveFields ) const +{ + if ( nEndPos > pNode->Len() ) + nEndPos = pNode->Len(); + + DBG_ASSERT( nStartPos <= nEndPos, "Start und Ende vertauscht?" ); + + USHORT nIndex = nStartPos; + XubString aStr; + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); + while ( nIndex < nEndPos ) + { + USHORT nEnd = nEndPos; + if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) ) + nEnd = pNextFeature->GetStart(); + else + pNextFeature = 0; // Feature interessiert unten nicht + + DBG_ASSERT( nEnd >= nIndex, "Ende vorm Index?" ); + //!! beware of sub string length of -1 which is also defined as STRING_LEN and + //!! thus would result in adding the whole sub string up to the end of the node !! + if (nEnd > nIndex) + aStr += XubString( *pNode, nIndex, nEnd - nIndex ); + + if ( pNextFeature ) + { + switch ( pNextFeature->GetItem()->Which() ) + { + case EE_FEATURE_TAB: aStr += '\t'; + break; + case EE_FEATURE_LINEBR: aStr += '\x0A'; + break; + case EE_FEATURE_FIELD: if ( bResolveFields ) + aStr += ((EditCharAttribField*)pNextFeature)->GetFieldValue(); + break; + default: DBG_ERROR( "Was fuer ein Feature ?" ); + } + pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd ); + } + nIndex = nEnd; + } + return aStr; +} + +ULONG EditDoc::GetTextLen() const +{ + ULONG nLen = 0; + for ( USHORT nNode = 0; nNode < Count(); nNode++ ) + { + ContentNode* pNode = GetObject( nNode ); + nLen += pNode->Len(); + // Felder k”nnen laenger sein als der Platzhalter im Node. + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( USHORT nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + USHORT nFieldLen = ((EditCharAttribField*)pAttr)->GetFieldValue().Len(); + if ( !nFieldLen ) + nLen--; + else + nLen += nFieldLen-1; + } + } + } + return nLen; +} + +EditPaM EditDoc::Clear() +{ + ImplDestroyContents(); + + ContentNode* pNode = new ContentNode( GetItemPool() ); + Insert( pNode, 0 ); + + CreateDefFont( FALSE ); + + SetModified( FALSE ); + + EditPaM aPaM( pNode, 0 ); + return aPaM; +} + +void EditDoc::SetModified( BOOL b ) +{ + bModified = b; + if ( bModified ) + { + aModifyHdl.Call( NULL ); + } +} + +EditPaM EditDoc::RemoveText() +{ + // Das alte ItemSetmerken, damit z.B. im Chart Font behalten bleibt + ContentNode* pPrevFirstNode = GetObject(0); + SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet(); + SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() ); + Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() ); + + ImplDestroyContents(); + + ContentNode* pNode = new ContentNode( GetItemPool() ); + Insert( pNode, 0 ); + + pNode->SetStyleSheet( pPrevStyle, FALSE ); + pNode->GetContentAttribs().GetItems().Set( aPrevSet ); + pNode->GetCharAttribs().GetDefFont() = aPrevFont; + + SetModified( TRUE ); + + EditPaM aPaM( pNode, 0 ); + return aPaM; +} + +void EditDoc::InsertText( const EditPaM& rPaM, xub_Unicode c ) +{ + DBG_ASSERT( c != 0x0A, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != 0x0D, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != '\t', "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + + rPaM.GetNode()->Insert( c, rPaM.GetIndex() ); + rPaM.GetNode()->ExpandAttribs( rPaM.GetIndex(), 1, GetItemPool() ); + + SetModified( TRUE ); +} + +EditPaM EditDoc::InsertText( EditPaM aPaM, const XubString& rStr ) +{ + DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" ); + + aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() ); + aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.Len(), GetItemPool() ); + aPaM.GetIndex() = aPaM.GetIndex() + rStr.Len(); + + SetModified( TRUE ); + + return aPaM; +} + +EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, BOOL bKeepEndingAttribs ) +{ + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" ); + ContentNode* pCurNode = aPaM.GetNode(); + USHORT nPos = GetPos( pCurNode ); + XubString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() ); + aPaM.GetNode()->Erase( aPaM.GetIndex() ); + + // the paragraph attributes... + ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() ); + + // for a new paragraph we like to have the bullet/numbering visible by default + aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, TRUE), EE_PARA_BULLETSTATE ); + + // ContenNode-CTOR kopiert auch die Absatzattribute + ContentNode* pNode = new ContentNode( aStr, aContentAttribs ); + + // Den Default-Font kopieren + pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont(); + SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet(); + if ( pStyle ) + { + XubString aFollow( pStyle->GetFollow() ); + if ( aFollow.Len() && ( aFollow != pStyle->GetName() ) ) + { + SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() ); + pNode->SetStyleSheet( (SfxStyleSheet*)pNext ); + } + } + + // Zeichenattribute muessen ggf. kopiert bzw gestutzt werden: + pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs ); + + Insert( pNode, nPos+1 ); + + SetModified( TRUE ); + + aPaM.SetNode( pNode ); + aPaM.SetIndex( 0 ); + return aPaM; +} + +EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem ) +{ + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" ); + + aPaM.GetNode()->Insert( CH_FEATURE, aPaM.GetIndex() ); + aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() ); + + // Fuer das Feature ein Feature-Attribut anlegen... + EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 ); + DBG_ASSERT( pAttrib, "Warum kann ich kein Feature anlegen ?" ); + aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib ); + + SetModified( TRUE ); + + aPaM.GetIndex()++; + return aPaM; +} + +EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight ) +{ + const EditPaM aPaM( pLeft, pLeft->Len() ); + + // Erst die Attribute, da sonst nLen nicht stimmt! + pLeft->AppendAttribs( pRight ); + // Dann den Text... + *pLeft += *pRight; + + // der rechte verschwindet. + RemoveItemsFromPool( pRight ); + USHORT nRight = GetPos( pRight ); + Remove( nRight ); + delete pRight; + + SetModified( TRUE ); + + return aPaM; +} + +EditPaM EditDoc::RemoveChars( EditPaM aPaM, USHORT nChars ) +{ + // Evtl. Features entfernen! + aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars ); + aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() ); + + SetModified( TRUE ); + + return aPaM; +} + +void EditDoc::InsertAttribInSelection( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ) +{ + DBG_ASSERT( pNode, "Wohin mit dem Attribut?" ); + DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" ); + + // fuer Optimierung: + // dieses endet am Anfang der Selektion => kann erweitert werden + EditCharAttrib* pEndingAttrib = 0; + // dieses startet am Ende der Selektion => kann erweitert werden + EditCharAttrib* pStartingAttrib = 0; + + DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" ); + + RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() ); + + if ( pStartingAttrib && pEndingAttrib && + ( *(pStartingAttrib->GetItem()) == rPoolItem ) && + ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) + { + // wird ein groesses Attribut. + pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd(); + GetItemPool().Remove( *(pStartingAttrib->GetItem()) ); + pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) ); + delete pStartingAttrib; + } + else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) ) + pStartingAttrib->GetStart() = nStart; + else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) + pEndingAttrib->GetEnd() = nEnd; + else + InsertAttrib( rPoolItem, pNode, nStart, nEnd ); + + if ( pStartingAttrib ) + pNode->GetCharAttribs().ResortAttribs(); + + SetModified( TRUE ); +} + +BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, USHORT nWhich ) +{ + EditCharAttrib* pStarting; + EditCharAttrib* pEnding; + return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich ); +} + +BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, USHORT nWhich ) +{ + DBG_ASSERT( pNode, "Wohin mit dem Attribut?" ); + DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" ); + + // dieses endet am Anfang der Selektion => kann erweitert werden + rpEnding = 0; + // dieses startet am Ende der Selektion => kann erweitert werden + rpStarting = 0; + + BOOL bChanged = FALSE; + + DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" ); + + // ueber die Attribute iterieren... + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + BOOL bRemoveAttrib = FALSE; + // MT 11.9.97: + // Ich denke dass in dieser Methode generell keine Features geloescht + // werden sollen. + // => Dann koennen die Feature-Abfragen weiter unten entfallen + USHORT nAttrWhich = pAttr->Which(); + if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) ) + { + // Attribut beginnt in Selection + if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) ) + { + bChanged = TRUE; + if ( pAttr->GetEnd() > nEnd ) + { + pAttr->GetStart() = nEnd; // dann faengt es dahinter an + rpStarting = pAttr; + if ( nWhich ) + 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; + } + } + + // Attribut endet in Selection + else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) ) + { + bChanged = TRUE; + if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() ) + { + pAttr->GetEnd() = nStart; // dann hoert es hier auf + rpEnding = pAttr; + } + else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) + { + // Feature nur loeschen, wenn genau an der Stelle + bRemoveAttrib = TRUE; + } + } + // Attribut ueberlappt die Selektion + else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) ) + { + bChanged = TRUE; + if ( pAttr->GetStart() == nStart ) + { + pAttr->GetStart() = nEnd; + rpStarting = pAttr; + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + else if ( pAttr->GetEnd() == nEnd ) + { + pAttr->GetEnd() = nStart; + rpEnding = pAttr; + if ( nWhich ) + 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 ); + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + } + } + if ( bRemoveAttrib ) + { + 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--; + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + + if ( bChanged ) + { + // char attributes need to be sorted by start again + pNode->GetCharAttribs().ResortAttribs(); + + SetModified( TRUE ); + } + + return bChanged; +} + +void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, USHORT nStart, USHORT nEnd ) +{ + // Diese Methode prueft nicht mehr, ob ein entspr. Attribut + // schon an der Stelle existiert! + + EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd ); + DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" ); + pNode->GetCharAttribs().InsertAttrib( pAttrib ); + + SetModified( TRUE ); +} + +void EditDoc::InsertAttrib( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ) +{ + if ( nStart != nEnd ) + { + InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem ); + } + else + { + // Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle: + EditCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart ); + if ( pAttr ) + { + // Attribut entfernen.... + pNode->GetCharAttribs().GetAttribs().Remove( + pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) ); + } + + // pruefen, ob ein 'gleiches' Attribut an der Stelle liegt. + pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart ); + if ( pAttr ) + { + 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; + } + } + InsertAttrib( rPoolItem, pNode, nStart, nStart ); + } + + SetModified( TRUE ); +} + +void EditDoc::FindAttribs( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet ) +{ + DBG_ASSERT( pNode, "Wo soll ich suchen ?" ); + DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" ); + + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + // keine Selection... + if ( nStartPos == nEndPos ) + { + while ( pAttr && ( pAttr->GetStart() <= nEndPos) ) + { + const SfxPoolItem* pItem = 0; + // Attribut liegt dadrueber... + if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) + pItem = pAttr->GetItem(); + // Attribut endet hier, ist nicht leer + else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) + { + if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) ) + pItem = pAttr->GetItem(); + } + // Attribut endet hier, ist leer + else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) + { + pItem = pAttr->GetItem(); + } + // Attribut beginnt hier + else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) + { + if ( nStartPos == 0 ) // Sonderfall + pItem = pAttr->GetItem(); + } + + if ( pItem ) + { + USHORT nWhich = pItem->Which(); + if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + rCurSet.Put( *pItem ); + } + else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rCurSet.Get( nWhich ); + if ( rItem != *pItem ) + { + rCurSet.InvalidateItem( nWhich ); + } + } + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + } + else // Selektion + { + while ( pAttr && ( pAttr->GetStart() < nEndPos) ) + { + const SfxPoolItem* pItem = 0; + // Attribut liegt dadrueber... + if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) ) + pItem = pAttr->GetItem(); + // Attribut startet mitten drin... + else if ( pAttr->GetStart() >= nStartPos ) + { + // !!! pItem = pAttr->GetItem(); + // einfach nur pItem reicht nicht, da ich z.B. bei Shadow + // niemals ein ungleiches Item finden wuerde, da ein solche + // seine Anwesenheit durch Abwesenheit repraesentiert! + // if ( ... ) + // Es muesste geprueft werden, on genau das gleiche Attribut + // an der Bruchstelle aufsetzt, was recht aufwendig ist. + // Da ich beim Einfuegen von Attributen aber etwas optimiere + // tritt der Fall nicht so schnell auf... + // Also aus Geschwindigkeitsgruenden: + rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); + + } + // Attribut endet mitten drin... + else if ( pAttr->GetEnd() > nStartPos ) + { + // pItem = pAttr->GetItem(); + // s.o. + /*-----------------31.05.95 16:01------------------- + 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() ); + } + + if ( pItem ) + { + USHORT nWhich = pItem->Which(); + if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + rCurSet.Put( *pItem ); + } + else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rCurSet.Get( nWhich ); + if ( rItem != *pItem ) + { + rCurSet.InvalidateItem( nWhich ); + } + } + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + } +} + + +// ------------------------------------------------------------------------- +// class EditCharAttribList +// ------------------------------------------------------------------------- + +CharAttribList::CharAttribList() +{ + DBG_CTOR( EE_CharAttribList, 0 ); + bHasEmptyAttribs = FALSE; +} + +CharAttribList::~CharAttribList() +{ + DBG_DTOR( EE_CharAttribList, 0 ); + + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr ) + { + delete pAttr; + ++nAttr; + pAttr = GetAttrib( aAttribs, nAttr ); + } + Clear(); +} + +void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib ) +{ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// optimieren: binaere Suche ? ! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // MT: 26.11.98 + // Vielleicht aber auch einfach nur rueckwaerts iterieren: + // Der haeufigste und kritischste Fall: Attribute kommen bereits + // sortiert an (InsertBinTextObject!) + // Hier waere auch binaere Suche nicht optimal. + // => Wuerde einiges bringen! + + const USHORT nCount = Count(); + const USHORT nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt. + + if ( pAttrib->IsEmpty() ) + bHasEmptyAttribs = TRUE; + + BOOL bInserted = FALSE; + for ( USHORT x = 0; x < nCount; x++ ) + { + EditCharAttribPtr pCurAttrib = aAttribs[x]; + if ( pCurAttrib->GetStart() > nStart ) + { + aAttribs.Insert( pAttrib, x ); + bInserted = TRUE; + break; + } + } + if ( !bInserted ) + aAttribs.Insert( pAttrib, nCount ); +} + +void CharAttribList::ResortAttribs() +{ + if ( Count() ) + { +#if defined __SUNPRO_CC +#pragma disable_warn +#endif + qsort( (void*)aAttribs.GetData(), aAttribs.Count(), sizeof( EditCharAttrib* ), CompareStart ); +#if defined __SUNPRO_CC +#pragma enable_warn +#endif + } +} + +void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool ) +{ + for ( USHORT n = 0; n < aAttribs.Count(); n++ ) + { + EditCharAttrib* pAttr = aAttribs.GetObject( n ); + for ( USHORT nNext = n+1; nNext < aAttribs.Count(); nNext++ ) + { + EditCharAttrib* p = aAttribs.GetObject( nNext ); + if ( !pAttr->IsFeature() && ( p->GetStart() == pAttr->GetEnd() ) && ( p->Which() == pAttr->Which() ) ) + { + if ( *p->GetItem() == *pAttr->GetItem() ) + { + pAttr->GetEnd() = p->GetEnd(); + aAttribs.Remove( nNext ); + rItemPool.Remove( *p->GetItem() ); + delete p; + } + break; // only 1 attr with same which can start here. + } + else if ( p->GetStart() > pAttr->GetEnd() ) + { + break; + } + } + } +} + +EditCharAttrib* CharAttribList::FindAttrib( USHORT nWhich, USHORT nPos ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + USHORT nAttr = aAttribs.Count()-1; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr ) + { + if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) ) + return pAttr; + pAttr = GetAttrib( aAttribs, --nAttr ); + } + return 0; +} + +EditCharAttrib* CharAttribList::FindNextAttrib( USHORT nWhich, USHORT nFromPos ) const +{ + DBG_ASSERT( nWhich, "FindNextAttrib: Which?" ); + const USHORT nAttribs = aAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[ nAttr ]; + if ( ( pAttr->GetStart() >= nFromPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + } + return 0; +} + +BOOL CharAttribList::HasAttrib( USHORT nWhich ) const +{ + for ( USHORT nAttr = aAttribs.Count(); nAttr; ) + { + const EditCharAttrib* pAttr = aAttribs[--nAttr]; + if ( pAttr->Which() == nWhich ) + return TRUE; + } + return FALSE; +} + +BOOL CharAttribList::HasAttrib( USHORT nStartPos, USHORT nEndPos ) const +{ + BOOL bAttr = FALSE; + for ( USHORT nAttr = aAttribs.Count(); nAttr && !bAttr; ) + { + const EditCharAttrib* pAttr = aAttribs[--nAttr]; + if ( ( pAttr->GetStart() < nEndPos ) && ( pAttr->GetEnd() > nStartPos ) ) + return bAttr = TRUE; + } + return bAttr; +} + + +BOOL CharAttribList::HasBoundingAttrib( USHORT nBound ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + USHORT nAttr = aAttribs.Count()-1; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr && ( pAttr->GetEnd() >= nBound ) ) + { + if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) ) + return TRUE; + pAttr = GetAttrib( aAttribs, --nAttr ); + } + return FALSE; +} + +EditCharAttrib* CharAttribList::FindEmptyAttrib( USHORT nWhich, USHORT nPos ) +{ + if ( !bHasEmptyAttribs ) + return 0; + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr && ( pAttr->GetStart() <= nPos ) ) + { + if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + nAttr++; + pAttr = GetAttrib( aAttribs, nAttr ); + } + return 0; +} + +EditCharAttrib* CharAttribList::FindFeature( USHORT nPos ) const +{ + + USHORT nAttr = 0; + EditCharAttrib* pNextAttrib = GetAttrib( aAttribs, nAttr ); + + // erstmal zur gewuenschten Position... + while ( pNextAttrib && ( pNextAttrib->GetStart() < nPos ) ) + { + nAttr++; + pNextAttrib = GetAttrib( aAttribs, nAttr ); + } + + // jetzt das Feature suchen... + while ( pNextAttrib && !pNextAttrib->IsFeature() ) + { + nAttr++; + pNextAttrib = GetAttrib( aAttribs, nAttr ); + } + + return pNextAttrib; +} + + +void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool ) +{ + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[nAttr]; + if ( pAttr->IsEmpty() ) + { + rItemPool.Remove( *pAttr->GetItem() ); + aAttribs.Remove( nAttr ); + delete pAttr; + nAttr--; + } + } + bHasEmptyAttribs = FALSE; +} + +BOOL CharAttribList::DbgCheckAttribs() +{ +#ifdef DBG_UTIL + BOOL bOK = TRUE; + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[nAttr]; + if ( pAttr->GetStart() > pAttr->GetEnd() ) + { + bOK = FALSE; + DBG_ERROR( "Attr verdreht" ); + } + else if ( pAttr->IsFeature() && ( pAttr->GetLen() != 1 ) ) + { + bOK = FALSE; + DBG_ERROR( "Feature, Len != 1" ); + } + } + return bOK; +#else + return TRUE; +#endif +} + + + +SvxFontTable::SvxFontTable() +{ +} + +SvxFontTable::~SvxFontTable() +{ + SvxFontItem* pItem = First(); + while( pItem ) + { + delete pItem; + pItem = Next(); + } +} + +ULONG SvxFontTable::GetId( const SvxFontItem& rFontItem ) +{ + SvxFontItem* pItem = First(); + while ( pItem ) + { + if ( *pItem == rFontItem ) + return GetCurKey(); + pItem = Next(); + } + DBG_WARNING( "Font nicht gefunden: GetId()" ); + return 0; +} + +SvxColorList::SvxColorList() +{ +} + +SvxColorList::~SvxColorList() +{ + SvxColorItem* pItem = First(); + while( pItem ) + { + delete pItem; + pItem = Next(); + } +} + +ULONG SvxColorList::GetId( const SvxColorItem& rColorItem ) +{ + SvxColorItem* pItem = First(); + while ( pItem ) + { + if ( *pItem == rColorItem ) + return GetCurPos(); + pItem = Next(); + } + DBG_WARNING( "Color nicht gefunden: GetId()" ); + return 0; +} + +EditEngineItemPool::EditEngineItemPool( BOOL bPersistenRefCounts ) + : SfxItemPool( String( "EditEngineItemPool", RTL_TEXTENCODING_ASCII_US ), EE_ITEMS_START, EE_ITEMS_END, + aItemInfos, 0, bPersistenRefCounts ) +{ + SetVersionMap( 1, 3999, 4015, aV1Map ); + SetVersionMap( 2, 3999, 4019, aV2Map ); + SetVersionMap( 3, 3997, 4020, aV3Map ); + SetVersionMap( 4, 3994, 4022, aV4Map ); + SetVersionMap( 5, 3994, 4037, aV5Map ); + + DBG_ASSERT( EE_DLL(), "EditDLL?!" ); + SfxPoolItem** ppDefItems = EE_DLL()->GetGlobalData()->GetDefItems(); + SetDefaults( ppDefItems ); +} + +EditEngineItemPool::~EditEngineItemPool() +{ +} + +SvStream& EditEngineItemPool::Store( SvStream& rStream ) const +{ + // Bei einem 3.1-Export muess ein Hack eingebaut werden, da BUG im + // SfxItemSet::Load, aber nicht nachtraeglich in 3.1 fixbar. + + // Der eingestellte Range muss nach Store erhalten bleiben, weil dann + // erst die ItemSets gespeichert werden... + + long nVersion = rStream.GetVersion(); + BOOL b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) ) + ? TRUE : FALSE; + + EditEngineItemPool* pThis = (EditEngineItemPool*)this; + if ( b31Format ) + pThis->SetStoringRange( 3997, 4022 ); + else + pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END ); + + return SfxItemPool::Store( rStream ); +} |