/* -*- 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qsort using namespace ::com::sun::star; // ------------------------------------------------------------ sal_uInt16 GetScriptItemId( sal_uInt16 nItemId, short nScriptType ) { sal_uInt16 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; } sal_Bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType ) { sal_Bool bValid = sal_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; } // ------------------------------------------------------------ // Should later be moved to TOOLS/STRING (Current: 303) // for 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 }, // EE_PARA_OUTLLEVEL { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE }, // EE_PARA_BULLET { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_LRSPACE { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_ULSPACE { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE }, // EE_PARA_SBL { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE }, // EE_PARA_JUST { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE }, // EE_PARA_TABS { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, SFX_ITEM_POOLABLE }, // EE_PARA_JUST_METHOD { SID_ATTR_ALIGN_VER_JUSTIFY, SFX_ITEM_POOLABLE }, // EE_PARA_VER_JUST { 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 } }; sal_uInt16 aV1Map[] = { 3999, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019? }; sal_uInt16 aV2Map[] = { 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020 }; sal_uInt16 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 }; sal_uInt16 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 }; sal_uInt16 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* ); 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, sal_uInt16 nS, sal_uInt16 nE ) { // Create a new attribute in the pool 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 ); // Attribute 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: { OSL_FAIL( "Invalid Attribute!" ); } } return pNew; } EditLine::EditLine() { DBG_CTOR( EE_EditLine, 0 ); nStart = nEnd = 0; nStartPortion = 0; // to be able to tell the difference between a line // without Ptorions form one with the Portion number 0 nEndPortion = 0; nHeight = 0; nStartPosX = 0; nTxtHeight = 0; nTxtWidth = 0; nCrsrHeight = 0; nMaxAscent = 0; bHangingPunctuation = sal_False; bInvalid = sal_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 = sal_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; } sal_Bool operator == ( const EditLine& r1, const EditLine& r2 ) { if ( r1.nStart != r2.nStart ) return sal_False; if ( r1.nEnd != r2.nEnd ) return sal_False; if ( r1.nStartPortion != r2.nStartPortion ) return sal_False; if ( r1.nEndPortion != r2.nEndPortion ) return sal_False; return sal_True; } EditLine& EditLine::operator = ( const EditLine& r ) { nEnd = r.nEnd; nStart = r.nStart; nEndPortion = r.nEndPortion; nStartPortion = r.nStartPortion; return *this; } sal_Bool operator != ( const EditLine& r1, const EditLine& r2 ) { return !( r1 == r2 ); } Size EditLine::CalcTextSize( ParaPortion& rParaPortion ) { Size aSz; Size aTmpSz; TextPortion* pPortion; sal_uInt16 nIndex = GetStart(); DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize before CreatePortions !" ); for ( sal_uInt16 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: { aSz.Width() += pPortion->GetSize().Width(); } break; } nIndex = nIndex + pPortion->GetLen(); } SetHeight( (sal_uInt16)aSz.Height() ); return aSz; } EditLineList::EditLineList() { } EditLineList::~EditLineList() { Reset(); } void EditLineList::Reset() { for ( sal_uInt16 nLine = 0; nLine < Count(); nLine++ ) delete GetObject(nLine); Remove( 0, Count() ); } void EditLineList::DeleteFromLine( sal_uInt16 nDelFrom ) { DBG_ASSERT( nDelFrom <= (Count() - 1), "DeleteFromLine: Out of range" ); for ( sal_uInt16 nL = nDelFrom; nL < Count(); nL++ ) delete GetObject(nL); Remove( nDelFrom, Count()-nDelFrom ); } sal_uInt16 EditLineList::FindLine( sal_uInt16 nChar, sal_Bool bInclEnd ) { for ( sal_uInt16 nLine = 0; nLine < Count(); nLine++ ) { EditLine* pLine = GetObject( nLine ); if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || ( pLine->GetEnd() > nChar ) ) { return nLine; } } DBG_ASSERT( !bInclEnd, "Line not found: FindLine" ); return ( Count() - 1 ); } sal_Bool EditPaM::DbgIsBuggy( EditDoc& rDoc ) { if ( !pNode ) return sal_True; if ( rDoc.GetPos( pNode ) >= rDoc.Count() ) return sal_True; if ( nIndex > pNode->Len() ) return sal_True; return sal_False; } sal_Bool EditSelection::DbgIsBuggy( EditDoc& rDoc ) { if ( aStartPaM.DbgIsBuggy( rDoc ) ) return sal_True; if ( aEndPaM.DbgIsBuggy( rDoc ) ) return sal_True; return sal_False; } EditSelection::EditSelection() { } EditSelection::EditSelection( const EditPaM& rStartAndAnd ) { // could still be optimized! // do no first call the Def-constructor from PaM! aStartPaM = rStartAndAnd; aEndPaM = rStartAndAnd; } EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd ) { // could still be optimized! aStartPaM = rStart; aEndPaM = rEnd; } EditSelection& EditSelection::operator = ( const EditPaM& rPaM ) { aStartPaM = rPaM; aEndPaM = rPaM; return *this; } sal_Bool EditSelection::IsInvalid() const { EditPaM aEmptyPaM; if ( aStartPaM == aEmptyPaM ) return sal_True; if ( aEndPaM == aEmptyPaM ) return sal_True; return sal_False; } sal_Bool EditSelection::Adjust( const ContentList& rNodes ) { DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in Adjust(1)" ); DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in Adjust(2)" ); ContentNode* pStartNode = aStartPaM.GetNode(); ContentNode* pEndNode = aEndPaM.GetNode(); sal_uInt16 nStartNode = rNodes.GetPos( pStartNode ); sal_uInt16 nEndNode = rNodes.GetPos( pEndNode ); DBG_ASSERT( nStartNode != USHRT_MAX, "Node out of range in Adjust(1)" ); DBG_ASSERT( nEndNode != USHRT_MAX, "Node out of range in Adjust(2)" ); sal_Bool bSwap = sal_False; if ( nStartNode > nEndNode ) bSwap = sal_True; else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) ) bSwap = sal_True; if ( bSwap ) { EditPaM aTmpPaM( aStartPaM ); aStartPaM = aEndPaM; aEndPaM = aTmpPaM; } return bSwap; } sal_Bool operator == ( const EditPaM& r1, const EditPaM& r2 ) { if ( r1.GetNode() != r2.GetNode() ) return sal_False; if ( r1.GetIndex() != r2.GetIndex() ) return sal_False; return sal_True; } EditPaM& EditPaM::operator = ( const EditPaM& rPaM ) { nIndex = rPaM.nIndex; pNode = rPaM.pNode; return *this; } sal_Bool operator != ( const EditPaM& r1, const EditPaM& r2 ) { return !( r1 == r2 ); } 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 ); delete pWrongList; } void ContentNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew, SfxItemPool& rItemPool ) { if ( !nNew ) return; // Since features are treated differently than normal character attributes, // can also the order of the start list be change! // In every if ..., in the next (n) opportunities due to bFeature or // an existing special case, must (n-1) opportunities be provided with // bResort. The most likely possibility receives no bResort, so that is // not sorted anew when all attributes are the same. sal_Bool bResort = sal_False; sal_Bool bExpandedEmptyAtIndexNull = sal_False; sal_uInt16 nAttr = 0; EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); while ( pAttrib ) { if ( pAttrib->GetEnd() >= nIndex ) { // Move all attributes behind the insertion point... if ( pAttrib->GetStart() > nIndex ) { pAttrib->MoveForward( nNew ); } // 0: Expand empty attribute, if at insertion point else if ( pAttrib->IsEmpty() ) { // Do not check Index, a emty one could only be there // When later checking it anyhow: // Special caase: Start == 0; AbsLen == 1, nNew = 1 // => Expand, because of paragraph break! // Start <= nIndex, End >= nIndex => Start=End=nIndex! // if ( pAttrib->GetStart() == nIndex ) pAttrib->Expand( nNew ); if ( pAttrib->GetStart() == 0 ) bExpandedEmptyAtIndexNull = sal_True; } // 1: Attribute starts before, goes to index ... else if ( pAttrib->GetEnd() == nIndex ) // Start must be before { // Only expand when there is no feature // and if not in exclude list! // Otherwise, a UL will go on until a new ULDB, expaning both // if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) ) if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) ) { if ( !pAttrib->IsEdge() ) pAttrib->Expand( nNew ); } else bResort = sal_True; } // 2: Attribute starts before, goes past the Index... else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) { DBG_ASSERT( !pAttrib->IsFeature(), "Large Feature?!" ); pAttrib->Expand( nNew ); } // 3: Attribute starts on index... else if ( pAttrib->GetStart() == nIndex ) { if ( pAttrib->IsFeature() ) { pAttrib->MoveForward( nNew ); bResort = sal_True; } else { sal_Bool bExpand = sal_False; if ( nIndex == 0 ) { bExpand = sal_True; if( bExpandedEmptyAtIndexNull ) { // Check if this kind of attribut was empty and expanded here... sal_uInt16 nW = pAttrib->GetItem()->Which(); for ( sal_uInt16 nA = 0; nA < nAttr; nA++ ) { EditCharAttrib* pA = aCharAttribList.GetAttribs()[nA]; if ( ( pA->GetStart() == 0 ) && ( pA->GetItem()->Which() == nW ) ) { bExpand = sal_False; break; } } } } if ( bExpand ) { pAttrib->Expand( nNew ); bResort = sal_True; } else { pAttrib->MoveForward( nNew ); } } } } if ( pAttrib->IsEdge() ) pAttrib->SetEdge( sal_False ); DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribute distorted!" ); DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attribute larger than paragraph!" ); if ( pAttrib->IsEmpty() ) { OSL_FAIL( "Empty Attribute after ExpandAttribs?" ); bResort = sal_True; aCharAttribList.GetAttribs().Remove( nAttr ); rItemPool.Remove( *pAttrib->GetItem() ); delete pAttrib; nAttr--; } nAttr++; pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); } if ( bResort ) aCharAttribList.ResortAttribs(); if ( pWrongList ) { sal_Bool bSep = ( GetChar( nIndex ) == ' ' ) || IsFeature( nIndex ); pWrongList->TextInserted( nIndex, nNew, bSep ); } #if OSL_DEBUG_LEVEL > 2 OSL_ENSURE( CheckOrderedList( aCharAttribList.GetAttribs(), sal_True ), "Expand: Start List distorted" ); #endif } void ContentNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted, SfxItemPool& rItemPool ) { if ( !nDeleted ) return; // Since features are treated differently than normal character attributes, // can also the order of the start list be change! sal_Bool bResort = sal_False; sal_Bool bDelAttr = sal_False; sal_uInt16 nEndChanges = nIndex+nDeleted; sal_uInt16 nAttr = 0; EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); while ( pAttrib ) { bDelAttr = sal_False; if ( pAttrib->GetEnd() >= nIndex ) { // Move all Attribute behind the insert point... if ( pAttrib->GetStart() >= nEndChanges ) { pAttrib->MoveBackward( nDeleted ); } // 1. Delete Internal attributes... else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) ) { // Special case: Attribute covers the area exactly // => keep as empty Attribute. if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) ) pAttrib->GetEnd() = nIndex; // empty else bDelAttr = sal_True; } // 2. Attribute starts earlier, ends inside or behind it ... else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) { DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" ); if ( pAttrib->GetEnd() <= nEndChanges ) // ends inside pAttrib->GetEnd() = nIndex; else pAttrib->Collaps( nDeleted ); // ends behind } // 3. Attribute starts inside, ending behind ... else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) ) { // Features not allowed to expand! if ( pAttrib->IsFeature() ) { pAttrib->MoveBackward( nDeleted ); bResort = sal_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 distorted!" ); DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attribute larger than paragraph!" ); if ( bDelAttr ) { bResort = sal_True; aCharAttribList.GetAttribs().Remove( nAttr ); rItemPool.Remove( *pAttrib->GetItem() ); delete pAttrib; nAttr--; } else if ( pAttrib->IsEmpty() ) aCharAttribList.HasEmptyAttribs() = sal_True; nAttr++; pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); } if ( bResort ) aCharAttribList.ResortAttribs(); if ( pWrongList ) pWrongList->TextDeleted( nIndex, nDeleted ); #if OSL_DEBUG_LEVEL > 2 OSL_ENSURE( CheckOrderedList( aCharAttribList.GetAttribs(), sal_True ), "Collaps: Start list distorted" ); #endif } void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, sal_Bool bKeepEndingAttribs ) { DBG_ASSERT( pPrevNode, "Copy of attributes to a null pointer?" ); xub_StrLen nCut = pPrevNode->Len(); sal_uInt16 nAttr = 0; EditCharAttrib* pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); while ( pAttrib ) { if ( pAttrib->GetEnd() < nCut ) { // remain unchanged .... ; } else if ( pAttrib->GetEnd() == nCut ) { // must be copied as an empty attributes. if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) ) { EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 ); DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" ); aCharAttribList.InsertAttrib( pNewAttrib ); } } else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) ) { // If cut is done right at the front then the attribute must be // kept! Has to be copied and changed. EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut ); DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" ); aCharAttribList.InsertAttrib( pNewAttrib ); pAttrib->GetEnd() = nCut; } else { // Move all attributes in the current 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, "Copy of attributes to a null pointer?" ); sal_uInt16 nNewStart = Len(); #if OSL_DEBUG_LEVEL > 2 OSL_ENSURE( aCharAttribList.DbgCheckAttribs(), "Attribute before AppendAttribs broken" ); #endif sal_uInt16 nAttr = 0; EditCharAttrib* pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); while ( pAttrib ) { // Move all attributes in the current node (this) sal_Bool bMelted = sal_False; if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) ) { // Attributes can possibly be summarized as: sal_uInt16 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 ); // Unsubscribe from the pool?! delete pAttrib; bMelted = sal_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 ); } // For the Attributes that just moved over: pNextNode->GetCharAttribs().Clear(); #if OSL_DEBUG_LEVEL > 2 OSL_ENSURE( aCharAttribList.DbgCheckAttribs(), "Attribute after AppendAttribs broken" ); #endif } void ContentNode::CreateDefFont() { // First use the information from the style ... SfxStyleSheet* pS = aContentAttribs.GetStyleSheet(); if ( pS ) CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() ); // ... then iron out the hard paragraph formatting... CreateFont( GetCharAttribs().GetDefFont(), GetContentAttribs().GetItems(), pS == NULL ); } void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle ) { aContentAttribs.SetStyleSheet( pS ); // First use the information from the style ... GetCharAttribs().GetDefFont() = rFontFromStyle; // ... then iron out the hard paragraph formatting... CreateFont( GetCharAttribs().GetDefFont(), GetContentAttribs().GetItems(), pS == NULL ); } void ContentNode::SetStyleSheet( SfxStyleSheet* pS, sal_Bool bRecalcFont ) { aContentAttribs.SetStyleSheet( pS ); if ( bRecalcFont ) CreateDefFont(); } void ContentNode::DestroyWrongList() { delete pWrongList; pWrongList = NULL; } void ContentNode::CreateWrongList() { DBG_ASSERT( !pWrongList, "WrongList already exist!" ); pWrongList = new WrongList; } void ContentNode::SetWrongList( WrongList* p ) { DBG_ASSERT( !pWrongList, "WrongList already exist!" ); pWrongList = p; } 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, sal_uInt16 nDefTab ) { const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS ); for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ ) { const SvxTabStop& rTab = rTabs[i]; if ( rTab.GetTabPos() > nCurPos ) return rTab; } // Determine DefTab ... SvxTabStop aTabStop; long x = nCurPos / nDefTab + 1; aTabStop.GetTabPos() = nDefTab * x; return aTabStop; } void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS ) { sal_Bool bStyleChanged = ( pStyle != pS ); pStyle = pS; // Only when other style sheet, not when current style sheet modified if ( pStyle && bStyleChanged ) { // Selectively remove the attributes from the paragraph formatting // which are specified in the style, so that the attributes of the // style can have an affect. const SfxItemSet& rStyleAttribs = pStyle->GetItemSet(); for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) { // Don't change bullet on/off if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) ) aAttribSet.ClearItem( nWhich ); } } } const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich ) { // Hard paragraph attributes take precedence! SfxItemSet* pTakeFrom = &aAttribSet; if ( pStyle && ( aAttribSet.GetItemState( nWhich, sal_False ) != SFX_ITEM_ON ) ) pTakeFrom = &pStyle->GetItemSet(); return pTakeFrom->Get( nWhich ); } sal_Bool ContentAttribs::HasItem( sal_uInt16 nWhich ) { sal_Bool bHasItem = sal_False; if ( aAttribSet.GetItemState( nWhich, sal_False ) == SFX_ITEM_ON ) bHasItem = sal_True; else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON ) bHasItem = sal_True; return bHasItem; } ItemList::ItemList() : CurrentItem( 0 ) { } const SfxPoolItem* ItemList::FindAttrib( sal_uInt16 nWhich ) { for ( size_t i = 0, n = aItemPool.size(); i < n; ++i ) if ( aItemPool[ i ]->Which() == nWhich ) return aItemPool[ i ]; return NULL; } const SfxPoolItem* ItemList::First() { CurrentItem = 0; return aItemPool.empty() ? NULL : aItemPool[ 0 ]; } const SfxPoolItem* ItemList::Next() { if ( CurrentItem + 1 < aItemPool.size() ) { ++CurrentItem; return aItemPool[ CurrentItem ]; } return NULL; } void ItemList::Insert( const SfxPoolItem* pItem ) { aItemPool.push_back( pItem ); CurrentItem = aItemPool.size() - 1; } EditDoc::EditDoc( SfxItemPool* pPool ) { if ( pPool ) { pItemPool = pPool; bOwnerOfPool = sal_False; } else { pItemPool = new EditEngineItemPool( sal_False ); bOwnerOfPool = sal_True; } nDefTab = DEFTAB; bIsVertical = sal_False; bIsFixedCellHeight = sal_False; // Don't create a empty node, Clear() will be called in EditEngine-CTOR SetModified( sal_False ); }; EditDoc::~EditDoc() { ImplDestroyContents(); if ( bOwnerOfPool ) SfxItemPool::Free(pItemPool); } void EditDoc::ImplDestroyContents() { for ( sal_uInt16 nNode = Count(); nNode; ) RemoveItemsFromPool( GetObject( --nNode ) ); DeleteAndDestroy( 0, Count() ); } void EditDoc::RemoveItemsFromPool( ContentNode* pNode ) { for ( sal_uInt16 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( sal_True ); sal_uInt16 nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ); sal_uInt16 nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); sal_uInt16 nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ); sal_uInt16 nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ); sal_uInt16 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 ); sal_uInt16 nProp = rEsc.GetProp(); rFont.SetPropr( (sal_uInt8)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() ); // If comparing the entire font, or if checking before each alteration // whether the value changes, remains relatively the same thing. // So possible one MakeUniqFont more in the font, but as a result a quicker // abortion of the query, or one must each time check bChanged. if ( rFont == aPrevFont ) rFont = aPrevFont; // => The same ImpPointer for IsSameInstance } void EditDoc::CreateDefFont( sal_Bool bUseStyles ) { SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END ); CreateFont( aDefFont, aTmpSet ); aDefFont.SetVertical( IsVertical() ); aDefFont.SetOrientation( IsVertical() ? 2700 : 0 ); for ( sal_uInt16 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 { sal_uLong nLen = GetTextLen(); sal_uInt16 nNodes = Count(); String aSep = EditDoc::GetSepStr( eEnd ); sal_uInt16 nSepSize = aSep.Len(); if ( nSepSize ) nLen += nNodes * nSepSize; if ( nLen > 0xFFFb / sizeof(xub_Unicode) ) { OSL_FAIL( "Text to large for String" ); return XubString(); } xub_Unicode* pStr = new xub_Unicode[nLen+1]; xub_Unicode* pCur = pStr; sal_uInt16 nLastNode = nNodes-1; for ( sal_uInt16 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( sal_uInt16 nNode ) const { return GetParaAsString( SaveGetObject( nNode ) ); } XubString EditDoc::GetParaAsString( ContentNode* pNode, sal_uInt16 nStartPos, sal_uInt16 nEndPos, sal_Bool bResolveFields ) const { if ( nEndPos > pNode->Len() ) nEndPos = pNode->Len(); DBG_ASSERT( nStartPos <= nEndPos, "Start and End reversed?" ); sal_uInt16 nIndex = nStartPos; XubString aStr; EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); while ( nIndex < nEndPos ) { sal_uInt16 nEnd = nEndPos; if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) ) nEnd = pNextFeature->GetStart(); else pNextFeature = 0; // Feature does not interest the below DBG_ASSERT( nEnd >= nIndex, "End in front of the 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: OSL_FAIL( "What feature?" ); } pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd ); } nIndex = nEnd; } return aStr; } sal_uLong EditDoc::GetTextLen() const { sal_uLong nLen = 0; for ( sal_uInt16 nNode = 0; nNode < Count(); nNode++ ) { ContentNode* pNode = GetObject( nNode ); nLen += pNode->Len(); // Fields can be longer than the placeholder in the Node const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) { EditCharAttrib* pAttr = rAttrs[--nAttr]; if ( pAttr->Which() == EE_FEATURE_FIELD ) { sal_uInt16 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( sal_False ); SetModified( sal_False ); EditPaM aPaM( pNode, 0 ); return aPaM; } void EditDoc::SetModified( sal_Bool b ) { bModified = b; if ( bModified ) { aModifyHdl.Call( NULL ); } } EditPaM EditDoc::RemoveText() { // Keep the old ItemSet, to keep the chart Font. 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, sal_False ); pNode->GetContentAttribs().GetItems().Set( aPrevSet ); pNode->GetCharAttribs().GetDefFont() = aPrevFont; SetModified( sal_True ); EditPaM aPaM( pNode, 0 ); return aPaM; } void EditDoc::InsertText( const EditPaM& rPaM, xub_Unicode c ) { DBG_ASSERT( c != 0x0A, "EditDoc::InsertText: Newlines prohibited in paragraph!" ); DBG_ASSERT( c != 0x0D, "EditDoc::InsertText: Newlines prohibited in paragraph!" ); DBG_ASSERT( c != '\t', "EditDoc::InsertText: Newlines prohibited in paragraph!" ); rPaM.GetNode()->Insert( c, rPaM.GetIndex() ); rPaM.GetNode()->ExpandAttribs( rPaM.GetIndex(), 1, GetItemPool() ); SetModified( sal_True ); } EditPaM EditDoc::InsertText( EditPaM aPaM, const XubString& rStr ) { DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "EditDoc::InsertText: Newlines prohibited in paragraph!" ); DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "EditDoc::InsertText: Newlines prohibited in paragraph!" ); DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "EditDoc::InsertText: Newlines prohibited in paragraph!" ); 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( sal_True ); return aPaM; } EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, sal_Bool bKeepEndingAttribs ) { DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" ); ContentNode* pCurNode = aPaM.GetNode(); sal_uInt16 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, sal_True), EE_PARA_BULLETSTATE ); // ContenNode constructor copies also the paragraph attributes ContentNode* pNode = new ContentNode( aStr, aContentAttribs ); // Copy the Default Font 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 ); } } // Character attributes may need to be copied or trimmed: pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs ); Insert( pNode, nPos+1 ); SetModified( sal_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() ); // Create a feature-attribute for the feature... EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 ); DBG_ASSERT( pAttrib, "Why can not the feature be created?" ); aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib ); SetModified( sal_True ); aPaM.GetIndex()++; return aPaM; } EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight ) { const EditPaM aPaM( pLeft, pLeft->Len() ); // First the attributes, otherwise nLen will not be correct! pLeft->AppendAttribs( pRight ); // then the Text... *pLeft += *pRight; // the one to the right disappears. RemoveItemsFromPool( pRight ); sal_uInt16 nRight = GetPos( pRight ); Remove( nRight ); delete pRight; SetModified( sal_True ); return aPaM; } EditPaM EditDoc::RemoveChars( EditPaM aPaM, sal_uInt16 nChars ) { // Maybe remove Features! aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars ); aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() ); SetModified( sal_True ); return aPaM; } void EditDoc::InsertAttribInSelection( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem ) { DBG_ASSERT( pNode, "What to do with the attribute?" ); DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribute to large!" ); // for Optimization: // This ends at the beginning of the selection => can be expanded EditCharAttrib* pEndingAttrib = 0; // This starts at the end of the selection => can be expanded EditCharAttrib* pStartingAttrib = 0; DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" ); RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() ); if ( pStartingAttrib && pEndingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) && ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) { // Will become a large Attribute. 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( sal_True ); } sal_Bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, sal_uInt16 nWhich ) { EditCharAttrib* pStarting; EditCharAttrib* pEnding; return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich ); } sal_Bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, sal_uInt16 nWhich ) { DBG_ASSERT( pNode, "What to do with the attribute?" ); DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribute to large!" ); // This ends at the beginning of the selection => can be expanded rpEnding = 0; // This starts at the end of the selection => can be expanded rpStarting = 0; sal_Bool bChanged = sal_False; DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" ); // iterate over the attributes ... sal_uInt16 nAttr = 0; EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); while ( pAttr ) { sal_Bool bRemoveAttrib = sal_False; sal_uInt16 nAttrWhich = pAttr->Which(); if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) ) { // Attribute starts in Selection if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) ) { bChanged = sal_True; if ( pAttr->GetEnd() > nEnd ) { pAttr->GetStart() = nEnd; // then it starts after this rpStarting = pAttr; if ( nWhich ) break; // There can be no further attributes here } else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) { // Delete feature only if on the exact spot bRemoveAttrib = sal_True; } } // Attribute ends in Selection else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) ) { bChanged = sal_True; if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() ) { pAttr->GetEnd() = nStart; // then it ends here rpEnding = pAttr; } else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) { // Delete feature only if on the exact spot bRemoveAttrib = sal_True; } } // Attribute overlaps the selection else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) ) { bChanged = sal_True; if ( pAttr->GetStart() == nStart ) { pAttr->GetStart() = nEnd; rpStarting = pAttr; if ( nWhich ) break; // There can be further attributes! } else if ( pAttr->GetEnd() == nEnd ) { pAttr->GetEnd() = nStart; rpEnding = pAttr; if ( nWhich ) break; // There can be further attributes! } else // Attribute must be split ... { sal_uInt16 nOldEnd = pAttr->GetEnd(); pAttr->GetEnd() = nStart; rpEnding = pAttr; InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd ); if ( nWhich ) break; // There can be further attributes! } } } if ( bRemoveAttrib ) { DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Delete and retain the same attribute?" ); 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( sal_True ); } return bChanged; } void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd ) { // This method no longer checks whether a corresponding attribute already // exists at this place! EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd ); DBG_ASSERT( pAttrib, "MakeCharAttrib failed!" ); pNode->GetCharAttribs().InsertAttrib( pAttrib ); SetModified( sal_True ); } void EditDoc::InsertAttrib( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem ) { if ( nStart != nEnd ) { InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem ); } else { // Check whether already a new attribute with WhichId exists at this place: EditCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart ); if ( pAttr ) { // Remove attribute.... pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) ); } // check whether 'the same' attribute exist at this place. pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart ); if ( pAttr ) { if ( pAttr->IsInside( nStart ) ) // split { // check again if really splitting, or return ! sal_uInt16 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(), "Still an empty attribute?" ); // Check if exactly the same attribute if ( *(pAttr->GetItem()) == rPoolItem ) return; } } InsertAttrib( rPoolItem, pNode, nStart, nStart ); } SetModified( sal_True ); } void EditDoc::FindAttribs( ContentNode* pNode, sal_uInt16 nStartPos, sal_uInt16 nEndPos, SfxItemSet& rCurSet ) { DBG_ASSERT( pNode, "Where to search?" ); DBG_ASSERT( nStartPos <= nEndPos, "Invalid region!" ); sal_uInt16 nAttr = 0; EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); // No Selection... if ( nStartPos == nEndPos ) { while ( pAttr && ( pAttr->GetStart() <= nEndPos) ) { const SfxPoolItem* pItem = 0; // Attribute is about... if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) pItem = pAttr->GetItem(); // Attribute ending here is not empty else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) { if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) ) pItem = pAttr->GetItem(); } // Attribute ending here is empty else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) { pItem = pAttr->GetItem(); } // Attribute starts here else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) { if ( nStartPos == 0 ) // special case pItem = pAttr->GetItem(); } if ( pItem ) { sal_uInt16 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 // Selection { while ( pAttr && ( pAttr->GetStart() < nEndPos) ) { const SfxPoolItem* pItem = 0; // Attribut is about... if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) ) pItem = pAttr->GetItem(); // Attribute starts right in the middle ... else if ( pAttr->GetStart() >= nStartPos ) { // !!! pItem = pAttr->GetItem(); // PItem is simply not enough, since one for example in case // of Shadow, would never find an unequal item, since such a // item represents its presence by absence! // If (...) // It needs to be examined on exactly the same attribute at the // breaki point, which is quite expensive. // Since optimazation is done when inserting the attributes // this case does not appear so fast ... // So based on the need for speed: rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); } // Attribute ends in the middle of it ... else if ( pAttr->GetEnd() > nStartPos ) { rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); } if ( pItem ) { sal_uInt16 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 ); } } } CharAttribList::CharAttribList() { DBG_CTOR( EE_CharAttribList, 0 ); bHasEmptyAttribs = sal_False; } CharAttribList::~CharAttribList() { DBG_DTOR( EE_CharAttribList, 0 ); sal_uInt16 nAttr = 0; EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); while ( pAttr ) { delete pAttr; ++nAttr; pAttr = GetAttrib( aAttribs, nAttr ); } Clear(); } void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib ) { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! // optimize: binary search? ! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Maybe just simply iterate backwards: // The most common and critical case: Attributes are already sorted // (InsertBinTextObject!) binary search would not be optimal here. // => Would bring something! const sal_uInt16 nCount = Count(); const sal_uInt16 nStart = pAttrib->GetStart(); // may be better for Comp.Opt. if ( pAttrib->IsEmpty() ) bHasEmptyAttribs = sal_True; sal_Bool bInserted = sal_False; for ( sal_uInt16 x = 0; x < nCount; x++ ) { EditCharAttribPtr pCurAttrib = aAttribs[x]; if ( pCurAttrib->GetStart() > nStart ) { aAttribs.Insert( pAttrib, x ); bInserted = sal_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 ( sal_uInt16 n = 0; n < aAttribs.Count(); n++ ) { EditCharAttrib* pAttr = aAttribs.GetObject( n ); for ( sal_uInt16 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( sal_uInt16 nWhich, sal_uInt16 nPos ) { // Backwards, if one ends where the next starts. // => The starting one is the valid one ... sal_uInt16 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( sal_uInt16 nWhich, sal_uInt16 nFromPos ) const { DBG_ASSERT( nWhich, "FindNextAttrib: Which?" ); const sal_uInt16 nAttribs = aAttribs.Count(); for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) { EditCharAttrib* pAttr = aAttribs[ nAttr ]; if ( ( pAttr->GetStart() >= nFromPos ) && ( pAttr->Which() == nWhich ) ) return pAttr; } return 0; } sal_Bool CharAttribList::HasAttrib( sal_uInt16 nStartPos, sal_uInt16 nEndPos ) const { sal_Bool bAttr = sal_False; for ( sal_uInt16 nAttr = aAttribs.Count(); nAttr && !bAttr; ) { const EditCharAttrib* pAttr = aAttribs[--nAttr]; if ( ( pAttr->GetStart() < nEndPos ) && ( pAttr->GetEnd() > nStartPos ) ) return bAttr = sal_True; } return bAttr; } sal_Bool CharAttribList::HasBoundingAttrib( sal_uInt16 nBound ) { // Backwards, if one ends where the next starts. // => The starting one is the valid one ... sal_uInt16 nAttr = aAttribs.Count()-1; EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); while ( pAttr && ( pAttr->GetEnd() >= nBound ) ) { if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) ) return sal_True; pAttr = GetAttrib( aAttribs, --nAttr ); } return sal_False; } EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ) { if ( !bHasEmptyAttribs ) return 0; sal_uInt16 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( sal_uInt16 nPos ) const { sal_uInt16 nAttr = 0; EditCharAttrib* pNextAttrib = GetAttrib( aAttribs, nAttr ); // first to the desired position ... while ( pNextAttrib && ( pNextAttrib->GetStart() < nPos ) ) { nAttr++; pNextAttrib = GetAttrib( aAttribs, nAttr ); } // Now search for the Feature... while ( pNextAttrib && !pNextAttrib->IsFeature() ) { nAttr++; pNextAttrib = GetAttrib( aAttribs, nAttr ); } return pNextAttrib; } void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool ) { for ( sal_uInt16 nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) { EditCharAttrib* pAttr = aAttribs[nAttr]; if ( pAttr->IsEmpty() ) { rItemPool.Remove( *pAttr->GetItem() ); aAttribs.Remove( nAttr ); delete pAttr; nAttr--; } } bHasEmptyAttribs = sal_False; } #if OSL_DEBUG_LEVEL > 2 bool CharAttribList::DbgCheckAttribs() const { bool bOK = true; for ( sal_uInt16 nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) { const EditCharAttrib* pAttr = aAttribs[nAttr]; if ( pAttr->GetStart() > pAttr->GetEnd() ) { bOK = false; OSL_FAIL( "Attribute is distorted" ); } else if ( pAttr->IsFeature() && ( pAttr->GetLen() != 1 ) ) { bOK = false; OSL_FAIL( "Feature, Len != 1" ); } } return bOK; } #endif SvxFontTable::SvxFontTable() { } SvxFontTable::~SvxFontTable() { SvxFontItem* pItem = First(); while( pItem ) { delete pItem; pItem = Next(); } } sal_uLong SvxFontTable::GetId( const SvxFontItem& rFontItem ) { SvxFontItem* pItem = First(); while ( pItem ) { if ( *pItem == rFontItem ) return GetCurKey(); pItem = Next(); } DBG_WARNING( "Font not found: GetId()" ); return 0; } SvxColorList::SvxColorList() { } SvxColorList::~SvxColorList() { for ( size_t i = 0, n = aColorList.size(); i < n; ++i ) delete aColorList[ i ]; aColorList.clear(); } size_t SvxColorList::GetId( const SvxColorItem& rColorItem ) { for ( size_t i = 0, n = aColorList.size(); i < n; ++i ) if ( *aColorList[ i ] == rColorItem ) return i; DBG_WARNING( "Color not found: GetId()" ); return 0; } void SvxColorList::Insert( SvxColorItem* pItem, size_t nIndex ) { if ( nIndex >= aColorList.size() ) { aColorList.push_back( pItem ); } else { DummyColorList::iterator it = aColorList.begin(); ::std::advance( it, nIndex ); aColorList.insert( it, pItem ); } } SvxColorItem* SvxColorList::GetObject( size_t nIndex ) { return ( nIndex >= aColorList.size() ) ? NULL : aColorList[ nIndex ]; } EditEngineItemPool::EditEngineItemPool( sal_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 ); SfxPoolItem** ppDefItems = EE_DLL().GetGlobalData()->GetDefItems(); SetDefaults( ppDefItems ); } EditEngineItemPool::~EditEngineItemPool() { } SvStream& EditEngineItemPool::Store( SvStream& rStream ) const { // for a 3.1 export a hack has to be installed, as in there is a BUG in // SfxItemSet::Load, but not subsequently after 3.1. // The selected range must be kept after Store, because itemsets are not // stored until then... long nVersion = rStream.GetVersion(); sal_Bool b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) ) ? sal_True : sal_False; EditEngineItemPool* pThis = (EditEngineItemPool*)this; if ( b31Format ) pThis->SetStoringRange( 3997, 4022 ); else pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END ); return SfxItemPool::Store( rStream ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */