summaryrefslogtreecommitdiff
path: root/sw/source/core/text/txtftn.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/txtftn.cxx')
-rw-r--r--sw/source/core/text/txtftn.cxx1699
1 files changed, 1699 insertions, 0 deletions
diff --git a/sw/source/core/text/txtftn.cxx b/sw/source/core/text/txtftn.cxx
new file mode 100644
index 000000000000..2b655847ad05
--- /dev/null
+++ b/sw/source/core/text/txtftn.cxx
@@ -0,0 +1,1699 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+#include "viewsh.hxx"
+#include "doc.hxx"
+#include "pagefrm.hxx"
+#include "ndtxt.hxx"
+#include "txtatr.hxx"
+#include <SwPortionHandler.hxx>
+#include <txtftn.hxx>
+#include <flyfrm.hxx>
+#include <fmtftn.hxx>
+#include <ftninfo.hxx>
+#include <charfmt.hxx>
+#include <dflyobj.hxx>
+#include <rowfrm.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <breakit.hxx>
+#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+#include <com/sun/star/i18n/ScriptType.hdl>
+#endif
+#include <tabfrm.hxx>
+// OD 2004-05-24 #i28701#
+#include <sortedobjs.hxx>
+
+#include "txtcfg.hxx"
+#include "swfont.hxx" // new SwFont
+#include "porftn.hxx"
+#include "porfly.hxx"
+#include "porlay.hxx"
+#include "txtfrm.hxx"
+#include "itrform2.hxx"
+#include "ftnfrm.hxx" // FindQuoVadisFrm(),
+#include "pagedesc.hxx"
+#include "redlnitr.hxx" // SwRedlnItr
+#include "sectfrm.hxx" // SwSectionFrm
+#include "layouter.hxx" // Endnote-Collection
+#include "frmtool.hxx"
+#include "ndindex.hxx"
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * _IsFtnNumFrm()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::_IsFtnNumFrm() const
+{
+ const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster();
+ while( pFtn && !pFtn->ContainsCntnt() )
+ pFtn = pFtn->GetMaster();
+ return !pFtn;
+}
+
+/*************************************************************************
+ * FindFtn()
+ *************************************************************************/
+
+// Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn
+
+SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn )
+{
+ SwTxtFrm *pFrm = this;
+ const sal_Bool bFwd = *pFtn->GetStart() >= GetOfst();
+ while( pFrm )
+ {
+ if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) )
+ return pFrm;
+ pFrm = bFwd ? pFrm->GetFollow() :
+ pFrm->IsFollow() ? pFrm->FindMaster() : 0;
+ }
+ return pFrm;
+}
+
+/*************************************************************************
+ * CalcFtnFlag()
+ *************************************************************************/
+
+#ifndef DBG_UTIL
+void SwTxtFrm::CalcFtnFlag()
+#else
+void SwTxtFrm::CalcFtnFlag( xub_StrLen nStop )//Fuer den Test von SplitFrm
+#endif
+{
+ bFtn = sal_False;
+
+ const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( !pHints )
+ return;
+
+ const USHORT nSize = pHints->Count();
+
+#ifndef DBG_UTIL
+ const xub_StrLen nEnd = GetFollow() ? GetFollow()->GetOfst() : STRING_LEN;
+#else
+ const xub_StrLen nEnd = nStop != STRING_LEN ? nStop
+ : GetFollow() ? GetFollow()->GetOfst() : STRING_LEN;
+#endif
+
+ for ( USHORT 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( GetOfst() <= nIdx )
+ {
+ bFtn = sal_True;
+ break;
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * CalcPrepFtnAdjust()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::CalcPrepFtnAdjust()
+{
+ ASSERT( HasFtn(), "Wer ruft mich da?" );
+ SwFtnBossFrm *pBoss = FindFtnBossFrm( sal_True );
+ const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this );
+ if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos &&
+ ( !pBoss->GetUpper()->IsSctFrm() ||
+ !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) )
+ {
+ const SwFtnContFrm *pCont = pBoss->FindFtnCont();
+ sal_Bool bReArrange = sal_True;
+
+ SWRECTFN( this )
+ if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
+ (Frm().*fnRect->fnGetBottom)() ) > 0 )
+ {
+ pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), sal_False,
+ pFtn->GetAttr() );
+ ValidateBodyFrm();
+ ValidateFrm();
+ pFtn = pBoss->FindFirstFtn( this );
+ }
+ else
+ bReArrange = sal_False;
+ if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) )
+ {
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+ aLine.TruncLines();
+ SetPara( 0 ); //Wird ggf. geloescht!
+ ResetPreps();
+ return sal_False;
+ }
+ }
+ return sal_True;
+}
+
+
+/*************************************************************************
+ * lcl_GetFtnLower()
+ *
+ * Local helper function. Checks if nLower should be taken as the boundary
+ * for the footnote.
+ *************************************************************************/
+
+SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower )
+{
+ // nLower is an absolute value. It denotes the bottom of the line
+ // containing the footnote.
+ SWRECTFN( pFrm )
+
+ ASSERT( !pFrm->IsVertical() || !pFrm->IsSwapped(),
+ "lcl_GetFtnLower with swapped frame" );
+
+ SwTwips nAdd;
+ SwTwips nRet = nLower;
+
+ //
+ // Check if text is inside a table.
+ //
+ if ( pFrm->IsInTab() )
+ {
+ //
+ // If pFrm is inside a table, we have to check if
+ // a) The table is not allowed to split or
+ // b) The table row is not allowed to split
+ //
+ // Inside a table, there are no footnotes,
+ // see SwFrm::FindFtnBossFrm. So we don't have to check
+ // the case that pFrm is inside a (footnote collecting) section
+ // within the table.
+ //
+ const SwFrm* pRow = pFrm;
+ while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
+ pRow = pRow->GetUpper();
+ const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper();
+
+ ASSERT( pTabFrm && pRow &&
+ pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" )
+
+ const BOOL bDontSplit = !pTabFrm->IsFollow() &&
+ !pTabFrm->IsLayoutSplitAllowed();
+
+ SwTwips nMin = 0;
+ if ( bDontSplit )
+ nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)();
+ else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() )
+ nMin = (pRow->Frm().*fnRect->fnGetBottom)();
+
+ if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 )
+ nRet = nMin;
+
+ nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)();
+ }
+ else
+ nAdd = (pFrm->*fnRect->fnGetBottomMargin)();
+
+ if( nAdd > 0 )
+ {
+ if ( bVert )
+ nRet -= nAdd;
+ else
+ nRet += nAdd;
+ }
+
+ // #i10770#: If there are fly frames anchored at previous paragraphs,
+ // the deadline should consider their lower borders.
+ const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower();
+ ASSERT( pStartFrm, "Upper has no lower" )
+ SwTwips nFlyLower = bVert ? LONG_MAX : 0;
+ while ( pStartFrm != pFrm )
+ {
+ ASSERT( pStartFrm, "Frame chain is broken" )
+ if ( pStartFrm->GetDrawObjs() )
+ {
+ const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
+ for ( USHORT i = 0; i < rObjs.Count(); ++i )
+ {
+ SwAnchoredObject* pAnchoredObj = rObjs[i];
+ SwRect aRect( pAnchoredObj->GetObjRect() );
+
+ if ( !pAnchoredObj->ISA(SwFlyFrm) ||
+ static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() )
+ {
+ const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
+ if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 )
+ nFlyLower = nBottom;
+ }
+ }
+ }
+
+ pStartFrm = pStartFrm->GetNext();
+ }
+
+ if ( bVert )
+ nRet = Min( nRet, nFlyLower );
+ else
+ nRet = Max( nRet, nFlyLower );
+
+ return nRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::GetFtnLine()
+ *************************************************************************/
+
+SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const
+{
+ ASSERT( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::GetFtnLine with swapped frame" )
+
+ SwTxtFrm *pThis = (SwTxtFrm*)this;
+
+ if( !HasPara() )
+ {
+ // #109071# GetFormatted() does not work here, bacause most probably
+ // the frame is currently locked. We return the previous value.
+ return pThis->mnFtnLine > 0 ?
+ pThis->mnFtnLine :
+ IsVertical() ? Frm().Left() : Frm().Bottom();
+ }
+
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwTxtInfo aInf( pThis );
+ SwTxtIter aLine( pThis, &aInf );
+ const xub_StrLen nPos = *pFtn->GetStart();
+ aLine.CharToLine( nPos );
+
+ SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
+ if( IsVertical() )
+ nRet = SwitchHorizontalToVertical( nRet );
+
+ UNDO_SWAP( this )
+
+ nRet = lcl_GetFtnLower( pThis, nRet );
+
+ pThis->mnFtnLine = nRet;
+ return nRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetFtnRstHeight()
+ *************************************************************************/
+
+// Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich.
+// Sie wird eingeschraenkt durch den unteren Rand der Zeile mit
+// der Ftn-Referenz.
+
+SwTwips SwTxtFrm::_GetFtnFrmHeight() const
+{
+ ASSERT( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" );
+
+ const SwFtnFrm *pFtnFrm = FindFtnFrm();
+ const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef();
+ const SwFtnBossFrm *pBoss = FindFtnBossFrm();
+ if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()->
+ GetFtn().IsEndNote() ) )
+ return 0;
+
+ SWAP_IF_SWAPPED( this )
+
+ SwTwips nHeight = pRef->IsInFtnConnect() ?
+ 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() );
+ if( nHeight )
+ {
+ // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich
+ // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text
+ // eingeben.
+ const SwFrm *pCont = pFtnFrm->GetUpper();
+ //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf.
+ SWRECTFN( pCont )
+ SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
+ (Frm().*fnRect->fnGetTop)() );
+
+#ifdef DBG_UTIL
+ if( nTmp < 0 )
+ {
+ sal_Bool bInvalidPos = sal_False;
+ const SwLayoutFrm* pTmp = GetUpper();
+ while( !bInvalidPos && pTmp )
+ {
+ bInvalidPos = !pTmp->GetValidPosFlag() ||
+ !pTmp->Lower()->GetValidPosFlag();
+ if( pTmp == pCont )
+ break;
+ pTmp = pTmp->GetUpper();
+ }
+ ASSERT( bInvalidPos, "Hanging below FtnCont" );
+ }
+#endif
+
+ if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
+ {
+ //Wachstumspotential den Containers.
+ if ( !pRef->IsInFtnConnect() )
+ {
+ SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight );
+ nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True );
+ }
+ else
+ nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True );
+
+ nHeight += nTmp;
+ if( nHeight < 0 )
+ nHeight = 0;
+ }
+ else
+ { // The container has to shrink
+ nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight);
+ if( nTmp > 0 )
+ nHeight = nTmp;
+ else
+ nHeight = 0;
+ }
+ }
+
+ UNDO_SWAP( this )
+
+ return nHeight;
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindQuoVadisFrm()
+ *************************************************************************/
+
+SwTxtFrm *SwTxtFrm::FindQuoVadisFrm()
+{
+ // Erstmal feststellen, ob wir in einem FtnFrm stehen:
+ if( GetIndPrev() || !IsInFtn() )
+ return 0;
+
+ // Zum Vorgaenger-FtnFrm
+ SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster();
+ if( !pFtnFrm )
+ return 0;
+
+ // Nun den letzten Cntnt:
+ const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt();
+ if( !pCnt )
+ return NULL;
+ const SwCntntFrm *pLast;
+ do
+ { pLast = pCnt;
+ pCnt = pCnt->GetNextCntntFrm();
+ } while( pCnt && pFtnFrm->IsAnLower( pCnt ) );
+ return (SwTxtFrm*)pLast;
+}
+
+/*************************************************************************
+ * SwTxtFrm::RemoveFtn()
+ *************************************************************************/
+
+void SwTxtFrm::RemoveFtn( const xub_StrLen nStart, const xub_StrLen nLen )
+{
+ if ( !IsFtnAllowed() )
+ return;
+
+ SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( !pHints )
+ return;
+
+ sal_Bool bRollBack = nLen != STRING_LEN;
+ USHORT nSize = pHints->Count();
+ xub_StrLen nEnd;
+ SwTxtFrm* pSource;
+ if( bRollBack )
+ {
+ nEnd = nStart + nLen;
+ pSource = GetFollow();
+ if( !pSource )
+ return;
+ }
+ else
+ {
+ nEnd = STRING_LEN;
+ pSource = this;
+ }
+
+ if( nSize )
+ {
+ SwPageFrm* pUpdate = NULL;
+ sal_Bool bRemove = sal_False;
+ SwFtnBossFrm *pFtnBoss = 0;
+ SwFtnBossFrm *pEndBoss = 0;
+ sal_Bool bFtnEndDoc
+ = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos;
+ for ( USHORT i = nSize; i; )
+ {
+ SwTxtAttr *pHt = pHints->GetTextHint(--i);
+ if ( RES_TXTATR_FTN != pHt->Which() )
+ continue;
+
+ const xub_StrLen nIdx = *pHt->GetStart();
+ if( nStart > nIdx )
+ break;
+
+ if( nEnd >= nIdx )
+ {
+ SwTxtFtn *pFtn = (SwTxtFtn*)pHt;
+ sal_Bool bEndn = pFtn->GetFtn().IsEndNote();
+
+ if( bEndn )
+ {
+ if( !pEndBoss )
+ pEndBoss = pSource->FindFtnBossFrm();
+ }
+ else
+ {
+ if( !pFtnBoss )
+ {
+ pFtnBoss = pSource->FindFtnBossFrm( sal_True );
+ if( pFtnBoss->GetUpper()->IsSctFrm() )
+ {
+ SwSectionFrm* pSect = (SwSectionFrm*)
+ pFtnBoss->GetUpper();
+ if( pSect->IsFtnAtEnd() )
+ bFtnEndDoc = sal_False;
+ }
+ }
+ }
+
+ // Wir loeschen nicht, sondern wollen die Ftn verschieben.
+ // Drei Faelle koennen auftreten:
+ // 1) Es gibt weder Follow noch PrevFollow
+ // -> RemoveFtn() (vielleicht sogar ein ASSERT wert)
+ // 2) nStart > GetOfst, ich habe einen Follow
+ // -> Ftn wandert in den Follow
+ // 3) nStart < GetOfst, ich bin ein Follow
+ // -> Ftn wandert in den PrevFollow
+ // beide muessen auf einer Seite/in einer Spalte stehen.
+
+ SwFtnFrm *pFtnFrm = bEndn ? pEndBoss->FindFtn( pSource, pFtn ) :
+ pFtnBoss->FindFtn( pSource, pFtn );
+
+ if( pFtnFrm )
+ {
+ const sal_Bool bEndDoc = bEndn ? sal_True : bFtnEndDoc;
+ if( bRollBack )
+ {
+ while ( pFtnFrm )
+ {
+ pFtnFrm->SetRef( this );
+ pFtnFrm = pFtnFrm->GetFollow();
+ SetFtn( sal_True );
+ }
+ }
+ else if( GetFollow() )
+ {
+ SwCntntFrm *pDest = GetFollow();
+ while( pDest->GetFollow() && ((SwTxtFrm*)pDest->
+ GetFollow())->GetOfst() <= nIdx )
+ pDest = pDest->GetFollow();
+ ASSERT( !pDest->FindFtnBossFrm( !bEndn )->FindFtn(
+ pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists");
+
+ //Nicht ummelden sondern immer Moven.
+ // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)>
+ if ( bEndDoc ||
+ !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) )
+ )
+ {
+ SwPageFrm* pTmp = pFtnFrm->FindPageFrm();
+ if( pUpdate && pUpdate != pTmp )
+ pUpdate->UpdateFtnNum();
+ pUpdate = pTmp;
+ while ( pFtnFrm )
+ {
+ pFtnFrm->SetRef( pDest );
+ pFtnFrm = pFtnFrm->GetFollow();
+ }
+ }
+ else
+ {
+ if( bEndn )
+ pEndBoss->MoveFtns( this, pDest, pFtn );
+ else
+ pFtnBoss->MoveFtns( this, pDest, pFtn );
+ bRemove = sal_True;
+ }
+ ((SwTxtFrm*)pDest)->SetFtn( sal_True );
+
+ ASSERT( pDest->FindFtnBossFrm( !bEndn )->FindFtn( pDest,
+ pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed");
+ }
+ else
+ {
+ if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
+ !SwLayouter::Collecting( GetNode()->GetDoc(),
+ pEndBoss->FindSctFrm(), NULL ) ) )
+ {
+ if( bEndn )
+ pEndBoss->RemoveFtn( this, pFtn );
+ else
+ pFtnBoss->RemoveFtn( this, pFtn );
+ bRemove = bRemove || !bEndDoc;
+ ASSERT( bEndn ? !pEndBoss->FindFtn( this, pFtn ) :
+ !pFtnBoss->FindFtn( this, pFtn ),
+ "SwTxtFrm::RemoveFtn: can't get off that footnote" );
+ }
+ }
+ }
+ }
+ }
+ if( pUpdate )
+ pUpdate->UpdateFtnNum();
+ // Wir bringen die Oszillation zum stehen:
+ if( bRemove && !bFtnEndDoc && HasPara() )
+ {
+ ValidateBodyFrm();
+ ValidateFrm();
+ }
+ }
+ // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen,
+ // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset
+ // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist
+ // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig
+ // der Follow-Offset manipuliert.
+ xub_StrLen nOldOfst = STRING_LEN;
+ if( HasFollow() && nStart > GetOfst() )
+ {
+ nOldOfst = GetFollow()->GetOfst();
+ GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
+ }
+ pSource->CalcFtnFlag();
+ if( nOldOfst < STRING_LEN )
+ GetFollow()->ManipOfst( nOldOfst );
+}
+
+/*************************************************************************
+ * SwTxtFormatter::ConnectFtn()
+ *************************************************************************/
+// sal_False, wenn irgendetwas schief gegangen ist.
+// Es gibt eigentlich nur zwei Moeglichkeiten:
+// a) Die Ftn ist bereits vorhanden
+// => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde
+// b) Die Ftn ist nicht vorhanden
+// => dann wird sie fuer uns angelegt.
+// Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht,
+// spielt in diesem Zusammenhang keine Rolle.
+// Optimierungen bei Endnoten.
+// Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die
+// Ftn verschoben werden.
+
+void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine )
+{
+ ASSERT( !IsVertical() || !IsSwapped(),
+ "SwTxtFrm::ConnectFtn with swapped frame" );
+
+ bFtn = sal_True;
+ bInFtnConnect = sal_True; //Bloss zuruecksetzen!
+ sal_Bool bEnd = pFtn->GetFtn().IsEndNote();
+
+ //
+ // We want to store this value, because it is needed as a fallback
+ // in GetFtnLine(), if there is no paragraph information available
+ //
+ mnFtnLine = nDeadLine;
+
+ // Wir brauchen immer einen Boss (Spalte/Seite)
+ SwSectionFrm *pSect;
+ SwCntntFrm *pCntnt = this;
+ if( bEnd && IsInSct() )
+ {
+ pSect = FindSctFrm();
+ if( pSect->IsEndnAtEnd() )
+ pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE );
+ if( !pCntnt )
+ pCntnt = this;
+ }
+
+ SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd );
+
+#if OSL_DEBUG_LEVEL > 1
+ SwTwips nRstHeight = GetRstHeight();
+#endif
+
+ pSect = pBoss->FindSctFrm();
+ sal_Bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
+ ( !( pSect && pSect->IsFtnAtEnd() ) &&
+ FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos );
+ //Ftn kann beim Follow angemeldet sein.
+ SwCntntFrm *pSrcFrm = FindFtnRef( pFtn );
+
+ if( bDocEnd )
+ {
+ if( pSect && pSrcFrm )
+ {
+ SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
+ if( pFtnFrm && pFtnFrm->IsInSct() )
+ {
+ pBoss->RemoveFtn( pSrcFrm, pFtn );
+ pSrcFrm = 0;
+ }
+ }
+ }
+ else if( bEnd && pSect )
+ {
+ SwFtnFrm *pFtnFrm = pSrcFrm ? pBoss->FindFtn( pSrcFrm, pFtn ) : NULL;
+ if( pFtnFrm && !pFtnFrm->GetUpper() )
+ pFtnFrm = NULL;
+ SwDoc *pDoc = GetNode()->GetDoc();
+ if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) )
+ {
+ if( !pSrcFrm )
+ {
+ SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,pFtn);
+ SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 );
+ ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
+ GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
+ }
+ else if( pSrcFrm != this )
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ bInFtnConnect = sal_False;
+ return;
+ }
+ else if( pSrcFrm )
+ {
+ SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
+ if( !pFtnBoss->IsInSct() ||
+ pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
+ {
+ pBoss->RemoveFtn( pSrcFrm, pFtn );
+ pSrcFrm = 0;
+ }
+ }
+ }
+
+ if( bDocEnd || bEnd )
+ {
+ if( !pSrcFrm )
+ pBoss->AppendFtn( this, pFtn );
+ else if( pSrcFrm != this )
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ bInFtnConnect = sal_False;
+ return;
+ }
+
+ SwSaveFtnHeight aHeight( pBoss, nDeadLine );
+
+ if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden.
+ pBoss->AppendFtn( this, pFtn );
+ else
+ {
+ SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
+ SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
+
+ sal_Bool bBrutal = sal_False;
+
+ if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte.
+ {
+ SwFrm *pCont = pFtnFrm->GetUpper();
+
+ SWRECTFN ( pCont )
+ long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
+ nDeadLine );
+
+ if( nDiff >= 0 )
+ {
+ //Wenn die Fussnote bei einem Follow angemeldet ist, so ist
+ //es jetzt an der Zeit sie umzumelden.
+ if ( pSrcFrm != this )
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ //Es steht Platz zur Verfuegung, also kann die Fussnote evtl.
+ //wachsen.
+ if ( pFtnFrm->GetFollow() && nDiff > 0 )
+ {
+ SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
+ pBoss->RearrangeFtns( nDeadLine, sal_False, pFtn );
+ ValidateBodyFrm();
+ ValidateFrm();
+ ViewShell *pSh = GetShell();
+ if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
+ //Damit uns nix durch die Lappen geht.
+ pSh->InvalidateWindows( pCont->Frm() );
+ }
+ bInFtnConnect = sal_False;
+ return;
+ }
+ else
+ bBrutal = sal_True;
+ }
+ else
+ {
+ // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig.
+ SwFrm* pTmp = this;
+ while( pTmp->GetNext() && pSrcFrm != pTmp )
+ pTmp = pTmp->GetNext();
+ if( pSrcFrm == pTmp )
+ bBrutal = sal_True;
+ else
+ { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf
+ // der Seite schon einen FtnContainer gibt, hilft nur die brutale
+ // Methode
+ if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() )
+ bBrutal = sal_True;
+ // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)>
+ else if ( !pFtnFrm->GetPrev() ||
+ pFtnBoss->IsBefore( pBoss )
+ )
+ {
+ SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd );
+ pSrcBoss->MoveFtns( pSrcFrm, this, pFtn );
+ }
+ else
+ pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
+ }
+ }
+
+ // Die brutale Loesung: Fussnote entfernen und appenden.
+ // Es muss SetFtnDeadLine() gerufen werden, weil nach
+ // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche
+ // eingestellt werden kann.
+ if( bBrutal )
+ {
+ pBoss->RemoveFtn( pSrcFrm, pFtn, sal_False );
+ SwSaveFtnHeight *pHeight = bEnd ? NULL :
+ new SwSaveFtnHeight( pBoss, nDeadLine );
+ pBoss->AppendFtn( this, pFtn );
+ delete pHeight;
+ }
+ }
+
+ // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen,
+ // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch
+ // nicht kalkuliert worden ist.
+ if( !pSect || !pSect->Growable() )
+ {
+ // Umgebung validieren, um Oszillationen zu verhindern.
+ SwSaveFtnHeight aNochmal( pBoss, nDeadLine );
+ ValidateBodyFrm();
+ pBoss->RearrangeFtns( nDeadLine, sal_True );
+ ValidateFrm();
+ }
+ else if( pSect->IsFtnAtEnd() )
+ {
+ ValidateBodyFrm();
+ ValidateFrm();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ // pFtnFrm kann sich durch Calc veraendert haben ...
+ SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn );
+ if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) )
+ {
+ int bla = 5;
+ (void)bla;
+ }
+ nRstHeight = GetRstHeight();
+#endif
+ bInFtnConnect = sal_False;
+ return;
+}
+
+
+
+/*************************************************************************
+ * SwTxtFormatter::NewFtnPortion()
+ *************************************************************************/
+
+// Die Portion fuer die Ftn-Referenz im Text
+SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf,
+ SwTxtAttr *pHint )
+{
+ ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
+ "NewFtnPortion with unswapped frame" );
+
+ if( !pFrm->IsFtnAllowed() )
+ return 0;
+
+ SwTxtFtn *pFtn = (SwTxtFtn*)pHint;
+ SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
+ SwDoc *pDoc = pFrm->GetNode()->GetDoc();
+
+ if( rInf.IsTest() )
+ return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFrm, pFtn );
+
+ SWAP_IF_SWAPPED( pFrm )
+
+ KSHORT nReal;
+ {
+ KSHORT nOldReal = pCurr->GetRealHeight();
+ KSHORT nOldAscent = pCurr->GetAscent();
+ KSHORT nOldHeight = pCurr->Height();
+ ((SwTxtFormatter*)this)->CalcRealHeight();
+ nReal = pCurr->GetRealHeight();
+ if( nReal < nOldReal )
+ nReal = nOldReal;
+ pCurr->SetRealHeight( nOldReal );
+ pCurr->Height( nOldHeight );
+ pCurr->SetAscent( nOldAscent );
+ }
+
+ SwTwips nLower = Y() + nReal;
+
+ const bool bVertical = pFrm->IsVertical();
+ if( bVertical )
+ nLower = pFrm->SwitchHorizontalToVertical( nLower );
+
+ nLower = lcl_GetFtnLower( pFrm, nLower );
+
+ //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix
+ //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die
+ //Ftn wegwerfen und neu erzeugen.
+
+ if( !rInf.IsQuick() )
+ pFrm->ConnectFtn( pFtn, nLower );
+
+ SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn );
+ SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() );
+ SwFtnFrm *pFtnFrm = NULL;
+ if( pScrFrm )
+ pFtnFrm = pBoss->FindFtn( pScrFrm, pFtn );
+
+ // Wir erkundigen uns, ob durch unser Append irgendeine
+ // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet
+ // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten
+ // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr.
+ // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die
+ // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte.
+ // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt,
+ // so sollte die Ftn2-Referenz auch auf die naechste wandern.
+ if( !rFtn.IsEndNote() )
+ {
+ SwSectionFrm *pSct = pBoss->FindSctFrm();
+ sal_Bool bAtSctEnd = pSct && pSct->IsFtnAtEnd();
+ if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd )
+ {
+ SwFrm* pFtnCont = pBoss->FindFtnCont();
+ // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine
+ // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte
+ // ist, duerfen wir ausweichen
+ if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
+ ( !bAtSctEnd && pFrm->GetIndPrev() ) ||
+ ( pSct && pBoss->GetPrev() ) ) )
+ {
+ if( !pFtnCont )
+ {
+ rInf.SetStop( sal_True );
+ UNDO_SWAP( pFrm )
+ return 0;
+ }
+ else
+ {
+ // Es darf keine Fussnotencontainer in spaltigen Bereichen und
+ // gleichzeitig auf der Seite/Seitenspalte geben
+ if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich?
+ {
+ SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( sal_True );
+ SwFtnContFrm* pFtnC = pTmp->FindFtnCont();
+ if( pFtnC )
+ {
+ SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower();
+ if( pTmpFrm && *pTmpFrm < pFtn )
+ {
+ rInf.SetStop( sal_True );
+ UNDO_SWAP( pFrm )
+ return 0;
+ }
+ }
+ }
+ // Ist dies die letzte passende Zeile?
+ SwTwips nTmpBot = Y() + nReal * 2;
+
+ if( bVertical )
+ nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
+
+ SWRECTFN( pFtnCont )
+
+ const long nDiff = (*fnRect->fnYDiff)(
+ (pFtnCont->Frm().*fnRect->fnGetTop)(),
+ nTmpBot );
+
+ if( pScrFrm && nDiff < 0 )
+ {
+ if( pFtnFrm )
+ {
+ SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
+ if( pFtnBoss != pBoss )
+ {
+ // Wir sind in der letzte Zeile und die Fussnote
+ // ist auf eine andere Seite gewandert, dann wollen
+ // wir mit ...
+ rInf.SetStop( sal_True );
+ UNDO_SWAP( pFrm )
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // Endlich: FtnPortion anlegen und raus hier...
+ SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ),
+ pFrm, pFtn, nReal );
+ rInf.SetFtnInside( sal_True );
+
+ UNDO_SWAP( pFrm )
+
+ return pRet;
+ }
+
+/*************************************************************************
+ * SwTxtFormatter::NewFtnNumPortion()
+ *************************************************************************/
+
+// Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich
+
+SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const
+{
+ ASSERT( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(),
+ "This is the wrong place for a ftnnumber" );
+ if( rInf.GetTxtStart() != nStart ||
+ rInf.GetTxtStart() != rInf.GetIdx() )
+ return 0;
+
+ const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm();
+ const SwTxtFtn* pFtn = pFtnFrm->GetAttr();
+
+ // Aha, wir sind also im Fussnotenbereich
+ SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
+
+ SwDoc *pDoc = pFrm->GetNode()->GetDoc();
+ XubString aFtnTxt( rFtn.GetViewNumStr( *pDoc, sal_True ));
+
+ const SwEndNoteInfo* pInfo;
+ if( rFtn.IsEndNote() )
+ pInfo = &pDoc->GetEndNoteInfo();
+ else
+ pInfo = &pDoc->GetFtnInfo();
+ const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet();
+
+ const SwAttrSet* pParSet = &rInf.GetCharAttr();
+ const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess();
+ SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
+
+ // --> FME 2005-02-17 #i37142#
+ // Underline style of paragraph font should not be considered
+ // Overline style of paragraph font should not be considered
+ // Weight style of paragraph font should not be considered
+ // Posture style of paragraph font should not be considered
+ // See also #i18463# and SwTxtFormatter::NewNumberPortion()
+ pNumFnt->SetUnderline( UNDERLINE_NONE );
+ pNumFnt->SetOverline( UNDERLINE_NONE );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
+ pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
+ pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
+ // <--
+
+ pNumFnt->SetDiffFnt(&rSet, pIDSA );
+ pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
+
+ SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt );
+ pNewPor->SetLeft( !pFrm->IsRightToLeft() );
+ return pNewPor;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::NewErgoSumPortion()
+ *************************************************************************/
+
+XubString lcl_GetPageNumber( const SwPageFrm* pPage )
+{
+ ASSERT( pPage, "GetPageNumber: Homeless TxtFrm" );
+ MSHORT nVirtNum = pPage->GetVirtPageNum();
+ const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
+ return rNum.GetNumStr( nVirtNum );
+}
+
+SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const
+{
+ // Wir koennen nicht davon ausgehen, dass wir ein Follow sind
+ // 7983: GetIdx() nicht nStart
+ if( !pFrm->IsInFtn() || pFrm->GetPrev() ||
+ rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
+ pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
+ return 0;
+
+ // Aha, wir sind also im Fussnotenbereich
+ const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
+ SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
+ if( !pQuoFrm )
+ return 0;
+ const SwPageFrm* pPage = pFrm->FindPageFrm();
+ const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
+ if( pPage == pQuoFrm->FindPageFrm() )
+ return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht
+ const XubString aPage = lcl_GetPageNumber( pPage );
+ SwParaPortion *pPara = pQuoFrm->GetPara();
+ if( pPara )
+ pPara->SetErgoSumNum( aPage );
+ if( !rFtnInfo.aErgoSum.Len() )
+ return 0;
+ SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum,
+ lcl_GetPageNumber( pQuoPage ) );
+ return pErgo;
+}
+
+/*************************************************************************
+ * SwTxtFormatter::FormatQuoVadis()
+ *************************************************************************/
+
+xub_StrLen SwTxtFormatter::FormatQuoVadis( const xub_StrLen nOffset )
+{
+ ASSERT( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
+ "SwTxtFormatter::FormatQuoVadis with swapped frame" );
+
+ if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
+ return nOffset;
+
+ const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow();
+ if( !pErgoFrm && pFrm->HasFollow() )
+ pErgoFrm = pFrm->GetFollow();
+ if( !pErgoFrm )
+ return nOffset;
+
+ if( pErgoFrm == pFrm->GetNext() )
+ {
+ SwFrm *pCol = pFrm->FindColFrm();
+ while( pCol && !pCol->GetNext() )
+ pCol = pCol->GetUpper()->FindColFrm();
+ if( pCol )
+ return nOffset;
+ }
+ else
+ {
+ const SwPageFrm* pPage = pFrm->FindPageFrm();
+ const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm();
+ if( pPage == pErgoPage )
+ return nOffset; // Wenn der ErgoSum auf der selben Seite steht
+ }
+
+ SwTxtFormatInfo &rInf = GetInfo();
+ const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
+ if( !rFtnInfo.aQuoVadis.Len() )
+ return nOffset;
+
+ // Ein Wort zu QuoVadis/ErgoSum:
+ // Fuer diese Texte wird der am Absatz eingestellte Font verwendet.
+ // Wir initialisieren uns also:
+// ResetFont();
+ FeedInf( rInf );
+ SeekStartAndChg( rInf, sal_True );
+ if( GetRedln() && pCurr->HasRedline() )
+ GetRedln()->Seek( *pFnt, nOffset, 0 );
+
+ // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen
+ // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen.
+ // Erst mal sehen, ob es so schlimm ist:
+ SwLinePortion *pPor = pCurr->GetFirstPortion();
+ KSHORT nLastLeft = 0;
+ while( pPor )
+ {
+ if ( pPor->IsFlyPortion() )
+ nLastLeft = ( (SwFlyPortion*) pPor)->Fix() +
+ ( (SwFlyPortion*) pPor)->Width();
+ pPor = pPor->GetPortion();
+ }
+ // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten
+ // Stelle umbricht, also beeinflussen wir die Width.
+ // nLastLeft ist jetzt quasi der rechte Rand.
+ const KSHORT nOldRealWidth = rInf.RealWidth();
+ rInf.RealWidth( nOldRealWidth - nLastLeft );
+
+ XubString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
+ SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo );
+ pQuo->SetAscent( rInf.GetAscent() );
+ pQuo->Height( rInf.GetTxtHeight() );
+ pQuo->Format( rInf );
+ USHORT nQuoWidth = pQuo->Width();
+ SwLinePortion* pCurrPor = pQuo;
+
+ while ( rInf.GetRest() )
+ {
+ SwLinePortion* pFollow = rInf.GetRest();
+ rInf.SetRest( 0 );
+ pCurrPor->Move( rInf );
+
+ ASSERT( pFollow->IsQuoVadisPortion(),
+ "Quo Vadis, rest of QuoVadisPortion" )
+
+ // format the rest and append it to the other QuoVadis parts
+ pFollow->Format( rInf );
+ nQuoWidth = nQuoWidth + pFollow->Width();
+
+ pCurrPor->Append( pFollow );
+ pCurrPor = pFollow;
+ }
+
+ nLastLeft = nOldRealWidth - nQuoWidth;
+ Right( Right() - nQuoWidth );
+
+ SWAP_IF_NOT_SWAPPED( pFrm )
+
+ const xub_StrLen nRet = FormatLine( nStart );
+
+ UNDO_SWAP( pFrm )
+
+ Right( rInf.Left() + nOldRealWidth - 1 );
+
+ nLastLeft = nOldRealWidth - pCurr->Width();
+ FeedInf( rInf );
+
+ // Es kann durchaus sein, dass am Ende eine Marginportion steht,
+ // die beim erneuten Aufspannen nur Aerger bereiten wuerde.
+ pPor = pCurr->FindLastPortion();
+ SwGluePortion *pGlue = pPor->IsMarginPortion() ?
+ (SwMarginPortion*) pPor : 0;
+ if( pGlue )
+ {
+ pGlue->Height( 0 );
+ pGlue->Width( 0 );
+ pGlue->SetLen( 0 );
+ pGlue->SetAscent( 0 );
+ pGlue->SetPortion( NULL );
+ pGlue->SetFixWidth(0);
+ }
+
+ // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer,
+ // dass der QuoVadis-Text rechts erscheint:
+ nLastLeft = nLastLeft - nQuoWidth;
+ if( nLastLeft )
+ {
+ if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand
+ {
+ switch( GetAdjust() )
+ {
+ case SVX_ADJUST_BLOCK:
+ {
+ if( !pCurr->GetLen() ||
+ CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1))
+ nLastLeft = pQuo->GetAscent();
+ nQuoWidth = nQuoWidth + nLastLeft;
+ break;
+ }
+ case SVX_ADJUST_RIGHT:
+ {
+ nLastLeft = pQuo->GetAscent();
+ nQuoWidth = nQuoWidth + nLastLeft;
+ break;
+ }
+ case SVX_ADJUST_CENTER:
+ {
+ nQuoWidth = nQuoWidth + pQuo->GetAscent();
+ long nDiff = nLastLeft - nQuoWidth;
+ if( nDiff < 0 )
+ {
+ nLastLeft = pQuo->GetAscent();
+ nQuoWidth = (USHORT)(-nDiff + nLastLeft);
+ }
+ else
+ {
+ nQuoWidth = 0;
+ nLastLeft = USHORT(( pQuo->GetAscent() + nDiff ) / 2);
+ }
+ break;
+ }
+ default:
+ nQuoWidth = nQuoWidth + nLastLeft;
+ }
+ }
+ else
+ nQuoWidth = nQuoWidth + nLastLeft;
+ if( nLastLeft )
+ {
+ pGlue = new SwGluePortion(0);
+ pGlue->Width( nLastLeft );
+ pPor->Append( pGlue );
+ pPor = pPor->GetPortion();
+ }
+ }
+
+ // Jetzt aber: die QuoVadis-Portion wird angedockt:
+ pCurrPor = pQuo;
+ while ( pCurrPor )
+ {
+ // pPor->Append deletes the pPortoin pointer of pPor. Therefore
+ // we have to keep a pointer to the next portion
+ pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion();
+ pPor->Append( pCurrPor );
+ pPor = pPor->GetPortion();
+ pCurrPor = pQuo;
+ }
+
+ pCurr->Width( pCurr->Width() + KSHORT( nQuoWidth ) );
+
+ // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt
+ // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig
+ // einen kleineren Font eingestellt als der vom QuoVadis-Text ...
+ CalcAdjustLine( pCurr );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( OPTDBG( rInf ) )
+ {
+// aDbstream << "FormatQuoVadis:" << endl;
+// pCurr->DebugPortions( aDbstream, rInf.GetTxt(), nStart );
+ }
+#endif
+
+ // Uff...
+ return nRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFormatter::MakeDummyLine()
+ *************************************************************************/
+
+// MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand
+// reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen
+// zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden.
+// Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn-
+// Oszillationen verwendet.
+
+void SwTxtFormatter::MakeDummyLine()
+{
+ KSHORT nRstHeight = GetFrmRstHeight();
+ if( pCurr && nRstHeight > pCurr->Height() )
+ {
+ SwLineLayout *pLay = new SwLineLayout;
+ nRstHeight = nRstHeight - pCurr->Height();
+ pLay->Height( nRstHeight );
+ pLay->SetAscent( nRstHeight );
+ Insert( pLay );
+ Next();
+ }
+}
+
+/*************************************************************************
+ * class SwFtnSave
+ *************************************************************************/
+class SwFtnSave
+{
+ SwTxtSizeInfo *pInf;
+ SwFont *pFnt;
+ SwFont *pOld;
+public:
+ SwFtnSave( const SwTxtSizeInfo &rInf,
+ const SwTxtFtn *pTxtFtn,
+ const bool bApplyGivenScriptType,
+ const BYTE nGivenScriptType );
+ ~SwFtnSave();
+};
+
+/*************************************************************************
+ * SwFtnSave::SwFtnSave()
+ *************************************************************************/
+
+SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf,
+ const SwTxtFtn* pTxtFtn,
+ const bool bApplyGivenScriptType,
+ const BYTE nGivenScriptType )
+ : pInf( &((SwTxtSizeInfo&)rInf) )
+ , pFnt( 0 )
+ , pOld( 0 )
+{
+ if( pTxtFtn && rInf.GetTxtFrm() )
+ {
+ pFnt = ((SwTxtSizeInfo&)rInf).GetFont();
+ pOld = new SwFont( *pFnt );
+ pOld->GetTox() = pFnt->GetTox();
+ pFnt->GetTox() = 0;
+ SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
+ const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
+
+ // --> OD 2009-01-29 #i98418#
+ if ( bApplyGivenScriptType )
+ {
+ pFnt->SetActual( nGivenScriptType );
+ }
+ else
+ {
+ // examine text and set script
+ String aTmpStr( rFtn.GetViewNumStr( *pDoc ) );
+ pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
+ }
+ // <--
+
+ const SwEndNoteInfo* pInfo;
+ if( rFtn.IsEndNote() )
+ pInfo = &pDoc->GetEndNoteInfo();
+ else
+ pInfo = &pDoc->GetFtnInfo();
+ const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
+ pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() );
+
+ // we reduce footnote size, if we are inside a double line portion
+ if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() )
+ {
+ Size aSize = pFnt->GetSize( pFnt->GetActual() );
+ pFnt->SetSize( Size( (long)aSize.Width() / 2,
+ (long)aSize.Height() / 2 ),
+ pFnt->GetActual() );
+ }
+
+ // set the correct rotation at the footnote font
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
+ sal_True, &pItem ))
+ pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(),
+ rInf.GetTxtFrm()->IsVertical() );
+
+ pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
+
+ if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
+ sal_True, &pItem ))
+ pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) );
+ }
+ else
+ pFnt = NULL;
+}
+
+/*************************************************************************
+ * SwFtnSave::~SwFtnSave()
+ *************************************************************************/
+
+SwFtnSave::~SwFtnSave()
+{
+ if( pFnt )
+ {
+ // SwFont zurueckstellen
+ *pFnt = *pOld;
+ pFnt->GetTox() = pOld->GetTox();
+ pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
+ delete pOld;
+ }
+}
+
+/*************************************************************************
+ * SwFtnPortion::SwFtnPortion()
+ *************************************************************************/
+
+SwFtnPortion::SwFtnPortion( const XubString &rExpand, SwTxtFrm *pFrame,
+ SwTxtFtn *pFootn, KSHORT nReal )
+ : SwFldPortion( rExpand, 0 )
+ , pFrm(pFrame)
+ , pFtn(pFootn)
+ , nOrigHeight( nReal )
+ // --> OD 2009-01-29 #i98418#
+ , mbPreferredScriptTypeSet( false )
+ , mnPreferredScriptType( SW_LATIN )
+ // <--
+{
+ SetLen(1);
+ SetWhichPor( POR_FTN );
+}
+
+/*************************************************************************
+ * SwFtnPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwFtnPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwFtnPortion::Format( SwTxtFormatInfo &rInf )
+{
+ // --> OD 2009-01-29 #i98418#
+// SwFtnSave aFtnSave( rInf, pFtn );
+ SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
+ // <--
+ // the idx is manipulated in SwExpandPortion::Format
+ // this flag indicates, that a footnote is allowed to trigger
+ // an underflow during SwTxtGuess::Guess
+ rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
+ sal_Bool bFull = SwFldPortion::Format( rInf );
+ rInf.SetFakeLineStart( sal_False );
+ SetAscent( rInf.GetAscent() );
+ Height( rInf.GetTxtHeight() );
+ rInf.SetFtnDone( !bFull );
+ if( !bFull )
+ rInf.SetParaFtn();
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwFtnPortion::Paint()
+ *************************************************************************/
+
+void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // --> OD 2009-01-29 #i98418#
+// SwFtnSave aFtnSave( rInf, pFtn );
+ SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
+ // <--
+ rInf.DrawViewOpt( *this, POR_FTN );
+ SwExpandPortion::Paint( rInf );
+}
+
+/*************************************************************************
+ * virtual SwFtnPortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const
+{
+ // --> OD 2009-01-29 #i98418#
+// SwFtnSave aFtnSave( rInfo, pFtn );
+ SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
+ // <--
+ return SwExpandPortion::GetTxtSize( rInfo );
+}
+
+// --> OD 2009-01-29 #i98418#
+void SwFtnPortion::SetPreferredScriptType( BYTE nPreferredScriptType )
+{
+ mbPreferredScriptTypeSet = true;
+ mnPreferredScriptType = nPreferredScriptType;
+}
+// <--
+
+/*************************************************************************
+ * class SwQuoVadisPortion
+ *************************************************************************/
+
+SwFldPortion *SwQuoVadisPortion::Clone( const XubString &rExpand ) const
+{ return new SwQuoVadisPortion( rExpand, aErgo ); }
+
+SwQuoVadisPortion::SwQuoVadisPortion( const XubString &rExp, const XubString& rStr )
+ : SwFldPortion( rExp ), aErgo(rStr)
+{
+ SetLen(0);
+ SetWhichPor( POR_QUOVADIS );
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf )
+{
+ // erster Versuch, vielleicht passt der Text
+ CheckScript( rInf );
+ sal_Bool bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+
+ if( bFull )
+ {
+ // zweiter Versuch, wir kuerzen den String:
+ aExpand = XubString( "...", RTL_TEXTENCODING_MS_1252 );
+ bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+ if( bFull )
+ // dritter Versuch, es langt: jetzt wird gestaucht:
+ Width( USHORT(rInf.Width() - rInf.X()) );
+
+ // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
+ if( rInf.GetRest() )
+ {
+ delete rInf.GetRest();
+ rInf.SetRest( 0 );
+ }
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ // if this QuoVadisPortion has a follow, the follow is responsible for
+ // the ergo text.
+ if ( ! HasFollow() )
+ rTxt += aErgo;
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::HandlePortion()
+ *************************************************************************/
+
+void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ String aString( aExpand );
+ aString += aErgo;
+ rPH.Special( GetLen(), aString, GetWhichPor() );
+}
+
+/*************************************************************************
+ * virtual SwQuoVadisPortion::Paint()
+ *************************************************************************/
+
+void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ // Wir wollen _immer_ per DrawStretchText ausgeben,
+ // weil nErgo schnell mal wechseln kann.
+ if( PrtWidth() )
+ {
+ rInf.DrawViewOpt( *this, POR_QUOVADIS );
+ SwTxtSlot aDiffTxt( &rInf, this, true, false );
+ SwFontSave aSave( rInf, pFnt );
+ rInf.DrawText( *this, rInf.GetLen(), sal_True );
+ }
+}
+
+/*************************************************************************
+ * class SwErgoSumPortion
+ *************************************************************************/
+
+SwFldPortion *SwErgoSumPortion::Clone( const XubString &rExpand ) const
+{
+ UniString aTmp; // = UniString::CreateFromInt32( 0 );
+ return new SwErgoSumPortion( rExpand, aTmp );
+}
+
+SwErgoSumPortion::SwErgoSumPortion( const XubString &rExp, const XubString& rStr )
+ : SwFldPortion( rExp )
+{
+ SetLen(0);
+ aExpand += rStr;
+
+ // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text
+ aExpand += ' ';
+ SetWhichPor( POR_ERGOSUM );
+}
+
+xub_StrLen SwErgoSumPortion::GetCrsrOfst( const KSHORT ) const
+{
+ return 0;
+}
+
+/*************************************************************************
+ * virtual SwErgoSumPortion::Format()
+ *************************************************************************/
+
+sal_Bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_Bool bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+ rInf.SetErgoDone( sal_True );
+
+ // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
+ if( bFull && rInf.GetRest() )
+ {
+ delete rInf.GetRest();
+ rInf.SetRest( 0 );
+ }
+
+ // We return false in order to get some text into the current line,
+ // even if it's full (better than looping)
+ return sal_False;
+}
+
+
+/*************************************************************************
+ * SwParaPortion::SetErgoSumNum()
+ *************************************************************************/
+
+void SwParaPortion::SetErgoSumNum( const XubString& rErgo )
+{
+ SwLineLayout *pLay = this;
+ while( pLay->GetNext() )
+ {
+ DBG_LOOP;
+ pLay = pLay->GetNext();
+ }
+ SwLinePortion *pPor = pLay;
+ SwQuoVadisPortion *pQuo = 0;
+ while( pPor && !pQuo )
+ {
+ if ( pPor->IsQuoVadisPortion() )
+ pQuo = (SwQuoVadisPortion*)pPor;
+ pPor = pPor->GetPortion();
+ }
+ if( pQuo )
+ pQuo->SetNumber( rErgo );
+}
+
+/*************************************************************************
+ * SwParaPortion::UpdateQuoVadis()
+ *
+ * Wird im SwTxtFrm::Prepare() gerufen
+ *************************************************************************/
+
+sal_Bool SwParaPortion::UpdateQuoVadis( const XubString &rQuo )
+{
+ SwLineLayout *pLay = this;
+ while( pLay->GetNext() )
+ {
+ DBG_LOOP;
+ pLay = pLay->GetNext();
+ }
+ SwLinePortion *pPor = pLay;
+ SwQuoVadisPortion *pQuo = 0;
+ while( pPor && !pQuo )
+ {
+ if ( pPor->IsQuoVadisPortion() )
+ pQuo = (SwQuoVadisPortion*)pPor;
+ pPor = pPor->GetPortion();
+ }
+
+ if( !pQuo )
+ return sal_False;
+
+ return pQuo->GetQuoTxt() == rQuo;
+}
+
+
+