blob: 471c4dfd60bf0103fd6e3552b25af7fce33aaa9c [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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 "rootfrm.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 sal_uInt16 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 ( 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( 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 sal_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 ( sal_uInt16 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;
sal_uInt16 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 ( sal_uInt16 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,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 = getRootFrm()->GetCurrShell();
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 );
sal_uInt16 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 = (sal_uInt16)(-nDiff + nLastLeft);
}
else
{
nQuoWidth = 0;
nLastLeft = sal_uInt16(( 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 sal_uInt8 nGivenScriptType );
~SwFtnSave();
};
/*************************************************************************
* SwFtnSave::SwFtnSave()
*************************************************************************/
SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf,
const SwTxtFtn* pTxtFtn,
const bool bApplyGivenScriptType,
const sal_uInt8 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( sal_uInt8 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( sal_uInt16(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;
}