/************************************************************************* * * 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. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // GetDoc() #include // InvalidateSpelling #include #include // ViewShell #include // SwPosition #include // SwTxtNode #include #include #include #include #include #include #include #include // SwPageDesc #include #include #include #include #include #include #include #include #include #include // SwTxtFrm #include // SwSectFrm #include // DBG_LOOP #include // Iteratoren #include // SwFrmBreak #include #include // GetLineSpace benutzt pLastFont #include #include #include // OD 2004-01-15 #110582# #include // OD 2004-05-24 #i28701# #include // --> OD 2005-03-30 #???# #include // SwTxtFlyCnt #include // SwFmtFlyCnt #include // SwFmtCntnt // <-- // --> OD 2008-01-31 #newlistlevelattrs# #include // <-- #include #include #include #if OSL_DEBUG_LEVEL > 1 #include // DbgRect extern const sal_Char *GetPrepName( const enum PrepareHint ePrep ); #endif TYPEINIT1( SwTxtFrm, SwCntntFrm ); // Switches width and height of the text frame void SwTxtFrm::SwapWidthAndHeight() { if ( ! bIsSwapped ) { const long nPrtOfstX = Prt().Pos().X(); Prt().Pos().X() = Prt().Pos().Y(); Prt().Pos().Y() = Frm().Width() - ( nPrtOfstX + Prt().Width() ); } else { const long nPrtOfstY = Prt().Pos().Y(); Prt().Pos().Y() = Prt().Pos().X(); Prt().Pos().X() = Frm().Height() - ( nPrtOfstY + Prt().Height() ); } const long nFrmWidth = Frm().Width(); Frm().Width( Frm().Height() ); Frm().Height( nFrmWidth ); const long nPrtWidth = Prt().Width(); Prt().Width( Prt().Height() ); Prt().Height( nPrtWidth ); bIsSwapped = ! bIsSwapped; } // Calculates the coordinates of a rectangle when switching from // horizontal to vertical layout. void SwTxtFrm::SwitchHorizontalToVertical( SwRect& rRect ) const { // calc offset inside frame const long nOfstX = rRect.Left() - Frm().Left(); const long nOfstY = rRect.Top() + rRect.Height() - Frm().Top(); const long nWidth = rRect.Width(); const long nHeight = rRect.Height(); if ( bIsSwapped ) rRect.Left( Frm().Left() + Frm().Height() - nOfstY ); else // frame is rotated rRect.Left( Frm().Left() + Frm().Width() - nOfstY ); rRect.Top( Frm().Top() + nOfstX ); rRect.Width( nHeight ); rRect.Height( nWidth ); } // Calculates the coordinates of a point when switching from // horizontal to vertical layout. void SwTxtFrm::SwitchHorizontalToVertical( Point& rPoint ) const { // calc offset inside frame const long nOfstX = rPoint.X() - Frm().Left(); const long nOfstY = rPoint.Y() - Frm().Top(); if ( bIsSwapped ) rPoint.X() = Frm().Left() + Frm().Height() - nOfstY; else // calc rotated coords rPoint.X() = Frm().Left() + Frm().Width() - nOfstY; rPoint.Y() = Frm().Top() + nOfstX; } // Calculates the a limit value when switching from // horizontal to vertical layout. long SwTxtFrm::SwitchHorizontalToVertical( long nLimit ) const { Point aTmp( 0, nLimit ); SwitchHorizontalToVertical( aTmp ); return aTmp.X(); } // Calculates the coordinates of a rectangle when switching from // vertical to horizontal layout. void SwTxtFrm::SwitchVerticalToHorizontal( SwRect& rRect ) const { long nOfstX; // calc offset inside frame if ( bIsSwapped ) nOfstX = Frm().Left() + Frm().Height() - ( rRect.Left() + rRect.Width() ); else nOfstX = Frm().Left() + Frm().Width() - ( rRect.Left() + rRect.Width() ); const long nOfstY = rRect.Top() - Frm().Top(); const long nWidth = rRect.Height(); const long nHeight = rRect.Width(); // calc rotated coords rRect.Left( Frm().Left() + nOfstY ); rRect.Top( Frm().Top() + nOfstX ); rRect.Width( nWidth ); rRect.Height( nHeight ); } // Calculates the coordinates of a point when switching from // vertical to horizontal layout. void SwTxtFrm::SwitchVerticalToHorizontal( Point& rPoint ) const { long nOfstX; // calc offset inside frame if ( bIsSwapped ) nOfstX = Frm().Left() + Frm().Height() - rPoint.X(); else nOfstX = Frm().Left() + Frm().Width() - rPoint.X(); const long nOfstY = rPoint.Y() - Frm().Top(); // calc rotated coords rPoint.X() = Frm().Left() + nOfstY; rPoint.Y() = Frm().Top() + nOfstX; } // Calculates the a limit value when switching from // vertical to horizontal layout. long SwTxtFrm::SwitchVerticalToHorizontal( long nLimit ) const { Point aTmp( nLimit, 0 ); SwitchVerticalToHorizontal( aTmp ); return aTmp.Y(); } SwFrmSwapper::SwFrmSwapper( const SwTxtFrm* pTxtFrm, sal_Bool bSwapIfNotSwapped ) : pFrm( pTxtFrm ), bUndo( sal_False ) { if ( pFrm->IsVertical() && ( ( bSwapIfNotSwapped && ! pFrm->IsSwapped() ) || ( ! bSwapIfNotSwapped && pFrm->IsSwapped() ) ) ) { bUndo = sal_True; ((SwTxtFrm*)pFrm)->SwapWidthAndHeight(); } } SwFrmSwapper::~SwFrmSwapper() { if ( bUndo ) ((SwTxtFrm*)pFrm)->SwapWidthAndHeight(); } void SwTxtFrm::SwitchLTRtoRTL( SwRect& rRect ) const { SWAP_IF_NOT_SWAPPED( this ) long nWidth = rRect.Width(); rRect.Left( 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rRect.Right() - 1 ); rRect.Width( nWidth ); UNDO_SWAP( this ) } void SwTxtFrm::SwitchLTRtoRTL( Point& rPoint ) const { SWAP_IF_NOT_SWAPPED( this ) rPoint.X() = 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rPoint.X() - 1; UNDO_SWAP( this ) } SwLayoutModeModifier::SwLayoutModeModifier( const OutputDevice& rOutp ) : rOut( rOutp ), nOldLayoutMode( rOutp.GetLayoutMode() ) { } SwLayoutModeModifier::~SwLayoutModeModifier() { ((OutputDevice&)rOut).SetLayoutMode( nOldLayoutMode ); } void SwLayoutModeModifier::Modify( sal_Bool bChgToRTL ) { ((OutputDevice&)rOut).SetLayoutMode( bChgToRTL ? TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL : TEXT_LAYOUT_BIDI_STRONG ); } void SwLayoutModeModifier::SetAuto() { const sal_uLong nNewLayoutMode = nOldLayoutMode & ~TEXT_LAYOUT_BIDI_STRONG; ((OutputDevice&)rOut).SetLayoutMode( nNewLayoutMode ); } SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) : rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() ) { LanguageType eLang = eCurLang; const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals(); if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals ) eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals ) eLang = LANGUAGE_ENGLISH; else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals ) eLang = (LanguageType)::GetAppLanguage(); ((OutputDevice&)rOut).SetDigitLanguage( eLang ); } SwDigitModeModifier::~SwDigitModeModifier() { ((OutputDevice&)rOut).SetDigitLanguage( nOldLanguageType ); } /************************************************************************* * SwTxtFrm::Init() *************************************************************************/ void SwTxtFrm::Init() { ASSERT( !IsLocked(), "+SwTxtFrm::Init: this ist locked." ); if( !IsLocked() ) { ClearPara(); ResetBlinkPor(); //Die Flags direkt setzen um ResetPreps und damit ein unnuetzes GetPara //einzusparen. // Nicht bOrphan, bLocked oder bWait auf sal_False setzen ! // bOrphan = bFlag7 = bFlag8 = sal_False; } } /************************************************************************* |* SwTxtFrm::CTORen/DTOR |*************************************************************************/ void SwTxtFrm::InitCtor() { nCacheIdx = MSHRT_MAX; nOfst = 0; nAllLines = 0; nThisLines = 0; mnFlyAnchorOfst = 0; mnFlyAnchorOfstNoWrap = 0; mnFtnLine = 0; // OD 2004-03-17 #i11860# mnHeightOfLastLine = 0; // --> OD 2008-01-31 #newlistlevelattrs# mnAdditionalFirstLineOffset = 0; // <-- nType = FRMC_TXT; bLocked = bFormatted = bWidow = bUndersized = bJustWidow = bEmpty = bInFtnConnect = bFtn = bRepaint = bBlinkPor = bFieldFollow = bHasAnimation = bIsSwapped = sal_False; // OD 14.03.2003 #i11760# mbFollowFormatAllowed = sal_True; } /************************************************************************* * SwTxtFrm::SwTxtFrm() *************************************************************************/ SwTxtFrm::SwTxtFrm(SwTxtNode * const pNode) : SwCntntFrm(pNode) { InitCtor(); } /************************************************************************* * SwTxtFrm::~SwTxtFrm() *************************************************************************/ SwTxtFrm::~SwTxtFrm() { // Remove associated SwParaPortion from pTxtCache ClearPara(); } const XubString& SwTxtFrm::GetTxt() const { return GetTxtNode()->GetTxt(); } void SwTxtFrm::ResetPreps() { if ( GetCacheIdx() != MSHRT_MAX ) { SwParaPortion *pPara; if( 0 != (pPara = GetPara()) ) pPara->ResetPreps(); } } /************************************************************************* * SwTxtFrm::IsHiddenNow() *************************************************************************/ sal_Bool SwTxtFrm::IsHiddenNow() const { SwFrmSwapper aSwapper( this, sal_True ); if( !Frm().Width() && IsValid() && GetUpper()->IsValid() ) //bei Stackueberlauf (StackHack) invalid! { // ASSERT( false, "SwTxtFrm::IsHiddenNow: thin frame" ); return sal_True; } const bool bHiddenCharsHidePara = GetTxtNode()->HasHiddenCharAttribute( true ); const bool bHiddenParaField = GetTxtNode()->HasHiddenParaField(); const ViewShell* pVsh = GetShell(); if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) ) { if ( ( bHiddenParaField && ( !pVsh->GetViewOptions()->IsShowHiddenPara() && !pVsh->GetViewOptions()->IsFldName() ) ) || ( bHiddenCharsHidePara && !pVsh->GetViewOptions()->IsShowHiddenChar() ) ) { return sal_True; } } return sal_False; } /************************************************************************* * SwTxtFrm::HideHidden() *************************************************************************/ // Entfernt die Anhaengsel des Textfrms wenn dieser hidden ist void SwTxtFrm::HideHidden() { ASSERT( !GetFollow() && IsHiddenNow(), "HideHidden on visible frame of hidden frame has follow" ); const xub_StrLen nEnd = STRING_LEN; HideFootnotes( GetOfst(), nEnd ); // OD 2004-01-15 #110582# HideAndShowObjects(); //Die Formatinfos sind jetzt obsolete ClearPara(); } /************************************************************************* * SwTxtFrm::HideFootnotes() *************************************************************************/ void SwTxtFrm::HideFootnotes( xub_StrLen nStart, xub_StrLen nEnd ) { const SwpHints *pHints = GetTxtNode()->GetpSwpHints(); if( pHints ) { const sal_uInt16 nSize = pHints->Count(); SwPageFrm *pPage = 0; for ( sal_uInt16 i = 0; i < nSize; ++i ) { const SwTxtAttr *pHt = (*pHints)[i]; if ( pHt->Which() == RES_TXTATR_FTN ) { const xub_StrLen nIdx = *pHt->GetStart(); if ( nEnd < nIdx ) break; if( nStart <= nIdx ) { if( !pPage ) pPage = FindPageFrm(); pPage->RemoveFtn( this, (SwTxtFtn*)pHt ); } } } } } // --> OD 2005-03-30 #120729# - hotfix: WW8 documents contain at its end hidden, // as-character anchored graphics, which are used for a graphic bullet list. // As long as these graphic bullet list aren't imported, do not hide a // at-character anchored object, if // (a) the document is an imported WW8 document - // checked by checking certain compatibility options -, // (b) the paragraph is the last content in the document and // (c) the anchor character is an as-character anchored graphic. bool lcl_HideObj( const SwTxtFrm& _rFrm, const RndStdIds _eAnchorType, const xub_StrLen _nObjAnchorPos, SwAnchoredObject* _pAnchoredObj ) { bool bRet( true ); if (_eAnchorType == FLY_AT_CHAR) { const IDocumentSettingAccess* pIDSA = _rFrm.GetTxtNode()->getIDocumentSettingAccess(); if ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) && !pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING) && !pIDSA->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) && pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) && _rFrm.IsInDocBody() && !_rFrm.FindNextCnt() ) { const xub_Unicode cAnchorChar = _rFrm.GetTxtNode()->GetTxt().GetChar( _nObjAnchorPos ); if ( cAnchorChar == CH_TXTATR_BREAKWORD ) { const SwTxtAttr* const pHint( _rFrm.GetTxtNode()->GetTxtAttrForCharAt(_nObjAnchorPos, RES_TXTATR_FLYCNT) ); if ( pHint ) { const SwFrmFmt* pFrmFmt = static_cast(pHint)->GetFlyCnt().GetFrmFmt(); if ( pFrmFmt->Which() == RES_FLYFRMFMT ) { SwNodeIndex nCntntIndex = *(pFrmFmt->GetCntnt().GetCntntIdx()); nCntntIndex++; if ( nCntntIndex.GetNode().IsNoTxtNode() ) { bRet = false; // set needed data structure values for object positioning SWRECTFN( (&_rFrm) ); SwRect aLastCharRect( _rFrm.Frm() ); (aLastCharRect.*fnRect->fnSetWidth)( 1 ); _pAnchoredObj->maLastCharRect = aLastCharRect; _pAnchoredObj->mnLastTopOfLine = (aLastCharRect.*fnRect->fnGetTop)(); } } } } } } return bRet; } // <-- /************************************************************************* * SwTxtFrm::HideAndShowObjects() *************************************************************************/ /** method to hide/show objects OD 2004-01-15 #110582# method hides respectively shows objects, which are anchored at paragraph, at/as a character of the paragraph, corresponding to the paragraph and paragraph portion visibility. - is called from HideHidden() - should hide objects in hidden paragraphs and - from _Format() - should hide/show objects in partly visible paragraphs @author OD */ void SwTxtFrm::HideAndShowObjects() { if ( GetDrawObjs() ) { if ( IsHiddenNow() ) { // complete paragraph is hidden. Thus, hide all objects for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i ) { SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj(); SwContact* pContact = static_cast(pObj->GetUserCall()); // --> OD 2005-03-30 #120729# - hotfix: do not hide object // under certain conditions const RndStdIds eAnchorType( pContact->GetAnchorId() ); const xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex(); if ((eAnchorType != FLY_AT_CHAR) || lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] )) { pContact->MoveObjToInvisibleLayer( pObj ); } // <-- } } else { // paragraph is visible, but can contain hidden text portion. // first we check if objects are allowed to be hidden: const SwTxtNode& rNode = *GetTxtNode(); const ViewShell* pVsh = GetShell(); const bool bShouldBeHidden = !pVsh || !pVsh->GetWin() || !pVsh->GetViewOptions()->IsShowHiddenChar(); // Thus, show all objects, which are anchored at paragraph and // hide/show objects, which are anchored at/as character, according // to the visibility of the anchor character. for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i ) { SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj(); SwContact* pContact = static_cast(pObj->GetUserCall()); // --> OD 2005-03-30 #120729# - determine anchor type only once const RndStdIds eAnchorType( pContact->GetAnchorId() ); // <-- if (eAnchorType == FLY_AT_PARA) { pContact->MoveObjToVisibleLayer( pObj ); } else if ((eAnchorType == FLY_AT_CHAR) || (eAnchorType == FLY_AS_CHAR)) { xub_StrLen nHiddenStart; xub_StrLen nHiddenEnd; xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex(); SwScriptInfo::GetBoundsOfHiddenRange( rNode, nObjAnchorPos, nHiddenStart, nHiddenEnd, 0 ); // --> OD 2005-03-30 #120729# - hotfix: do not hide object // under certain conditions if ( nHiddenStart != STRING_LEN && bShouldBeHidden && lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) ) // <-- pContact->MoveObjToInvisibleLayer( pObj ); else pContact->MoveObjToVisibleLayer( pObj ); } else { ASSERT( false, " - object not anchored at/inside paragraph!?" ); } } } } if ( IsFollow() ) { FindMaster()->HideAndShowObjects(); } } /************************************************************************* * SwTxtFrm::FindBrk() * * Liefert die erste Trennmoeglichkeit in der aktuellen Zeile zurueck. * Die Methode wird in SwTxtFrm::Format() benutzt, um festzustellen, ob * die Vorgaengerzeile mitformatiert werden muss. * nFound ist <= nEndLine. *************************************************************************/ xub_StrLen SwTxtFrm::FindBrk( const XubString &rTxt, const xub_StrLen nStart, const xub_StrLen nEnd ) const { // --> OD 2009-12-28 #i104291# - applying patch to avoid overflow. unsigned long nFound = nStart; const xub_StrLen nEndLine = Min( nEnd, rTxt.Len() ); // Wir ueberlesen erst alle Blanks am Anfang der Zeile (vgl. Bug 2235). while( nFound <= nEndLine && ' ' == rTxt.GetChar( static_cast(nFound) ) ) { nFound++; } // Eine knifflige Sache mit den TxtAttr-Dummy-Zeichen (hier "$"): // "Dr.$Meyer" am Anfang der zweiten Zeile. Dahinter ein Blank eingegeben // und das Wort rutscht nicht in die erste Zeile, obwohl es ginge. // Aus diesem Grund nehmen wir das Dummy-Zeichen noch mit. while( nFound <= nEndLine && ' ' != rTxt.GetChar( static_cast(nFound) ) ) { nFound++; } return nFound <= STRING_LEN ? static_cast(nFound) : STRING_LEN; // <-- } /************************************************************************* * SwTxtFrm::IsIdxInside() *************************************************************************/ sal_Bool SwTxtFrm::IsIdxInside( const xub_StrLen nPos, const xub_StrLen nLen ) const { if( GetOfst() > nPos + nLen ) // d.h., der Bereich liegt komplett vor uns. return sal_False; if( !GetFollow() ) // der Bereich liegt nicht komplett vor uns, return sal_True; // nach uns kommt niemand mehr. const xub_StrLen nMax = GetFollow()->GetOfst(); // der Bereich liegt nicht komplett hinter uns bzw. // unser Text ist geloescht worden. if( nMax > nPos || nMax > GetTxt().Len() ) return sal_True; // changes made in the first line of a follow can modify the master const SwParaPortion* pPara = GetFollow()->GetPara(); return pPara && ( nPos <= nMax + pPara->GetLen() ); } /************************************************************************* * SwTxtFrm::InvalidateRange() *************************************************************************/ inline void SwTxtFrm::InvalidateRange(const SwCharRange &aRange, const long nD) { if ( IsIdxInside( aRange.Start(), aRange.Len() ) ) _InvalidateRange( aRange, nD ); } /************************************************************************* * SwTxtFrm::_InvalidateRange() *************************************************************************/ void SwTxtFrm::_InvalidateRange( const SwCharRange &aRange, const long nD) { if ( !HasPara() ) { InvalidateSize(); return; } SetWidow( sal_False ); SwParaPortion *pPara = GetPara(); sal_Bool bInv = sal_False; if( 0 != nD ) { //Auf nDelta werden die Differenzen zwischen alter und //neuer Zeilenlaenge aufaddiert, deshalb ist es negativ, //wenn Zeichen eingefuegt wurden, positiv, wenn Zeichen //geloescht wurden. *(pPara->GetDelta()) += nD; bInv = sal_True; } SwCharRange &rReformat = *(pPara->GetReformat()); if(aRange != rReformat) { if( STRING_LEN == rReformat.Len() ) rReformat = aRange; else rReformat += aRange; bInv = sal_True; } if(bInv) { // 90365: nD is passed to a follow two times // if( GetFollow() ) // ((SwTxtFrm*)GetFollow())->InvalidateRange( aRange, nD ); InvalidateSize(); } } /************************************************************************* * SwTxtFrm::CalcLineSpace() *************************************************************************/ void SwTxtFrm::CalcLineSpace() { ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcLineSpace with swapped frame!" ) if( IsLocked() || !HasPara() ) return; SwParaPortion *pPara; if( GetDrawObjs() || GetTxtNode()->GetSwAttrSet().GetLRSpace().IsAutoFirst() || ( pPara = GetPara() )->IsFixLineHeight() ) { Init(); return; } Size aNewSize( Prt().SSize() ); SwTxtFormatInfo aInf( this ); SwTxtFormatter aLine( this, &aInf ); if( aLine.GetDropLines() ) { Init(); return; } aLine.Top(); aLine.RecalcRealHeight(); aNewSize.Height() = (aLine.Y() - Frm().Top()) + aLine.GetLineHeight(); SwTwips nDelta = aNewSize.Height() - Prt().Height(); // 4291: Unterlauf bei Flys if( aInf.GetTxtFly()->IsOn() ) { SwRect aTmpFrm( Frm() ); if( nDelta < 0 ) aTmpFrm.Height( Prt().Height() ); else aTmpFrm.Height( aNewSize.Height() ); if( aInf.GetTxtFly()->Relax( aTmpFrm ) ) { Init(); return; } } if( nDelta ) { SwTxtFrmBreak aBreak( this ); if( GetFollow() || aBreak.IsBreakNow( aLine ) ) { // Wenn es einen Follow() gibt, oder wenn wir an dieser // Stelle aufbrechen muessen, so wird neu formatiert. Init(); } else { // Alles nimmt seinen gewohnten Gang ... pPara->SetPrepAdjust(); pPara->SetPrep(); } } } // // SET_WRONG( nPos, nCnt, bMove ) // #define SET_WRONG( nPos, nCnt, bMove ) \ { \ lcl_SetWrong( *this, nPos, nCnt, bMove ); \ } void lcl_SetWrong( SwTxtFrm& rFrm, xub_StrLen nPos, long nCnt, bool bMove ) { if ( !rFrm.IsFollow() ) { SwTxtNode* pTxtNode = rFrm.GetTxtNode(); IGrammarContact* pGrammarContact = getGrammarContact( *pTxtNode ); SwGrammarMarkUp* pWrongGrammar = pGrammarContact ? pGrammarContact->getGrammarCheck( *pTxtNode, false ) : pTxtNode->GetGrammarCheck(); bool bGrammarProxy = pWrongGrammar != pTxtNode->GetGrammarCheck(); if( bMove ) { if( pTxtNode->GetWrong() ) pTxtNode->GetWrong()->Move( nPos, nCnt ); if( pWrongGrammar ) pWrongGrammar->MoveGrammar( nPos, nCnt ); if( bGrammarProxy && pTxtNode->GetGrammarCheck() ) pTxtNode->GetGrammarCheck()->MoveGrammar( nPos, nCnt ); if( pTxtNode->GetSmartTags() ) pTxtNode->GetSmartTags()->Move( nPos, nCnt ); } else { xub_StrLen nLen = (xub_StrLen)nCnt; if( pTxtNode->GetWrong() ) pTxtNode->GetWrong()->Invalidate( nPos, nLen ); if( pWrongGrammar ) pWrongGrammar->Invalidate( nPos, nLen ); if( pTxtNode->GetSmartTags() ) pTxtNode->GetSmartTags()->Invalidate( nPos, nLen ); } if ( !pTxtNode->GetWrong() && !pTxtNode->IsWrongDirty() ) { pTxtNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) ); pTxtNode->GetWrong()->SetInvalid( nPos, nPos + (sal_uInt16)( nCnt > 0 ? nCnt : 1 ) ); } if ( !pTxtNode->GetSmartTags() && !pTxtNode->IsSmartTagDirty() ) { // SMARTTAGS pTxtNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) ); pTxtNode->GetSmartTags()->SetInvalid( nPos, nPos + (sal_uInt16)( nCnt > 0 ? nCnt : 1 ) ); } pTxtNode->SetWrongDirty( true ); pTxtNode->SetGrammarCheckDirty( true ); pTxtNode->SetWordCountDirty( true ); pTxtNode->SetAutoCompleteWordDirty( true ); // SMARTTAGS pTxtNode->SetSmartTagDirty( true ); } SwRootFrm *pRootFrm = rFrm.FindRootFrm(); if (pRootFrm) { pRootFrm->SetNeedGrammarCheck( sal_True ); } SwPageFrm *pPage = rFrm.FindPageFrm(); if( pPage ) { pPage->InvalidateSpelling(); pPage->InvalidateAutoCompleteWords(); pPage->InvalidateWordCount(); pPage->InvalidateSmartTags(); } } // // SET_SCRIPT_INVAL( nPos ) // #define SET_SCRIPT_INVAL( nPos )\ lcl_SetScriptInval( *this, nPos ); void lcl_SetScriptInval( SwTxtFrm& rFrm, xub_StrLen nPos ) { if( rFrm.GetPara() ) rFrm.GetPara()->GetScriptInfo().SetInvalidity( nPos ); } void lcl_ModifyOfst( SwTxtFrm* pFrm, xub_StrLen nPos, xub_StrLen nLen ) { while( pFrm && pFrm->GetOfst() <= nPos ) pFrm = pFrm->GetFollow(); while( pFrm ) { pFrm->ManipOfst( pFrm->GetOfst() + nLen ); pFrm = pFrm->GetFollow(); } } /************************************************************************* * SwTxtFrm::Modify() *************************************************************************/ void SwTxtFrm::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew ) { const MSHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; //Wuensche die FrmAttribute betreffen werden von der Basisklasse //verarbeitet. if( IsInRange( aFrmFmtSetRange, nWhich ) || RES_FMT_CHG == nWhich ) { SwCntntFrm::Modify( pOld, pNew ); if( nWhich == RES_FMT_CHG && GetShell() ) { // Collection hat sich geaendert Prepare( PREP_CLEAR ); _InvalidatePrt(); SET_WRONG( 0, STRING_LEN, false ); SetDerivedR2L( sal_False ); CheckDirChange(); // OD 09.12.2002 #105576# - Force complete paint due to existing // indents. SetCompletePaint(); InvalidateLineNum(); } return; } // Im gelockten Zustand werden keine Bestellungen angenommen. if( IsLocked() ) return; // Dies spart Stack, man muss nur aufpassen, // dass sie Variablen gesetzt werden. xub_StrLen nPos, nLen; sal_Bool bSetFldsDirty = sal_False; sal_Bool bRecalcFtnFlag = sal_False; switch( nWhich ) { case RES_LINENUMBER: { InvalidateLineNum(); } break; case RES_INS_TXT: { nPos = ((SwInsTxt*)pNew)->nPos; nLen = ((SwInsTxt*)pNew)->nLen; if( IsIdxInside( nPos, nLen ) ) { if( !nLen ) { // 6969: Aktualisierung der NumPortions auch bei leeren Zeilen! if( nPos ) InvalidateSize(); else Prepare( PREP_CLEAR ); } else _InvalidateRange( SwCharRange( nPos, nLen ), nLen ); } SET_WRONG( nPos, nLen, true ) SET_SCRIPT_INVAL( nPos ) bSetFldsDirty = sal_True; if( HasFollow() ) lcl_ModifyOfst( this, nPos, nLen ); } break; case RES_DEL_CHR: { nPos = ((SwDelChr*)pNew)->nPos; InvalidateRange( SwCharRange( nPos, 1 ), -1 ); SET_WRONG( nPos, -1, true ) SET_SCRIPT_INVAL( nPos ) bSetFldsDirty = bRecalcFtnFlag = sal_True; if( HasFollow() ) lcl_ModifyOfst( this, nPos, STRING_LEN ); } break; case RES_DEL_TXT: { nPos = ((SwDelTxt*)pNew)->nStart; nLen = ((SwDelTxt*)pNew)->nLen; long m = nLen; m *= -1; if( IsIdxInside( nPos, nLen ) ) { if( !nLen ) InvalidateSize(); else InvalidateRange( SwCharRange( nPos, 1 ), m ); } SET_WRONG( nPos, m, true ) SET_SCRIPT_INVAL( nPos ) bSetFldsDirty = bRecalcFtnFlag = sal_True; if( HasFollow() ) lcl_ModifyOfst( this, nPos, nLen ); } break; case RES_UPDATE_ATTR: { nPos = ((SwUpdateAttr*)pNew)->nStart; nLen = ((SwUpdateAttr*)pNew)->nEnd - nPos; if( IsIdxInside( nPos, nLen ) ) { // Es muss in jedem Fall neu formatiert werden, // auch wenn der invalidierte Bereich null ist. // Beispiel: leere Zeile, 14Pt einstellen ! // if( !nLen ) nLen = 1; // 6680: FtnNummern muessen formatiert werden. if( !nLen ) nLen = 1; _InvalidateRange( SwCharRange( nPos, nLen) ); MSHORT nTmp = ((SwUpdateAttr*)pNew)->nWhichAttr; if( ! nTmp || RES_TXTATR_CHARFMT == nTmp || RES_TXTATR_AUTOFMT == nTmp || RES_FMT_CHG == nTmp || RES_ATTRSET_CHG == nTmp ) { SET_WRONG( nPos, nPos + nLen, false ) SET_SCRIPT_INVAL( nPos ) } } // --> OD 2010-02-16 #i104008# if ( GetShell() ) { GetShell()->InvalidateAccessibleParaAttrs( *this ); } // <-- } break; case RES_OBJECTDYING: break; case RES_PARATR_LINESPACING: { CalcLineSpace(); InvalidateSize(); _InvalidatePrt(); if( IsInSct() && !GetPrev() ) { SwSectionFrm *pSect = FindSctFrm(); if( pSect->ContainsAny() == this ) pSect->InvalidatePrt(); } // OD 09.01.2004 #i11859# - correction: // (1) Also invalidate next frame on next page/column. // (2) Skip empty sections and hidden paragraphs // Thus, use method InvalidateNextPrtArea(); SetCompletePaint(); } break; case RES_TXTATR_FIELD: { nPos = *((SwFmtFld*)pNew)->GetTxtFld()->GetStart(); if( IsIdxInside( nPos, 1 ) ) { if( pNew == pOld ) { // Nur repainten // opt: invalidate aufs Window ? InvalidatePage(); SetCompletePaint(); } else _InvalidateRange( SwCharRange( nPos, 1 ) ); } bSetFldsDirty = sal_True; // ST2 if ( SwSmartTagMgr::Get().IsSmartTagsEnabled() ) SET_WRONG( nPos, nPos + 1, false ) } break; case RES_TXTATR_FTN : { nPos = *((SwFmtFtn*)pNew)->GetTxtFtn()->GetStart(); if( IsInFtn() || IsIdxInside( nPos, 1 ) ) Prepare( PREP_FTN, ((SwFmtFtn*)pNew)->GetTxtFtn() ); break; } case RES_ATTRSET_CHG: { InvalidateLineNum(); SwAttrSet& rNewSet = *((SwAttrSetChg*)pNew)->GetChgSet(); const SfxPoolItem* pItem; int nClear = 0; MSHORT nCount = rNewSet.Count(); if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FTN, sal_False, &pItem )) { nPos = *((SwFmtFtn*)pItem)->GetTxtFtn()->GetStart(); if( IsIdxInside( nPos, 1 ) ) Prepare( PREP_FTN, pNew ); nClear = 0x01; --nCount; } if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FIELD, sal_False, &pItem )) { nPos = *((SwFmtFld*)pItem)->GetTxtFld()->GetStart(); if( IsIdxInside( nPos, 1 ) ) { const SfxPoolItem& rOldItem = ((SwAttrSetChg*)pOld)-> GetChgSet()->Get( RES_TXTATR_FIELD ); if( pItem == &rOldItem ) { // Nur repainten // opt: invalidate aufs Window ? InvalidatePage(); SetCompletePaint(); } else _InvalidateRange( SwCharRange( nPos, 1 ) ); } nClear |= 0x02; --nCount; } sal_Bool bLineSpace = SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_LINESPACING, sal_False ), bRegister = SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_REGISTER, sal_False ); if ( bLineSpace || bRegister ) { Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM ); CalcLineSpace(); InvalidateSize(); _InvalidatePrt(); // OD 09.01.2004 #i11859# - correction: // (1) Also invalidate next frame on next page/column. // (2) Skip empty sections and hidden paragraphs // Thus, use method InvalidateNextPrtArea(); SetCompletePaint(); nClear |= 0x04; if ( bLineSpace ) { --nCount; if( IsInSct() && !GetPrev() ) { SwSectionFrm *pSect = FindSctFrm(); if( pSect->ContainsAny() == this ) pSect->InvalidatePrt(); } } if ( bRegister ) --nCount; } if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_SPLIT, sal_False )) { if ( GetPrev() ) CheckKeep(); Prepare( PREP_CLEAR ); InvalidateSize(); nClear |= 0x08; --nCount; } if( SFX_ITEM_SET == rNewSet.GetItemState( RES_BACKGROUND, sal_False) && !IsFollow() && GetDrawObjs() ) { SwSortedObjs *pObjs = GetDrawObjs(); for ( int i = 0; GetDrawObjs() && i < int(pObjs->Count()); ++i ) { SwAnchoredObject* pAnchoredObj = (*pObjs)[MSHORT(i)]; if ( pAnchoredObj->ISA(SwFlyFrm) ) { SwFlyFrm *pFly = static_cast(pAnchoredObj); if( !pFly->IsFlyInCntFrm() ) { const SvxBrushItem &rBack = pFly->GetAttrSet()->GetBackground(); // OD 20.08.2002 #99657# #GetTransChg# // following condition determines, if the fly frame // "inherites" the background color of text frame. // This is the case, if fly frame background // color is "no fill"/"auto fill" and if the fly frame // has no background graphic. // Thus, check complete fly frame background // color and *not* only its transparency value if ( (rBack.GetColor() == COL_TRANSPARENT) && //if( rBack.GetColor().GetTransparency() && rBack.GetGraphicPos() == GPOS_NONE ) { pFly->SetCompletePaint(); pFly->InvalidatePage(); } } } } } if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_CHARFMT, sal_False ) ) { SET_WRONG( 0, STRING_LEN, false ) SET_SCRIPT_INVAL( 0 ) } else if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_CHRATR_LANGUAGE, sal_False ) || SFX_ITEM_SET == rNewSet.GetItemState( RES_CHRATR_CJK_LANGUAGE, sal_False ) || SFX_ITEM_SET == rNewSet.GetItemState( RES_CHRATR_CTL_LANGUAGE, sal_False ) ) SET_WRONG( 0, STRING_LEN, false ) else if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_CHRATR_FONT, sal_False ) || SFX_ITEM_SET == rNewSet.GetItemState( RES_CHRATR_CJK_FONT, sal_False ) || SFX_ITEM_SET == rNewSet.GetItemState( RES_CHRATR_CTL_FONT, sal_False ) ) SET_SCRIPT_INVAL( 0 ) else if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_FRAMEDIR, sal_False ) ) { SetDerivedR2L( sal_False ); CheckDirChange(); // OD 09.12.2002 #105576# - Force complete paint due to existing // indents. SetCompletePaint(); } if( nCount ) { if( GetShell() ) { Prepare( PREP_CLEAR ); _InvalidatePrt(); } if( nClear ) { SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); if( 0x01 & nClear ) { aOldSet.ClearItem( RES_TXTATR_FTN ); aNewSet.ClearItem( RES_TXTATR_FTN ); } if( 0x02 & nClear ) { aOldSet.ClearItem( RES_TXTATR_FIELD ); aNewSet.ClearItem( RES_TXTATR_FIELD ); } if ( 0x04 & nClear ) { if ( bLineSpace ) { aOldSet.ClearItem( RES_PARATR_LINESPACING ); aNewSet.ClearItem( RES_PARATR_LINESPACING ); } if ( bRegister ) { aOldSet.ClearItem( RES_PARATR_REGISTER ); aNewSet.ClearItem( RES_PARATR_REGISTER ); } } if ( 0x08 & nClear ) { aOldSet.ClearItem( RES_PARATR_SPLIT ); aNewSet.ClearItem( RES_PARATR_SPLIT ); } SwCntntFrm::Modify( &aOldSet, &aNewSet ); } else SwCntntFrm::Modify( pOld, pNew ); } // --> OD 2009-01-06 #i88069# if ( GetShell() ) { GetShell()->InvalidateAccessibleParaAttrs( *this ); } // <-- } break; /* Seit dem neuen Blocksatz muessen wir immer neu formatieren: case RES_PARATR_ADJUST: { if( GetShell() ) { Prepare( PREP_CLEAR ); } break; } */ // 6870: SwDocPosUpdate auswerten. case RES_DOCPOS_UPDATE: { if( pOld && pNew ) { const SwDocPosUpdate *pDocPos = (const SwDocPosUpdate*)pOld; if( pDocPos->nDocPos <= aFrm.Top() ) { const SwFmtFld *pFld = (const SwFmtFld *)pNew; InvalidateRange( SwCharRange( *pFld->GetTxtFld()->GetStart(), 1 ) ); } } break; } case RES_PARATR_SPLIT: if ( GetPrev() ) CheckKeep(); Prepare( PREP_CLEAR ); bSetFldsDirty = sal_True; break; case RES_FRAMEDIR : SetDerivedR2L( sal_False ); CheckDirChange(); break; default: { Prepare( PREP_CLEAR ); _InvalidatePrt(); if ( !nWhich ) { //Wird z.B. bei HiddenPara mit 0 gerufen. SwFrm *pNxt; if ( 0 != (pNxt = FindNext()) ) pNxt->InvalidatePrt(); } } } // switch if( bSetFldsDirty ) GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( sal_True, GetNode(), 1 ); if ( bRecalcFtnFlag ) CalcFtnFlag(); } sal_Bool SwTxtFrm::GetInfo( SfxPoolItem &rHnt ) const { if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && ! IsFollow() ) { SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt; const SwPageFrm *pPage = FindPageFrm(); if ( pPage ) { if ( pPage == rInfo.GetOrigPage() && !GetPrev() ) { //Das sollte er sein (kann allenfalls temporaer anders sein, // sollte uns das beunruhigen?) rInfo.SetInfo( pPage, this ); return sal_False; } if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() && (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum())) { //Das koennte er sein. rInfo.SetInfo( pPage, this ); } } } return sal_True; } /************************************************************************* * SwTxtFrm::PrepWidows() *************************************************************************/ void SwTxtFrm::PrepWidows( const MSHORT nNeed, sal_Bool bNotify ) { ASSERT(GetFollow() && nNeed, "+SwTxtFrm::Prepare: lost all friends"); SwParaPortion *pPara = GetPara(); if ( !pPara ) return; pPara->SetPrepWidows( sal_True ); // These two lines of code have been deleted for #102340#. // Obviously the widow control does not work if we have a // pMaster->pFollow->pFollow situation: // returnen oder nicht ist hier die Frage. // Ohne IsLocked() ist 5156 gefaehrlich, // ohne IsFollow() werden die Orphans unterdrueckt: 6968. // Abfrage auf IsLocked erst hier, weil das Flag gesetzt werden soll. // if( IsLocked() && IsFollow() ) // return; MSHORT nHave = nNeed; // Wir geben ein paar Zeilen ab und schrumpfen im CalcPreps() SWAP_IF_NOT_SWAPPED( this ) SwTxtSizeInfo aInf( this ); SwTxtMargin aLine( this, &aInf ); aLine.Bottom(); xub_StrLen nTmpLen = aLine.GetCurr()->GetLen(); while( nHave && aLine.PrevLine() ) { if( nTmpLen ) --nHave; nTmpLen = aLine.GetCurr()->GetLen(); } // In dieser Ecke tummelten sich einige Bugs: 7513, 7606. // Wenn feststeht, dass Zeilen abgegeben werden koennen, // muss der Master darueber hinaus die Widow-Regel ueberpruefen. if( !nHave ) { sal_Bool bSplit; if( !IsFollow() ) //Nur ein Master entscheidet ueber Orphans { const WidowsAndOrphans aWidOrp( this ); bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() && aLine.GetLineNr() >= aLine.GetDropLines() ); } else bSplit = sal_True; if( bSplit ) { GetFollow()->SetOfst( aLine.GetEnd() ); aLine.TruncLines( sal_True ); if( pPara->IsFollowField() ) GetFollow()->SetFieldFollow( sal_True ); } } if ( bNotify ) { _InvalidateSize(); InvalidatePage(); } UNDO_SWAP( this ) } /************************************************************************* * SwTxtFrm::Prepare *************************************************************************/ sal_Bool lcl_ErgoVadis( SwTxtFrm* pFrm, xub_StrLen &rPos, const PrepareHint ePrep ) { const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo(); if( ePrep == PREP_ERGOSUM ) { if( !rFtnInfo.aErgoSum.Len() ) return sal_False;; rPos = pFrm->GetOfst(); } else { if( !rFtnInfo.aQuoVadis.Len() ) return sal_False; if( pFrm->HasFollow() ) rPos = pFrm->GetFollow()->GetOfst(); else rPos = pFrm->GetTxt().Len(); if( rPos ) --rPos; // unser letztes Zeichen } return sal_True; } void SwTxtFrm::Prepare( const PrepareHint ePrep, const void* pVoid, sal_Bool bNotify ) { SwFrmSwapper aSwapper( this, sal_False ); #if OSL_DEBUG_LEVEL > 1 const SwTwips nDbgY = Frm().Top(); (void)nDbgY; #endif if ( IsEmpty() ) { switch ( ePrep ) { case PREP_BOSS_CHGD: SetInvalidVert( sal_True ); // Test case PREP_WIDOWS_ORPHANS: case PREP_WIDOWS: case PREP_FTN_GONE : return; case PREP_POS_CHGD : { // Auch in (spaltigen) Bereichen ist ein InvalidateSize notwendig, // damit formatiert wird und ggf. das bUndersized gesetzt wird. if( IsInFly() || IsInSct() ) { SwTwips nTmpBottom = GetUpper()->Frm().Top() + GetUpper()->Prt().Bottom(); if( nTmpBottom < Frm().Bottom() ) break; } // Gibt es ueberhaupt Flys auf der Seite ? SwTxtFly aTxtFly( this ); if( aTxtFly.IsOn() ) { // Ueberlappt irgendein Fly ? aTxtFly.Relax(); if ( aTxtFly.IsOn() || IsUndersized() ) break; } if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue()) break; GETGRID( FindPageFrm() ) if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() ) break; // --> OD 2004-07-16 #i28701# - consider anchored objects if ( GetDrawObjs() ) break; // <-- return; } default: break; } } if( !HasPara() && PREP_MUST_FIT != ePrep ) { SetInvalidVert( sal_True ); // Test ASSERT( !IsLocked(), "SwTxtFrm::Prepare: three of a perfect pair" ); if ( bNotify ) InvalidateSize(); else _InvalidateSize(); return; } //Objekt mit Locking aus dem Cache holen. SwTxtLineAccess aAccess( this ); SwParaPortion *pPara = aAccess.GetPara(); switch( ePrep ) { case PREP_MOVEFTN : Frm().Height(0); Prt().Height(0); _InvalidatePrt(); _InvalidateSize(); // KEIN break case PREP_ADJUST_FRM : pPara->SetPrepAdjust( sal_True ); if( IsFtnNumFrm() != pPara->IsFtnNum() || IsUndersized() ) { InvalidateRange( SwCharRange( 0, 1 ), 1); if( GetOfst() && !IsFollow() ) _SetOfst( 0 ); } break; case PREP_MUST_FIT : pPara->SetPrepMustFit( sal_True ); /* no break here */ case PREP_WIDOWS_ORPHANS : pPara->SetPrepAdjust( sal_True ); break; case PREP_WIDOWS : // MustFit ist staerker als alles anderes if( pPara->IsPrepMustFit() ) return; // Siehe Kommentar in WidowsAndOrphans::FindOrphans und CalcPreps() PrepWidows( *(const MSHORT *)pVoid, bNotify ); break; case PREP_FTN : { SwTxtFtn *pFtn = (SwTxtFtn *)pVoid; if( IsInFtn() ) { // Bin ich der erste TxtFrm einer Fussnote ? if( !GetPrev() ) // Wir sind also ein TxtFrm der Fussnote, die // die Fussnotenzahl zur Anzeige bringen muss. // Oder den ErgoSum-Text... InvalidateRange( SwCharRange( 0, 1 ), 1); if( !GetNext() ) { // Wir sind der letzte Ftn, jetzt muessten die // QuoVadis-Texte geupdated werden. const SwFtnInfo &rFtnInfo = GetNode()->GetDoc()->GetFtnInfo(); if( !pPara->UpdateQuoVadis( rFtnInfo.aQuoVadis ) ) { xub_StrLen nPos = pPara->GetParLen(); if( nPos ) --nPos; InvalidateRange( SwCharRange( nPos, 1 ), 1); } } } else { // Wir sind also der TxtFrm _mit_ der Fussnote const xub_StrLen nPos = *pFtn->GetStart(); InvalidateRange( SwCharRange( nPos, 1 ), 1); } break; } case PREP_BOSS_CHGD : { // Test { SetInvalidVert( sal_False ); sal_Bool bOld = IsVertical(); SetInvalidVert( sal_True ); if( bOld != IsVertical() ) InvalidateRange( SwCharRange( GetOfst(), STRING_LEN ) ); } if( HasFollow() ) { xub_StrLen nNxtOfst = GetFollow()->GetOfst(); if( nNxtOfst ) --nNxtOfst; InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1); } if( IsInFtn() ) { xub_StrLen nPos; if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) ) InvalidateRange( SwCharRange( nPos, 1 ), 0 ); if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) ) InvalidateRange( SwCharRange( nPos, 1 ), 0 ); } // 4739: Wenn wir ein Seitennummernfeld besitzen, muessen wir // die Stellen invalidieren. SwpHints *pHints = GetTxtNode()->GetpSwpHints(); if( pHints ) { const sal_uInt16 nSize = pHints->Count(); const xub_StrLen nEnd = GetFollow() ? GetFollow()->GetOfst() : STRING_LEN; for ( sal_uInt16 i = 0; i < nSize; ++i ) { const SwTxtAttr *pHt = (*pHints)[i]; const xub_StrLen nStart = *pHt->GetStart(); if( nStart >= GetOfst() ) { if( nStart >= nEnd ) i = nSize; // fuehrt das Ende herbei else { // 4029: wenn wir zurueckfliessen und eine Ftn besitzen, so // fliesst die Ftn in jedem Fall auch mit. Damit sie nicht im // Weg steht, schicken wir uns ein ADJUST_FRM. // pVoid != 0 bedeutet MoveBwd() const MSHORT nWhich = pHt->Which(); if( RES_TXTATR_FIELD == nWhich || (HasFtn() && pVoid && RES_TXTATR_FTN == nWhich)) InvalidateRange( SwCharRange( nStart, 1 ), 1 ); } } } } // A new boss, a new chance for growing if( IsUndersized() ) { _InvalidateSize(); InvalidateRange( SwCharRange( GetOfst(), 1 ), 1); } break; } case PREP_POS_CHGD : { if ( GetValidPrtAreaFlag() ) { GETGRID( FindPageFrm() ) if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() ) InvalidatePrt(); } // Falls wir mit niemandem ueberlappen: // Ueberlappte irgendein Fly _vor_ der Positionsaenderung ? sal_Bool bFormat = pPara->HasFly(); if( !bFormat ) { if( IsInFly() ) { SwTwips nTmpBottom = GetUpper()->Frm().Top() + GetUpper()->Prt().Bottom(); if( nTmpBottom < Frm().Bottom() ) bFormat = sal_True; } if( !bFormat ) { if ( GetDrawObjs() ) { const sal_uInt32 nCnt = GetDrawObjs()->Count(); for ( MSHORT i = 0; i < nCnt; ++i ) { SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i]; // --> OD 2004-07-16 #i28701# - consider all // to-character anchored objects if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_CHAR ) { bFormat = sal_True; break; } } } if( !bFormat ) { // Gibt es ueberhaupt Flys auf der Seite ? SwTxtFly aTxtFly( this ); if( aTxtFly.IsOn() ) { // Ueberlappt irgendein Fly ? aTxtFly.Relax(); bFormat = aTxtFly.IsOn() || IsUndersized(); } } } } if( bFormat ) { if( !IsLocked() ) { if( pPara->GetRepaint()->HasArea() ) SetCompletePaint(); Init(); pPara = 0; _InvalidateSize(); } } else { if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() ) Prepare( PREP_REGISTER, 0, bNotify ); // Durch Positionsverschiebungen mit Ftns muessen die // Frames neu adjustiert werden. else if( HasFtn() ) { Prepare( PREP_ADJUST_FRM, 0, bNotify ); _InvalidateSize(); } else return; // damit kein SetPrep() erfolgt. } break; } case PREP_REGISTER: if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() ) { pPara->SetPrepAdjust( sal_True ); CalcLineSpace(); InvalidateSize(); _InvalidatePrt(); SwFrm* pNxt; if ( 0 != ( pNxt = GetIndNext() ) ) { pNxt->_InvalidatePrt(); if ( pNxt->IsLayoutFrm() ) pNxt->InvalidatePage(); } SetCompletePaint(); } break; case PREP_FTN_GONE : { // Wenn ein Follow uns ruft, weil eine Fussnote geloescht wird, muss unsere // letzte Zeile formatiert werden, damit ggf. die erste Zeile des Follows // hochrutschen kann, die extra auf die naechste Seite gerutscht war, um mit // der Fussnote zusammen zu sein, insbesondere bei spaltigen Bereichen. ASSERT( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" ); xub_StrLen nPos = GetFollow()->GetOfst(); if( IsFollow() && GetOfst() == nPos ) // falls wir gar keine Textmasse besitzen, FindMaster()->Prepare( PREP_FTN_GONE ); // rufen wir das Prepare unseres Masters if( nPos ) --nPos; // das Zeichen vor unserem Follow InvalidateRange( SwCharRange( nPos, 1 ), 0 ); return; } case PREP_ERGOSUM: case PREP_QUOVADIS: { xub_StrLen nPos; if( lcl_ErgoVadis( this, nPos, ePrep ) ) InvalidateRange( SwCharRange( nPos, 1 ), 0 ); } break; case PREP_FLY_ATTR_CHG: { if( pVoid ) { xub_StrLen nWhere = CalcFlyPos( (SwFrmFmt*)pVoid ); ASSERT( STRING_LEN != nWhere, "Prepare: Why me?" ); InvalidateRange( SwCharRange( nWhere, 1 ) ); return; } // else ... Laufe in den Default-Switch } case PREP_CLEAR: default: { if( IsLocked() ) { if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep ) { xub_StrLen nLen = ( GetFollow() ? GetFollow()->GetOfst() : STRING_LEN ) - GetOfst(); InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 ); } } else { if( pPara->GetRepaint()->HasArea() ) SetCompletePaint(); Init(); pPara = 0; if( GetOfst() && !IsFollow() ) _SetOfst( 0 ); if ( bNotify ) InvalidateSize(); else _InvalidateSize(); } return; // damit kein SetPrep() erfolgt. } } if( pPara ) pPara->SetPrep( sal_True ); } /* -----------------11.02.99 17:56------------------- * Kleine Hilfsklasse mit folgender Funktion: * Sie soll eine Probeformatierung vorbereiten. * Der Frame wird in Groesse und Position angepasst, sein SwParaPortion zur Seite * gestellt und eine neue erzeugt, dazu wird formatiert mit gesetztem bTestFormat. * Im Dtor wird der TxtFrm wieder in seinen alten Zustand zurueckversetzt. * * --------------------------------------------------*/ class SwTestFormat { SwTxtFrm *pFrm; SwParaPortion *pOldPara; SwRect aOldFrm, aOldPrt; public: SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPrv, SwTwips nMaxHeight ); ~SwTestFormat(); }; SwTestFormat::SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPre, SwTwips nMaxHeight ) : pFrm( pTxtFrm ) { aOldFrm = pFrm->Frm(); aOldPrt = pFrm->Prt(); SWRECTFN( pFrm ) SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)(); pFrm->Frm() = pFrm->GetUpper()->Prt(); pFrm->Frm() += pFrm->GetUpper()->Frm().Pos(); (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight ); if( pFrm->GetPrev() ) (pFrm->Frm().*fnRect->fnSetPosY)( (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() - ( bVert ? nMaxHeight + 1 : 0 ) ); SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm ); const SwBorderAttrs &rAttrs = *aAccess.Get(); (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) ); if( pPre ) { SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre ); (pFrm->Prt().*fnRect->fnSetPosY)( nUpper ); } (pFrm->Prt().*fnRect->fnSetHeight)( Max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() - (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) ); (pFrm->Prt().*fnRect->fnSetWidth)( (pFrm->Frm().*fnRect->fnGetWidth)() - // OD 23.01.2003 #106895# - add 1st param to ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) ); pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL; pFrm->SetPara( new SwParaPortion(), sal_False ); ASSERT( ! pFrm->IsSwapped(), "A frame is swapped before _Format" ); if ( pFrm->IsVertical() ) pFrm->SwapWidthAndHeight(); SwTxtFormatInfo aInf( pFrm, sal_False, sal_True, sal_True ); SwTxtFormatter aLine( pFrm, &aInf ); pFrm->_Format( aLine, aInf ); if ( pFrm->IsVertical() ) pFrm->SwapWidthAndHeight(); ASSERT( ! pFrm->IsSwapped(), "A frame is swapped after _Format" ); } SwTestFormat::~SwTestFormat() { pFrm->Frm() = aOldFrm; pFrm->Prt() = aOldPrt; pFrm->SetPara( pOldPara ); } sal_Bool SwTxtFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, sal_Bool &bSplit ) { PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 ) if( IsLocked() && GetUpper()->Prt().Width() <= 0 ) return sal_False; SwTestFormat aSave( this, pPrv, rMaxHeight ); return SwTxtFrm::WouldFit( rMaxHeight, bSplit, sal_True ); } /************************************************************************* * SwTxtFrm::WouldFit() *************************************************************************/ /* SwTxtFrm::WouldFit() * sal_True: wenn ich aufspalten kann. * Es soll und braucht nicht neu formatiert werden. * Wir gehen davon aus, dass bereits formatiert wurde und dass * die Formatierungsdaten noch aktuell sind. * Wir gehen davon aus, dass die Framebreiten des evtl. Masters und * Follows gleich sind. Deswegen wird kein FindBreak() mit FindOrphans() * gerufen. * Die benoetigte Hoehe wird von nMaxHeight abgezogen! */ sal_Bool SwTxtFrm::WouldFit( SwTwips &rMaxHeight, sal_Bool &bSplit, sal_Bool bTst ) { ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::WouldFit with swapped frame" ); SWRECTFN( this ); if( IsLocked() ) return sal_False; //Kann gut sein, dass mir der IdleCollector mir die gecachten //Informationen entzogen hat. if( !IsEmpty() ) GetFormatted(); // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph // can *not* be applied, if test format is in progress. The test format doesn't // adjust the frame and the printing area - see method , // which is called in if ( IsEmpty() && !bTst ) { bSplit = sal_False; SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height(); if( rMaxHeight < nHeight ) return sal_False; else { rMaxHeight -= nHeight; return sal_True; } } // In sehr unguenstigen Faellen kann GetPara immer noch 0 sein. // Dann returnen wir sal_True, um auf der neuen Seite noch einmal // anformatiert zu werden. ASSERT( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" ); if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) ) return sal_True; // Da das Orphan-Flag nur sehr fluechtig existiert, wird als zweite // Bedingung ueberprueft, ob die Rahmengroesse durch CalcPreps // auf riesengross gesetzt wird, um ein MoveFwd zu erzwingen. if( IsWidow() || ( bVert ? ( 0 == Frm().Left() ) : ( LONG_MAX - 20000 < Frm().Bottom() ) ) ) { SetWidow(sal_False); if ( GetFollow() ) { // Wenn wir hier durch eine Widow-Anforderung unseres Follows gelandet // sind, wird ueberprueft, ob es ueberhaupt einen Follow mit einer // echten Hoehe gibt, andernfalls (z.B. in neu angelegten SctFrms) // ignorieren wir das IsWidow() und pruefen doch noch, ob wir // genung Platz finden. if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) || ( bVert && 0 < Frm().Left() ) ) && ( GetFollow()->IsVertical() ? !GetFollow()->Frm().Width() : !GetFollow()->Frm().Height() ) ) { SwTxtFrm* pFoll = GetFollow()->GetFollow(); while( pFoll && ( pFoll->IsVertical() ? !pFoll->Frm().Width() : !pFoll->Frm().Height() ) ) pFoll = pFoll->GetFollow(); if( pFoll ) return sal_False; } else return sal_False; } } SWAP_IF_NOT_SWAPPED( this ); SwTxtSizeInfo aInf( this ); SwTxtMargin aLine( this, &aInf ); WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit ); sal_Bool bRet = sal_True; aLine.Bottom(); // Ist Aufspalten ueberhaupt notwendig? if ( 0 != ( bSplit = !aFrmBreak.IsInside( aLine ) ) ) bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst ); else { //Wir brauchen die Gesamthoehe inklusive der aktuellen Zeile aLine.Top(); do { rMaxHeight -= aLine.GetLineHeight(); } while ( aLine.Next() ); } UNDO_SWAP( this ) return bRet; } /************************************************************************* * SwTxtFrm::GetParHeight() *************************************************************************/ KSHORT SwTxtFrm::GetParHeight() const { ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::GetParHeight with swapped frame" ) if( !HasPara() ) { // Fuer nichtleere Absaetze ist dies ein Sonderfall, da koennen wir // bei UnderSized ruhig nur 1 Twip mehr anfordern. KSHORT nRet = (KSHORT)Prt().SSize().Height(); if( IsUndersized() ) { if( IsEmpty() ) nRet = (KSHORT)EmptyHeight(); else ++nRet; } return nRet; } // FME, OD 08.01.2004 #i11859# - refactoring and improve code const SwLineLayout* pLineLayout = GetPara(); KSHORT nHeight = pLineLayout->GetRealHeight(); if( GetOfst() && !IsFollow() ) // Ist dieser Absatz gescrollt? Dann ist unsere nHeight *= 2; // bisherige Hoehe mind. eine Zeilenhoehe zu gering // OD 2004-03-04 #115793# while ( pLineLayout && pLineLayout->GetNext() ) { pLineLayout = pLineLayout->GetNext(); nHeight = nHeight + pLineLayout->GetRealHeight(); } return nHeight; } /************************************************************************* * SwTxtFrm::GetFormatted() *************************************************************************/ // returnt this _immer_ im formatierten Zustand! SwTxtFrm* SwTxtFrm::GetFormatted( bool bForceQuickFormat ) { SWAP_IF_SWAPPED( this ) //Kann gut sein, dass mir der IdleCollector mir die gecachten //Informationen entzogen hat. Calc() ruft unser Format. //Nicht bei leeren Absaetzen! if( !HasPara() && !(IsValid() && IsEmpty()) ) { // Calc() muss gerufen werden, weil unsere Frameposition // nicht stimmen muss. const sal_Bool bFormat = GetValidSizeFlag(); Calc(); // Es kann durchaus sein, dass Calc() das Format() // nicht anstiess (weil wir einst vom Idle-Zerstoerer // aufgefordert wurden unsere Formatinformationen wegzuschmeissen). // 6995: Optimierung mit FormatQuick() if( bFormat && !FormatQuick( bForceQuickFormat ) ) Format(); } UNDO_SWAP( this ) return this; } /************************************************************************* * SwTxtFrm::CalcFitToContent() *************************************************************************/ SwTwips SwTxtFrm::CalcFitToContent() { // --> FME 2004-07-16 #i31490# // If we are currently locked, we better return with a // fairly reasonable value: if ( IsLocked() ) return Prt().Width(); // <-- SwParaPortion* pOldPara = GetPara(); SwParaPortion *pDummy = new SwParaPortion(); SetPara( pDummy, false ); const SwPageFrm* pPage = FindPageFrm(); const Point aOldFrmPos = Frm().Pos(); const SwTwips nOldFrmWidth = Frm().Width(); const SwTwips nOldPrtWidth = Prt().Width(); const SwTwips nPageWidth = GetUpper()->IsVertical() ? pPage->Prt().Height() : pPage->Prt().Width(); Frm().Width( nPageWidth ); Prt().Width( nPageWidth ); // --> FME 2004-07-19 #i25422# objects anchored as character in RTL if ( IsRightToLeft() ) Frm().Pos().X() += nOldFrmWidth - nPageWidth; // --> FME 2004-07-16 #i31490# SwTxtFrmLocker aLock( this ); // <-- SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True ); aInf.SetIgnoreFly( sal_True ); SwTxtFormatter aLine( this, &aInf ); SwHookOut aHook( aInf ); // --> OD 2005-09-06 #i54031# - assure mininum of MINLAY twips. const SwTwips nMax = Max( (SwTwips)MINLAY, aLine._CalcFitToContent() + 1 ); // <-- Frm().Width( nOldFrmWidth ); Prt().Width( nOldPrtWidth ); // --> FME 2004-07-19 #i25422# objects anchored as character in RTL if ( IsRightToLeft() ) Frm().Pos() = aOldFrmPos; SetPara( pOldPara ); return nMax; } /** simulate format for a list item paragraph, whose list level attributes are in LABEL_ALIGNMENT mode, in order to determine additional first line offset for the real text formatting due to the value of label adjustment attribute of the list level. OD 2008-01-31 #newlistlevelattrs# @author OD */ void SwTxtFrm::CalcAdditionalFirstLineOffset() { if ( IsLocked() ) return; // reset additional first line offset mnAdditionalFirstLineOffset = 0; const SwTxtNode* pTxtNode( GetTxtNode() ); if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->IsCountedInList() && pTxtNode->GetNumRule() ) { const SwNumFmt& rNumFmt = pTxtNode->GetNumRule()->Get( static_cast(pTxtNode->GetActualListLevel()) ); if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) { // keep current paragraph portion and apply dummy paragraph portion SwParaPortion* pOldPara = GetPara(); SwParaPortion *pDummy = new SwParaPortion(); SetPara( pDummy, false ); // lock paragraph SwTxtFrmLocker aLock( this ); // simulate text formatting SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True ); aInf.SetIgnoreFly( sal_True ); SwTxtFormatter aLine( this, &aInf ); SwHookOut aHook( aInf ); aLine._CalcFitToContent(); // determine additional first line offset const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion(); if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFtnNumPortion() ) { SwTwips nNumberPortionWidth( pFirstPortion->Width() ); const SwLinePortion* pPortion = pFirstPortion->GetPortion(); while ( pPortion && pPortion->InNumberGrp() && !pPortion->IsFtnNumPortion()) { nNumberPortionWidth += pPortion->Width(); pPortion = pPortion->GetPortion(); } if ( ( IsRightToLeft() && rNumFmt.GetNumAdjust() == SVX_ADJUST_LEFT ) || ( !IsRightToLeft() && rNumFmt.GetNumAdjust() == SVX_ADJUST_RIGHT ) ) { mnAdditionalFirstLineOffset = -nNumberPortionWidth; } else if ( rNumFmt.GetNumAdjust() == SVX_ADJUST_CENTER ) { mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2); } } // restore paragraph portion SetPara( pOldPara ); } } } /** determine height of last line for the calculation of the proportional line spacing OD 08.01.2004 #i11859# OD 2004-03-17 #i11860# - method replace by method <_CalcHeightOfLastLine()>. Height of last line will be stored in new member and can be accessed via method OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont> in order to force the usage of the former algorithm to determine the height of the last line, which uses the font. @author OD */ void SwTxtFrm::_CalcHeightOfLastLine( const bool _bUseFont ) { // --> OD 2006-11-13 #i71281# // invalidate printing area, if height of last line changes const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine ); // <-- // determine output device ViewShell* pVsh = GetShell(); ASSERT( pVsh, " - no ViewShell" ); // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch // There could be no instance in the case of loading a binary // StarOffice file format containing an embedded Writer document. if ( !pVsh ) { return; } OutputDevice* pOut = pVsh->GetOut(); const IDocumentSettingAccess* pIDSA = GetTxtNode()->getIDocumentSettingAccess(); if ( !pIDSA->get(IDocumentSettingAccess::BROWSE_MODE) || pVsh->GetViewOptions()->IsPrtFormat() ) { pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true ); } ASSERT( pOut, " - no OutputDevice" ); // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch if ( !pOut ) { return; } // <-- // determine height of last line if ( _bUseFont || pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING ) ) { // former determination of last line height for proprotional line // spacing - take height of font set at the paragraph SwFont aFont( GetAttrSet(), pIDSA ); // Wir muessen dafuer sorgen, dass am OutputDevice der Font // korrekt restauriert wird, sonst droht ein Last!=Owner. if ( pLastFont ) { SwFntObj *pOldFont = pLastFont; pLastFont = NULL; aFont.SetFntChg( sal_True ); aFont.ChgPhysFnt( pVsh, *pOut ); mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut ); pLastFont->Unlock(); pLastFont = pOldFont; pLastFont->SetDevFont( pVsh, *pOut ); } else { Font aOldFont = pOut->GetFont(); aFont.SetFntChg( sal_True ); aFont.ChgPhysFnt( pVsh, *pOut ); mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut ); pLastFont->Unlock(); pLastFont = NULL; pOut->SetFont( aOldFont ); } } else { // new determination of last line height - take actually height of last line // --> OD 2008-05-06 #i89000# // assure same results, if paragraph is undersized if ( IsUndersized() ) { mnHeightOfLastLine = 0; } else { bool bCalcHeightOfLastLine = true; if ( !HasPara() ) { if ( IsEmpty() ) { mnHeightOfLastLine = EmptyHeight(); bCalcHeightOfLastLine = false; } } if ( bCalcHeightOfLastLine ) { ASSERT( HasPara(), " - missing paragraph portions." ); const SwLineLayout* pLineLayout = GetPara(); while ( pLineLayout && pLineLayout->GetNext() ) { // iteration to last line pLineLayout = pLineLayout->GetNext(); } if ( pLineLayout ) { SwTwips nAscent, nDescent, nDummy1, nDummy2; // --> OD 2005-05-20 #i47162# - suppress consideration of // fly content portions and the line portion. pLineLayout->MaxAscentDescent( nAscent, nDescent, nDummy1, nDummy2, 0, true ); // <-- // --> OD 2006-11-22 #i71281# // Suppress wrong invalidation of printing area, if method is // called recursive. // Thus, member is only set directly, if // no recursive call is needed. // mnHeightOfLastLine = nAscent + nDescent; const SwTwips nNewHeightOfLastLine = nAscent + nDescent; // --> OD 2005-05-20 #i47162# - if last line only contains // fly content portions, is zero. // In this case determine height of last line by the font if ( nNewHeightOfLastLine == 0 ) { _CalcHeightOfLastLine( true ); } else { mnHeightOfLastLine = nNewHeightOfLastLine; } // <-- // <-- } } } // <-- } // --> OD 2006-11-13 #i71281# // invalidate printing area, if height of last line changes if ( mnHeightOfLastLine != mnOldHeightOfLastLine ) { InvalidatePrt(); } // <-- } /************************************************************************* * SwTxtFrm::GetLineSpace() *************************************************************************/ // OD 07.01.2004 #i11859# - change return data type // add default parameter <_bNoPropLineSpacing> to control, if the // value of a proportional line spacing is returned or not // OD 07.01.2004 - trying to describe purpose of method: // Method returns the value of the inter line spacing for a text frame. // Such a value exists for proportional line spacings ("1,5 Lines", // "Double", "Proportional" and for leading line spacing ("Leading"). // By parameter <_bNoPropLineSpace> (default value false) it can be // controlled, if the value of a proportional line spacing is returned. long SwTxtFrm::GetLineSpace( const bool _bNoPropLineSpace ) const { long nRet = 0; const SwAttrSet* pSet = GetAttrSet(); const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing(); switch( rSpace.GetInterLineSpaceRule() ) { case SVX_INTER_LINE_SPACE_PROP: { // OD 07.01.2004 #i11859# if ( _bNoPropLineSpace ) { break; } // OD 2004-03-17 #i11860# - use method nRet = GetHeightOfLastLine(); long nTmp = nRet; nTmp *= rSpace.GetPropLineSpace(); nTmp /= 100; nTmp -= nRet; if ( nTmp > 0 ) nRet = nTmp; else nRet = 0; } break; case SVX_INTER_LINE_SPACE_FIX: { if ( rSpace.GetInterLineSpace() > 0 ) nRet = rSpace.GetInterLineSpace(); } break; default: break; } return nRet; } /************************************************************************* * SwTxtFrm::FirstLineHeight() *************************************************************************/ KSHORT SwTxtFrm::FirstLineHeight() const { if ( !HasPara() ) { if( IsEmpty() && IsValid() ) return IsVertical() ? (KSHORT)Prt().Width() : (KSHORT)Prt().Height(); return KSHRT_MAX; } const SwParaPortion *pPara = GetPara(); if ( !pPara ) return KSHRT_MAX; return pPara->Height(); } MSHORT SwTxtFrm::GetLineCount( xub_StrLen nPos ) { MSHORT nRet = 0; SwTxtFrm *pFrm = this; do { pFrm->GetFormatted(); if( !pFrm->HasPara() ) break; SwTxtSizeInfo aInf( pFrm ); SwTxtMargin aLine( pFrm, &aInf ); if( STRING_LEN == nPos ) aLine.Bottom(); else aLine.CharToLine( nPos ); nRet = nRet + aLine.GetLineNr(); pFrm = pFrm->GetFollow(); } while ( pFrm && pFrm->GetOfst() <= nPos ); return nRet; } void SwTxtFrm::ChgThisLines() { //not necassary to format here (GerFormatted etc.), because we have to come from there! sal_uLong nNew = 0; const SwLineNumberInfo &rInf = GetNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo(); if ( GetTxt().Len() && HasPara() ) { SwTxtSizeInfo aInf( this ); SwTxtMargin aLine( this, &aInf ); if ( rInf.IsCountBlankLines() ) { aLine.Bottom(); nNew = (sal_uLong)aLine.GetLineNr(); } else { do { if( aLine.GetCurr()->HasCntnt() ) ++nNew; } while ( aLine.NextLine() ); } } else if ( rInf.IsCountBlankLines() ) nNew = 1; if ( nNew != nThisLines ) { if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() ) { nAllLines -= nThisLines; nThisLines = nNew; nAllLines += nThisLines; SwFrm *pNxt = GetNextCntntFrm(); while( pNxt && pNxt->IsInTab() ) { if( 0 != (pNxt = pNxt->FindTabFrm()) ) pNxt = pNxt->FindNextCnt(); } if( pNxt ) pNxt->InvalidateLineNum(); //Extend repaint to the bottom. if ( HasPara() ) { SwRepaint *pRepaint = GetPara()->GetRepaint(); pRepaint->Bottom( Max( pRepaint->Bottom(), Frm().Top()+Prt().Bottom())); } } else //Paragraphs which are not counted should not manipulate the AllLines. nThisLines = nNew; } } void SwTxtFrm::RecalcAllLines() { ValidateLineNum(); const SwAttrSet *pAttrSet = GetAttrSet(); if ( !IsInTab() ) { const sal_uLong nOld = GetAllLines(); const SwFmtLineNumber &rLineNum = pAttrSet->GetLineNumber(); sal_uLong nNewNum; const bool bRestart = GetTxtNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo().IsRestartEachPage(); if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() ) nNewNum = rLineNum.GetStartValue() - 1; //If it is a follow or not has not be considered if it is a restart at each page; the //restart should also take affekt at follows. else if ( bRestart && FindPageFrm()->FindFirstBodyCntnt() == this ) { nNewNum = 0; } else { SwCntntFrm *pPrv = GetPrevCntntFrm(); while ( pPrv && (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) ) pPrv = pPrv->GetPrevCntntFrm(); // --> FME 2007-06-22 #i78254# Restart line numbering at page change: // First body content may be in table! if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() ) pPrv = 0; // <-- nNewNum = pPrv ? ((SwTxtFrm*)pPrv)->GetAllLines() : 0; } if ( rLineNum.IsCount() ) nNewNum += GetThisLines(); if ( nOld != nNewNum ) { nAllLines = nNewNum; SwCntntFrm *pNxt = GetNextCntntFrm(); while ( pNxt && (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) ) pNxt = pNxt->GetNextCntntFrm(); if ( pNxt ) { if ( pNxt->GetUpper() != GetUpper() ) pNxt->InvalidateLineNum(); else pNxt->_InvalidateLineNum(); } } } } void SwTxtFrm::VisitPortions( SwPortionHandler& rPH ) const { const SwParaPortion* pPara = GetPara(); if( pPara ) { if ( IsFollow() ) rPH.Skip( GetOfst() ); const SwLineLayout* pLine = pPara; while ( pLine ) { const SwLinePortion* pPor = pLine->GetFirstPortion(); while ( pPor ) { pPor->HandlePortion( rPH ); pPor = pPor->GetPortion(); } rPH.LineBreak(); pLine = pLine->GetNext(); } } rPH.Finish(); } /************************************************************************* * SwTxtFrm::GetScriptInfo() *************************************************************************/ const SwScriptInfo* SwTxtFrm::GetScriptInfo() const { const SwParaPortion* pPara = GetPara(); return pPara ? &pPara->GetScriptInfo() : 0; } /************************************************************************* * lcl_CalcFlyBasePos() * Helper function for SwTxtFrm::CalcBasePosForFly() *************************************************************************/ SwTwips lcl_CalcFlyBasePos( const SwTxtFrm& rFrm, SwRect aFlyRect, SwTxtFly& rTxtFly ) { SWRECTFN( (&rFrm) ) SwTwips nRet = rFrm.IsRightToLeft() ? (rFrm.Frm().*fnRect->fnGetRight)() : (rFrm.Frm().*fnRect->fnGetLeft)(); do { SwRect aRect = rTxtFly.GetFrm( aFlyRect ); if ( 0 != (aRect.*fnRect->fnGetWidth)() ) { if ( rFrm.IsRightToLeft() ) { if ( (aRect.*fnRect->fnGetRight)() - (aFlyRect.*fnRect->fnGetRight)() >= 0 ) { (aFlyRect.*fnRect->fnSetRight)( (aRect.*fnRect->fnGetLeft)() ); nRet = (aRect.*fnRect->fnGetLeft)(); } else break; } else { if ( (aFlyRect.*fnRect->fnGetLeft)() - (aRect.*fnRect->fnGetLeft)() >= 0 ) { (aFlyRect.*fnRect->fnSetLeft)( (aRect.*fnRect->fnGetRight)() + 1 ); nRet = (aRect.*fnRect->fnGetRight)(); } else break; } } else break; } while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 ); return nRet; } /************************************************************************* * SwTxtFrm::CalcBasePosForFly() *************************************************************************/ void SwTxtFrm::CalcBaseOfstForFly() { ASSERT( !IsVertical() || !IsSwapped(), "SwTxtFrm::CalcBasePosForFly with swapped frame!" ) const SwNode* pNode = GetTxtNode(); if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_FLY_OFFSETS) ) return; SWRECTFN( this ) SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() ); // Get first 'real' line and adjust position and height of line rectangle // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour, // if no 'real' line exists (empty paragraph with and without a dummy portion) { SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)(); const SwLineLayout* pLay = GetPara(); SwTwips nLineHeight = 200; while( pLay && pLay->IsDummy() && pLay->GetNext() ) { nTop += pLay->Height(); pLay = pLay->GetNext(); } if ( pLay ) { nLineHeight = pLay->Height(); } (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight ); } SwTxtFly aTxtFly( this ); aTxtFly.SetIgnoreCurrentFrame( sal_True ); aTxtFly.SetIgnoreContour( sal_True ); // --> OD 2004-12-17 #118809# - ignore objects in page header|footer for // text frames not in page header|footer aTxtFly.SetIgnoreObjsInHeaderFooter( sal_True ); // <-- SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly ); aTxtFly.SetIgnoreCurrentFrame( sal_False ); SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly ); // make values relative to frame start position SwTwips nLeft = IsRightToLeft() ? (Frm().*fnRect->fnGetRight)() : (Frm().*fnRect->fnGetLeft)(); mnFlyAnchorOfst = nRet1 - nLeft; mnFlyAnchorOfstNoWrap = nRet2 - nLeft; }