Files
libreoffice/sw/source/core/text/txtftn.cxx
Andrea Gelmini ca9de688c2 Fix typos
Change-Id: I549635318f46718042e50c8f89ce3c620cade990
Reviewed-on: https://gerrit.libreoffice.org/16281
Reviewed-by: Michael Stahl <mstahl@redhat.com>
Tested-by: Michael Stahl <mstahl@redhat.com>
2015-06-16 11:10:51 +00:00

1531 lines
51 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
#include "viewsh.hxx"
#include "doc.hxx"
#include <IDocumentLayoutAccess.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/brushitem.hxx>
#include <editeng/charrotateitem.hxx>
#include <breakit.hxx>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <tabfrm.hxx>
#include <sortedobjs.hxx>
#include "swfont.hxx"
#include "porftn.hxx"
#include "porfly.hxx"
#include "porlay.hxx"
#include "txtfrm.hxx"
#include "itrform2.hxx"
#include "ftnfrm.hxx"
#include "pagedesc.hxx"
#include "redlnitr.hxx"
#include "sectfrm.hxx"
#include "layouter.hxx"
#include "frmtool.hxx"
#include "ndindex.hxx"
using namespace ::com::sun::star;
bool SwTextFrm::_IsFootnoteNumFrm() const
{
const SwFootnoteFrm* pFootnote = FindFootnoteFrm()->GetMaster();
while( pFootnote && !pFootnote->ContainsContent() )
pFootnote = pFootnote->GetMaster();
return !pFootnote;
}
/**
* Looks for the TextFrm matching the SwTextFootnote within a master-follow chain
*/
SwTextFrm *SwTextFrm::FindFootnoteRef( const SwTextFootnote *pFootnote )
{
SwTextFrm *pFrm = this;
const bool bFwd = pFootnote->GetStart() >= GetOfst();
while( pFrm )
{
if( SwFootnoteBossFrm::FindFootnote( pFrm, pFootnote ) )
return pFrm;
pFrm = bFwd ? pFrm->GetFollow() :
pFrm->IsFollow() ? pFrm->FindMaster() : 0;
}
return pFrm;
}
#ifdef DBG_UTIL
void SwTextFrm::CalcFootnoteFlag( sal_Int32 nStop )// For testing the SplitFrm
#else
void SwTextFrm::CalcFootnoteFlag()
#endif
{
bFootnote = false;
const SwpHints *pHints = GetTextNode()->GetpSwpHints();
if( !pHints )
return;
const size_t nSize = pHints->Count();
#ifdef DBG_UTIL
const sal_Int32 nEnd = nStop != COMPLETE_STRING ? nStop
: GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
#else
const sal_Int32 nEnd = GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
#endif
for ( size_t i = 0; i < nSize; ++i )
{
const SwTextAttr *pHt = (*pHints)[i];
if ( pHt->Which() == RES_TXTATR_FTN )
{
const sal_Int32 nIdx = pHt->GetStart();
if ( nEnd < nIdx )
break;
if( GetOfst() <= nIdx )
{
bFootnote = true;
break;
}
}
}
}
bool SwTextFrm::CalcPrepFootnoteAdjust()
{
OSL_ENSURE( HasFootnote(), "Who´s calling me?" );
SwFootnoteBossFrm *pBoss = FindFootnoteBossFrm( true );
const SwFootnoteFrm *pFootnote = pBoss->FindFirstFootnote( this );
if( pFootnote && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFootnoteInfo().ePos &&
( !pBoss->GetUpper()->IsSctFrm() ||
!static_cast<SwSectionFrm*>(pBoss->GetUpper())->IsFootnoteAtEnd() ) )
{
const SwFootnoteContFrm *pCont = pBoss->FindFootnoteCont();
bool bReArrange = true;
SWRECTFN( this )
if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
(Frm().*fnRect->fnGetBottom)() ) > 0 )
{
pBoss->RearrangeFootnotes( (Frm().*fnRect->fnGetBottom)(), false,
pFootnote->GetAttr() );
ValidateBodyFrm();
ValidateFrm();
pFootnote = pBoss->FindFirstFootnote( this );
}
else
bReArrange = false;
if( !pCont || !pFootnote || bReArrange != (pFootnote->FindFootnoteBossFrm() == pBoss) )
{
SwTextFormatInfo aInf( this );
SwTextFormatter aLine( this, &aInf );
aLine.TruncLines();
SetPara( 0 ); // May be deleted!
ResetPreps();
return false;
}
}
return true;
}
/**
* Local helper function. Checks if nLower should be taken as the boundary
* for the footnote.
*/
static SwTwips lcl_GetFootnoteLower( const SwTextFrm* pFrm, SwTwips nLower )
{
// nLower is an absolute value. It denotes the bottom of the line
// containing the footnote.
SWRECTFN( pFrm )
OSL_ENSURE( !pFrm->IsVertical() || !pFrm->IsSwapped(),
"lcl_GetFootnoteLower 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::FindFootnoteBossFrm. 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 = static_cast<const SwTabFrm*>(pRow->GetUpper());
OSL_ENSURE( 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 ( !static_cast<const 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();
OSL_ENSURE( pStartFrm, "Upper has no lower" );
SwTwips nFlyLower = bVert ? LONG_MAX : 0;
while ( pStartFrm != pFrm )
{
OSL_ENSURE( pStartFrm, "Frame chain is broken" );
if ( pStartFrm->GetDrawObjs() )
{
const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
for ( size_t i = 0; i < rObjs.size(); ++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 = std::min( nRet, nFlyLower );
else
nRet = std::max( nRet, nFlyLower );
return nRet;
}
SwTwips SwTextFrm::GetFootnoteLine( const SwTextFootnote *pFootnote ) const
{
OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
"SwTextFrm::GetFootnoteLine with swapped frame" );
SwTextFrm *pThis = const_cast<SwTextFrm*>(this);
if( !HasPara() )
{
// #109071# GetFormatted() does not work here, because most probably
// the frame is currently locked. We return the previous value.
return pThis->mnFootnoteLine > 0 ?
pThis->mnFootnoteLine :
IsVertical() ? Frm().Left() : Frm().Bottom();
}
SwTwips nRet;
{
SWAP_IF_NOT_SWAPPED swap(const_cast<SwTextFrm *>(this));
SwTextInfo aInf( pThis );
SwTextIter aLine( pThis, &aInf );
const sal_Int32 nPos = pFootnote->GetStart();
aLine.CharToLine( nPos );
nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
if( IsVertical() )
nRet = SwitchHorizontalToVertical( nRet );
}
nRet = lcl_GetFootnoteLower( pThis, nRet );
pThis->mnFootnoteLine = nRet;
return nRet;
}
/**
* Calculates the maximum reachable height for the TextFrm in the Footnote Area.
* The cell's bottom margin with the Footnote Reference limit's this height.
*/
SwTwips SwTextFrm::_GetFootnoteFrmHeight() const
{
OSL_ENSURE( !IsFollow() && IsInFootnote(), "SwTextFrm::SetFootnoteLine: moon walk" );
const SwFootnoteFrm *pFootnoteFrm = FindFootnoteFrm();
const SwTextFrm *pRef = static_cast<const SwTextFrm *>(pFootnoteFrm->GetRef());
const SwFootnoteBossFrm *pBoss = FindFootnoteBossFrm();
if( pBoss != pRef->FindFootnoteBossFrm( !pFootnoteFrm->GetAttr()->
GetFootnote().IsEndNote() ) )
return 0;
SWAP_IF_SWAPPED swap(const_cast<SwTextFrm *>(this));
SwTwips nHeight = pRef->IsInFootnoteConnect() ?
1 : pRef->GetFootnoteLine( pFootnoteFrm->GetAttr() );
if( nHeight )
{
// As odd as it may seem: the first Footnote on the page may not touch the
// Footnote Reference, when entering text in the Footnote Area.
const SwFrm *pCont = pFootnoteFrm->GetUpper();
// Height within the Container which we're allowed to consume anyways
SWRECTFN( pCont )
SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
(Frm().*fnRect->fnGetTop)() );
#if OSL_DEBUG_LEVEL > 0
if( nTmp < 0 )
{
bool bInvalidPos = false;
const SwLayoutFrm* pTmp = GetUpper();
while( !bInvalidPos && pTmp )
{
bInvalidPos = !pTmp->GetValidPosFlag() ||
!pTmp->Lower()->GetValidPosFlag();
if( pTmp == pCont )
break;
pTmp = pTmp->GetUpper();
}
OSL_ENSURE( bInvalidPos, "Hanging below FootnoteCont" );
}
#endif
if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
{
// Growth potential of the container
if ( !pRef->IsInFootnoteConnect() )
{
SwSaveFootnoteHeight aSave( const_cast<SwFootnoteBossFrm*>(pBoss), nHeight );
nHeight = const_cast<SwFootnoteContFrm*>(static_cast<const SwFootnoteContFrm*>(pCont))->Grow( LONG_MAX, true );
}
else
nHeight = const_cast<SwFootnoteContFrm*>(static_cast<const SwFootnoteContFrm*>(pCont))->Grow( LONG_MAX, 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;
}
}
return nHeight;
}
SwTextFrm *SwTextFrm::FindQuoVadisFrm()
{
// Check whether we're in a FootnoteFrm
if( GetIndPrev() || !IsInFootnote() )
return 0;
// To the preceding FootnoteFrm
SwFootnoteFrm *pFootnoteFrm = FindFootnoteFrm()->GetMaster();
if( !pFootnoteFrm )
return 0;
// Now the last Content
SwContentFrm *pCnt = pFootnoteFrm->ContainsContent();
if( !pCnt )
return NULL;
SwContentFrm *pLast;
do
{ pLast = pCnt;
pCnt = pCnt->GetNextContentFrm();
} while( pCnt && pFootnoteFrm->IsAnLower( pCnt ) );
return static_cast<SwTextFrm*>(pLast);
}
void SwTextFrm::RemoveFootnote( const sal_Int32 nStart, const sal_Int32 nLen )
{
if ( !IsFootnoteAllowed() )
return;
SwpHints *pHints = GetTextNode()->GetpSwpHints();
if( !pHints )
return;
bool bRollBack = nLen != COMPLETE_STRING;
const size_t nSize = pHints->Count();
sal_Int32 nEnd;
SwTextFrm* pSource;
if( bRollBack )
{
nEnd = nStart + nLen;
pSource = GetFollow();
if( !pSource )
return;
}
else
{
nEnd = COMPLETE_STRING;
pSource = this;
}
if( nSize )
{
SwPageFrm* pUpdate = NULL;
bool bRemove = false;
SwFootnoteBossFrm *pFootnoteBoss = 0;
SwFootnoteBossFrm *pEndBoss = 0;
bool bFootnoteEndDoc
= FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFootnoteInfo().ePos;
for ( size_t i = nSize; i; )
{
SwTextAttr *pHt = pHints->GetTextHint(--i);
if ( RES_TXTATR_FTN != pHt->Which() )
continue;
const sal_Int32 nIdx = pHt->GetStart();
if( nStart > nIdx )
break;
if( nEnd >= nIdx )
{
SwTextFootnote *pFootnote = static_cast<SwTextFootnote*>(pHt);
const bool bEndn = pFootnote->GetFootnote().IsEndNote();
if( bEndn )
{
if( !pEndBoss )
pEndBoss = pSource->FindFootnoteBossFrm();
}
else
{
if( !pFootnoteBoss )
{
pFootnoteBoss = pSource->FindFootnoteBossFrm( true );
if( pFootnoteBoss->GetUpper()->IsSctFrm() )
{
SwSectionFrm* pSect = static_cast<SwSectionFrm*>(
pFootnoteBoss->GetUpper());
if( pSect->IsFootnoteAtEnd() )
bFootnoteEndDoc = false;
}
}
}
// We don't delete, but move instead.
// Three cases are to be considered:
// 1) There's neither Follow nor PrevFollow:
// -> RemoveFootnote() (maybe even a OSL_ENSURE(value))
//
// 2) nStart > GetOfst, I have a Follow
// -> Footnote moves into Follow
//
// 3) nStart < GetOfst, I am a Follow
// -> Footnote moves into the PrevFollow
//
// Both need to be on one Page/in one Column
SwFootnoteFrm *pFootnoteFrm = SwFootnoteBossFrm::FindFootnote(pSource, pFootnote);
if( pFootnoteFrm )
{
const bool bEndDoc = bEndn || bFootnoteEndDoc;
if( bRollBack )
{
while ( pFootnoteFrm )
{
pFootnoteFrm->SetRef( this );
pFootnoteFrm = pFootnoteFrm->GetFollow();
SetFootnote( true );
}
}
else if( GetFollow() )
{
SwContentFrm *pDest = GetFollow();
while( pDest->GetFollow() && static_cast<SwTextFrm*>(pDest->
GetFollow())->GetOfst() <= nIdx )
pDest = pDest->GetFollow();
OSL_ENSURE( !SwFootnoteBossFrm::FindFootnote(
pDest,pFootnote),"SwTextFrm::RemoveFootnote: footnote exists");
// Never deregister; always move
if ( bEndDoc ||
!pFootnoteFrm->FindFootnoteBossFrm()->IsBefore( pDest->FindFootnoteBossFrm( !bEndn ) )
)
{
SwPageFrm* pTmp = pFootnoteFrm->FindPageFrm();
if( pUpdate && pUpdate != pTmp )
pUpdate->UpdateFootnoteNum();
pUpdate = pTmp;
while ( pFootnoteFrm )
{
pFootnoteFrm->SetRef( pDest );
pFootnoteFrm = pFootnoteFrm->GetFollow();
}
}
else
{
pFootnoteBoss->MoveFootnotes( this, pDest, pFootnote );
bRemove = true;
}
static_cast<SwTextFrm*>(pDest)->SetFootnote( true );
OSL_ENSURE( SwFootnoteBossFrm::FindFootnote( pDest,
pFootnote),"SwTextFrm::RemoveFootnote: footnote ChgRef failed");
}
else
{
if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
!SwLayouter::Collecting( GetNode()->GetDoc(),
pEndBoss->FindSctFrm(), NULL ) ) )
{
if( bEndn )
pEndBoss->RemoveFootnote( this, pFootnote );
else
pFootnoteBoss->RemoveFootnote( this, pFootnote );
bRemove = bRemove || !bEndDoc;
OSL_ENSURE( !SwFootnoteBossFrm::FindFootnote( this, pFootnote ),
"SwTextFrm::RemoveFootnote: can't get off that footnote" );
}
}
}
}
}
if( pUpdate )
pUpdate->UpdateFootnoteNum();
// We brake the oscillation
if( bRemove && !bFootnoteEndDoc && HasPara() )
{
ValidateBodyFrm();
ValidateFrm();
}
}
// We call the RemoveFootnote from within the FindBreak, because the last line is
// to be passed to the Follow. The Offset of the Follow is, however, outdated;
// it'll be set soon. CalcFntFlag depends on a correctly set Follow Offset.
// Therefore we temporarily calculate the Follow Offset here
sal_Int32 nOldOfst = COMPLETE_STRING;
if( HasFollow() && nStart > GetOfst() )
{
nOldOfst = GetFollow()->GetOfst();
GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
}
pSource->CalcFootnoteFlag();
if( nOldOfst < COMPLETE_STRING )
GetFollow()->ManipOfst( nOldOfst );
}
/**
* We basically only have two possibilities:
*
* a) The Footnote is already present
* => we move it, if another pSrcFrm has been found
*
* b) The Footnote is not present
* => we have it created for us
*
* Whether the Footnote ends up on our Page/Column, doesn't matter in this
* context.
*
* Optimization for Endnotes.
*
* Another problem: if the Deadline falls within the Footnote Area, we need
* to move the Footnote.
*
* @returns false on any type of error
*/
void SwTextFrm::ConnectFootnote( SwTextFootnote *pFootnote, const SwTwips nDeadLine )
{
OSL_ENSURE( !IsVertical() || !IsSwapped(),
"SwTextFrm::ConnectFootnote with swapped frame" );
bFootnote = true;
bInFootnoteConnect = true; // Just reset!
const bool bEnd = pFootnote->GetFootnote().IsEndNote();
// We want to store this value, because it is needed as a fallback
// in GetFootnoteLine(), if there is no paragraph information available
mnFootnoteLine = nDeadLine;
// We always need a parent (Page/Column)
SwSectionFrm *pSect;
SwContentFrm *pContent = this;
if( bEnd && IsInSct() )
{
pSect = FindSctFrm();
if( pSect->IsEndnAtEnd() )
pContent = pSect->FindLastContent( FINDMODE_ENDNOTE );
if( !pContent )
pContent = this;
}
SwFootnoteBossFrm *pBoss = pContent->FindFootnoteBossFrm( !bEnd );
#if OSL_DEBUG_LEVEL > 1
SwTwips nRstHeight = GetRstHeight();
#endif
pSect = pBoss->FindSctFrm();
bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
( !( pSect && pSect->IsFootnoteAtEnd() ) &&
FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFootnoteInfo().ePos );
// Footnote can be registered with the Follow
SwContentFrm *pSrcFrm = FindFootnoteRef( pFootnote );
if( bDocEnd )
{
if( pSect && pSrcFrm )
{
SwFootnoteFrm *pFootnoteFrm = SwFootnoteBossFrm::FindFootnote( pSrcFrm, pFootnote );
if( pFootnoteFrm && pFootnoteFrm->IsInSct() )
{
pBoss->RemoveFootnote( pSrcFrm, pFootnote );
pSrcFrm = 0;
}
}
}
else if( bEnd && pSect )
{
SwFootnoteFrm *pFootnoteFrm = pSrcFrm ? SwFootnoteBossFrm::FindFootnote( pSrcFrm, pFootnote ) : NULL;
if( pFootnoteFrm && !pFootnoteFrm->GetUpper() )
pFootnoteFrm = NULL;
SwDoc *pDoc = GetNode()->GetDoc();
if( SwLayouter::Collecting( pDoc, pSect, pFootnoteFrm ) )
{
if( !pSrcFrm )
{
SwFootnoteFrm *pNew = new SwFootnoteFrm(pDoc->GetDfltFrameFormat(),this,this,pFootnote);
SwNodeIndex aIdx( *pFootnote->GetStartNode(), 1 );
::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
}
else if( pSrcFrm != this )
SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
bInFootnoteConnect = false;
return;
}
else if( pSrcFrm )
{
SwFootnoteBossFrm *pFootnoteBoss = pFootnoteFrm->FindFootnoteBossFrm();
if( !pFootnoteBoss->IsInSct() ||
pFootnoteBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
{
pBoss->RemoveFootnote( pSrcFrm, pFootnote );
pSrcFrm = 0;
}
}
}
if( bDocEnd || bEnd )
{
if( !pSrcFrm )
pBoss->AppendFootnote( this, pFootnote );
else if( pSrcFrm != this )
SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
bInFootnoteConnect = false;
return;
}
SwSaveFootnoteHeight aHeight( pBoss, nDeadLine );
if( !pSrcFrm ) // No Footnote was found at all
pBoss->AppendFootnote( this, pFootnote );
else
{
SwFootnoteFrm *pFootnoteFrm = SwFootnoteBossFrm::FindFootnote( pSrcFrm, pFootnote );
SwFootnoteBossFrm *pFootnoteBoss = pFootnoteFrm->FindFootnoteBossFrm();
bool bBrutal = false;
if( pFootnoteBoss == pBoss ) // Ref and Footnote are on the same Page/Column
{
SwFrm *pCont = pFootnoteFrm->GetUpper();
SWRECTFN ( pCont )
long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
nDeadLine );
if( nDiff >= 0 )
{
// If the Footnote has been registered to a Follow, we need to
// rewire it now too
if ( pSrcFrm != this )
SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
// We have some room left, so the Footnote can grow
if ( pFootnoteFrm->GetFollow() && nDiff > 0 )
{
SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
pBoss->RearrangeFootnotes( nDeadLine, false, pFootnote );
ValidateBodyFrm();
ValidateFrm();
SwViewShell *pSh = getRootFrm()->GetCurrShell();
if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
// So that we don't miss anything
pSh->InvalidateWindows( pCont->Frm() );
}
bInFootnoteConnect = false;
return;
}
else
bBrutal = true;
}
else
{
// Ref and Footnote are not on one Page; attempt to move is necessary
SwFrm* pTmp = this;
while( pTmp->GetNext() && pSrcFrm != pTmp )
pTmp = pTmp->GetNext();
if( pSrcFrm == pTmp )
bBrutal = true;
else
{ // If our Parent is in a column Area, but the Page already has a
// FootnoteContainer, we can only brute force it
if( pSect && pSect->FindFootnoteBossFrm( !bEnd )->FindFootnoteCont() )
bBrutal = true;
else if ( !pFootnoteFrm->GetPrev() ||
pFootnoteBoss->IsBefore( pBoss )
)
{
SwFootnoteBossFrm *pSrcBoss = pSrcFrm->FindFootnoteBossFrm( !bEnd );
pSrcBoss->MoveFootnotes( pSrcFrm, this, pFootnote );
}
else
SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
}
}
// The brute force method: Remove Footnote and append.
// We need to call SetFootnoteDeadLine(), as we can more easily adapt the
// nMaxFootnoteHeight after RemoveFootnote
if( bBrutal )
{
pBoss->RemoveFootnote( pSrcFrm, pFootnote, false );
SwSaveFootnoteHeight *pHeight = bEnd ? NULL : new SwSaveFootnoteHeight( pBoss, nDeadLine );
pBoss->AppendFootnote( this, pFootnote );
delete pHeight;
}
}
// In column Areas, that not yet reach the Page's border a RearrangeFootnotes is not
// useful yet, as the Footnote container has not yet been calculated
if( !pSect || !pSect->Growable() )
{
// Validate environment, to avoid oscillation
SwSaveFootnoteHeight aNochmal( pBoss, nDeadLine );
ValidateBodyFrm();
pBoss->RearrangeFootnotes( nDeadLine, true );
ValidateFrm();
}
else if( pSect->IsFootnoteAtEnd() )
{
ValidateBodyFrm();
ValidateFrm();
}
#if OSL_DEBUG_LEVEL > 1
// pFootnoteFrm may have changed due to Calc ...
SwFootnoteFrm *pFootnoteFrm = pBoss->FindFootnote( this, pFootnote );
if( pFootnoteFrm && pBoss != pFootnoteFrm->FindFootnoteBossFrm( !bEnd ) )
{
int bla = 5;
(void)bla;
}
nRstHeight = GetRstHeight();
(void)nRstHeight;
#endif
bInFootnoteConnect = false;
return;
}
/**
* The portion for the Footnote Reference in the Text
*/
SwFootnotePortion *SwTextFormatter::NewFootnotePortion( SwTextFormatInfo &rInf,
SwTextAttr *pHint )
{
OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
"NewFootnotePortion with unswapped frame" );
if( !pFrm->IsFootnoteAllowed() )
return 0;
SwTextFootnote *pFootnote = static_cast<SwTextFootnote*>(pHint);
const SwFormatFootnote& rFootnote = static_cast<const SwFormatFootnote&>(pFootnote->GetFootnote());
SwDoc *pDoc = pFrm->GetNode()->GetDoc();
if( rInf.IsTest() )
return new SwFootnotePortion( rFootnote.GetViewNumStr( *pDoc ), pFootnote );
SWAP_IF_SWAPPED swap(pFrm);
sal_uInt16 nReal;
{
sal_uInt16 nOldReal = pCurr->GetRealHeight();
sal_uInt16 nOldAscent = pCurr->GetAscent();
sal_uInt16 nOldHeight = pCurr->Height();
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_GetFootnoteLower( pFrm, nLower );
// We just refresh.
// The Connect does not do anything useful in this case, but will
// mostly throw away the Footnote and create it anew.
if( !rInf.IsQuick() )
pFrm->ConnectFootnote( pFootnote, nLower );
SwTextFrm *pScrFrm = pFrm->FindFootnoteRef( pFootnote );
SwFootnoteBossFrm *pBoss = pFrm->FindFootnoteBossFrm( !rFootnote.IsEndNote() );
SwFootnoteFrm *pFootnoteFrm = NULL;
if( pScrFrm )
pFootnoteFrm = SwFootnoteBossFrm::FindFootnote( pScrFrm, pFootnote );
// We see whether our Append has caused some Footnote to
// still be on the Page/Column. If not, our line disappears too,
// which will lead to the following undesired behaviour:
// Footnote1 still fits onto the Page/Column, but Footnote2 doesn't.
// The Footnote2 Reference remains on the Page/Column. The Footnote itself
// is on the next Page/Column.
//
// Exception: If the Page/Column cannot accomodate another line,
// the Footnote Reference should be moved to the next one.
if( !rFootnote.IsEndNote() )
{
SwSectionFrm *pSct = pBoss->FindSctFrm();
bool bAtSctEnd = pSct && pSct->IsFootnoteAtEnd();
if( FTNPOS_CHAPTER != pDoc->GetFootnoteInfo().ePos || bAtSctEnd )
{
SwFrm* pFootnoteCont = pBoss->FindFootnoteCont();
// If the Parent is within an Area, it can only be a Column of this
// Area. If this one is not the first Column, we can avoid it.
if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
( !bAtSctEnd && pFrm->GetIndPrev() ) ||
( pSct && pBoss->GetPrev() ) ) )
{
if( !pFootnoteCont )
{
rInf.SetStop( true );
return 0;
}
else
{
// There must not be any Footnote Containers in column Areas and at the same time on the
// Page/Page column
if( pSct && !bAtSctEnd ) // Is the Container in a (column) Area?
{
SwFootnoteBossFrm* pTmp = pBoss->FindSctFrm()->FindFootnoteBossFrm( true );
SwFootnoteContFrm* pFootnoteC = pTmp->FindFootnoteCont();
if( pFootnoteC )
{
SwFootnoteFrm* pTmpFrm = static_cast<SwFootnoteFrm*>(pFootnoteC->Lower());
if( pTmpFrm && *pTmpFrm < pFootnote )
{
rInf.SetStop( true );
return 0;
}
}
}
// Is this the last Line that fits?
SwTwips nTmpBot = Y() + nReal * 2;
if( bVertical )
nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
SWRECTFN( pFootnoteCont )
const long nDiff = (*fnRect->fnYDiff)(
(pFootnoteCont->Frm().*fnRect->fnGetTop)(),
nTmpBot );
if( pScrFrm && nDiff < 0 )
{
if( pFootnoteFrm )
{
SwFootnoteBossFrm *pFootnoteBoss = pFootnoteFrm->FindFootnoteBossFrm();
if( pFootnoteBoss != pBoss )
{
// We're in the last Line and the Footnote has moved
// to another Page. We also want to be on that Page!
rInf.SetStop( true );
return 0;
}
}
}
}
}
}
}
// Finally: Create FootnotePortion and exit ...
SwFootnotePortion *pRet = new SwFootnotePortion( rFootnote.GetViewNumStr( *pDoc ),
pFootnote, nReal );
rInf.SetFootnoteInside( true );
return pRet;
}
/**
* The portion for the Footnote Numbering in the Footnote Area
*/
SwNumberPortion *SwTextFormatter::NewFootnoteNumPortion( SwTextFormatInfo &rInf ) const
{
OSL_ENSURE( pFrm->IsInFootnote() && !pFrm->GetIndPrev() && !rInf.IsFootnoteDone(),
"This is the wrong place for a ftnnumber" );
if( rInf.GetTextStart() != nStart ||
rInf.GetTextStart() != rInf.GetIdx() )
return 0;
const SwFootnoteFrm* pFootnoteFrm = pFrm->FindFootnoteFrm();
const SwTextFootnote* pFootnote = pFootnoteFrm->GetAttr();
// Aha! So we're in the Footnote Area!
SwFormatFootnote& rFootnote = (SwFormatFootnote&)pFootnote->GetFootnote();
SwDoc *pDoc = pFrm->GetNode()->GetDoc();
OUString aFootnoteText( rFootnote.GetViewNumStr( *pDoc, true ));
const SwEndNoteInfo* pInfo;
if( rFootnote.IsEndNote() )
pInfo = &pDoc->GetEndNoteInfo();
else
pInfo = &pDoc->GetFootnoteInfo();
const SwAttrSet& rSet = pInfo->GetCharFormat(*pDoc)->GetAttrSet();
const SwAttrSet* pParSet = &rInf.GetCharAttr();
const IDocumentSettingAccess* pIDSA = pFrm->GetTextNode()->getIDocumentSettingAccess();
SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
// #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 SwTextFormatter::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() );
SwFootnoteNumPortion* pNewPor = new SwFootnoteNumPortion( aFootnoteText, pNumFnt );
pNewPor->SetLeft( !pFrm->IsRightToLeft() );
return pNewPor;
}
OUString lcl_GetPageNumber( const SwPageFrm* pPage )
{
OSL_ENSURE( pPage, "GetPageNumber: Homeless TextFrm" );
const sal_uInt16 nVirtNum = pPage->GetVirtPageNum();
const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
return rNum.GetNumStr( nVirtNum );
}
SwErgoSumPortion *SwTextFormatter::NewErgoSumPortion( SwTextFormatInfo &rInf ) const
{
// We cannot assume we're a Follow
if( !pFrm->IsInFootnote() || pFrm->GetPrev() ||
rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
pFrm->ImplFindFootnoteFrm()->GetAttr()->GetFootnote().IsEndNote() )
return 0;
// Aha, wir sind also im Fussnotenbereich
const SwFootnoteInfo &rFootnoteInfo = pFrm->GetNode()->GetDoc()->GetFootnoteInfo();
SwTextFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
if( !pQuoFrm )
return 0;
const SwPageFrm* pPage = pFrm->FindPageFrm();
const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
if( pPage == pQuoFrm->FindPageFrm() )
return 0; // If the QuoVadis is on the same Column/Page
const OUString aPage = lcl_GetPageNumber( pPage );
SwParaPortion *pPara = pQuoFrm->GetPara();
if( pPara )
pPara->SetErgoSumNum( aPage );
if( rFootnoteInfo.aErgoSum.isEmpty() )
return 0;
SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFootnoteInfo.aErgoSum,
lcl_GetPageNumber( pQuoPage ) );
return pErgo;
}
sal_Int32 SwTextFormatter::FormatQuoVadis( const sal_Int32 nOffset )
{
OSL_ENSURE( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
"SwTextFormatter::FormatQuoVadis with swapped frame" );
if( !pFrm->IsInFootnote() || pFrm->ImplFindFootnoteFrm()->GetAttr()->GetFootnote().IsEndNote() )
return nOffset;
const SwFrm* pErgoFrm = pFrm->FindFootnoteFrm()->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; // If the ErgoSum is on the same Page
}
SwTextFormatInfo &rInf = GetInfo();
const SwFootnoteInfo &rFootnoteInfo = pFrm->GetNode()->GetDoc()->GetFootnoteInfo();
if( rFootnoteInfo.aQuoVadis.isEmpty() )
return nOffset;
// A remark on QuoVadis/ErgoSum:
// We use the Font set for the Paragraph for these texts.
// Thus, we initialze:
// TODO: ResetFont();
FeedInf( rInf );
SeekStartAndChg( rInf, true );
if( GetRedln() && pCurr->HasRedline() )
GetRedln()->Seek( *pFnt, nOffset, 0 );
// A tricky special case: Flyfrms extend into the Line and are at the
// position we want to insert the Quovadis text
// Let's see if it is that bad indeed:
SwLinePortion *pPor = pCurr->GetFirstPortion();
sal_uInt16 nLastLeft = 0;
while( pPor )
{
if ( pPor->IsFlyPortion() )
nLastLeft = static_cast<SwFlyPortion*>(pPor)->Fix() +
static_cast<SwFlyPortion*>(pPor)->Width();
pPor = pPor->GetPortion();
}
// The old game all over again: we want the Line to wrap around
// at a certain point, so we adjust the width.
// nLastLeft is now basically the right margin
const sal_uInt16 nOldRealWidth = rInf.RealWidth();
rInf.RealWidth( nOldRealWidth - nLastLeft );
OUString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFootnoteInfo.aQuoVadis, aErgo );
pQuo->SetAscent( rInf.GetAscent() );
pQuo->Height( rInf.GetTextHeight() );
pQuo->Format( rInf );
sal_uInt16 nQuoWidth = pQuo->Width();
SwLinePortion* pCurrPor = pQuo;
while ( rInf.GetRest() )
{
SwLinePortion* pFollow = rInf.GetRest();
rInf.SetRest( 0 );
pCurrPor->Move( rInf );
OSL_ENSURE( 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;
}
Right( Right() - nQuoWidth );
sal_Int32 nRet;
{
SWAP_IF_NOT_SWAPPED swap(pFrm);
nRet = FormatLine( nStart );
}
Right( rInf.Left() + nOldRealWidth - 1 );
nLastLeft = nOldRealWidth - pCurr->Width();
FeedInf( rInf );
// It's possible that there's a Margin Portion at the end, which would
// just cause a lot of trouble, when respanning
pPor = pCurr->FindLastPortion();
SwGluePortion *pGlue = pPor->IsMarginPortion() ? static_cast<SwMarginPortion*>(pPor) : 0;
if( pGlue )
{
pGlue->Height( 0 );
pGlue->Width( 0 );
pGlue->SetLen( 0 );
pGlue->SetAscent( 0 );
pGlue->SetPortion( NULL );
pGlue->SetFixWidth(0);
}
// Luxury: We make sure the QuoVadis text appears on the right, by
// using Glues.
nLastLeft = nLastLeft - nQuoWidth;
if( nLastLeft )
{
if( nLastLeft > pQuo->GetAscent() ) // Minimum distance
{
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();
}
}
// Finally: we insert the QuoVadis Portion
pCurrPor = pQuo;
while ( pCurrPor )
{
// pPor->Append deletes the pPortion pointer of pPor.
// Therefore we have to keep a pointer to the next portion
pQuo = static_cast<SwQuoVadisPortion*>(pCurrPor->GetPortion());
pPor->Append( pCurrPor );
pPor = pPor->GetPortion();
pCurrPor = pQuo;
}
pCurr->Width( pCurr->Width() + nQuoWidth );
// And adjust again, due to the adjustment and due to the following special
// case:
// The DummyUser has set a smaller Font in the Line than the one used
// by the QuoVadis text ...
CalcAdjustLine( pCurr );
return nRet;
}
/**
* This function creates a Line that reaches to the other Page Margin.
* DummyLines or DummyPortions make sure, that osicllations stop, because
* there's no way to flow back.
* They are used for Footnotes in paragraph-bound Frames and for Footnote
* oscillations
*/
void SwTextFormatter::MakeDummyLine()
{
sal_uInt16 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 SwFootnoteSave
{
SwTextSizeInfo *pInf;
SwFont *pFnt;
SwFont *pOld;
public:
SwFootnoteSave( const SwTextSizeInfo &rInf,
const SwTextFootnote *pTextFootnote,
const bool bApplyGivenScriptType,
const sal_uInt8 nGivenScriptType );
~SwFootnoteSave();
};
SwFootnoteSave::SwFootnoteSave( const SwTextSizeInfo &rInf,
const SwTextFootnote* pTextFootnote,
const bool bApplyGivenScriptType,
const sal_uInt8 nGivenScriptType )
: pInf( &((SwTextSizeInfo&)rInf) )
, pFnt( 0 )
, pOld( 0 )
{
if( pTextFootnote && rInf.GetTextFrm() )
{
pFnt = ((SwTextSizeInfo&)rInf).GetFont();
pOld = new SwFont( *pFnt );
pOld->GetTox() = pFnt->GetTox();
pFnt->GetTox() = 0;
SwFormatFootnote& rFootnote = (SwFormatFootnote&)pTextFootnote->GetFootnote();
const SwDoc *pDoc = rInf.GetTextFrm()->GetNode()->GetDoc();
// #i98418#
if ( bApplyGivenScriptType )
{
pFnt->SetActual( nGivenScriptType );
}
else
{
// examine text and set script
OUString aTmpStr( rFootnote.GetViewNumStr( *pDoc ) );
pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
}
const SwEndNoteInfo* pInfo;
if( rFootnote.IsEndNote() )
pInfo = &pDoc->GetEndNoteInfo();
else
pInfo = &pDoc->GetFootnoteInfo();
const SwAttrSet& rSet = pInfo->GetAnchorCharFormat((SwDoc&)*pDoc)->GetAttrSet();
pFnt->SetDiffFnt( &rSet, rInf.GetTextFrm()->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( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_ROTATE,
true, &pItem ))
pFnt->SetVertical( static_cast<const SvxCharRotateItem*>(pItem)->GetValue(),
rInf.GetTextFrm()->IsVertical() );
pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
true, &pItem ))
pFnt->SetBackColor( new Color( static_cast<const SvxBrushItem*>(pItem)->GetColor() ) );
}
else
pFnt = NULL;
}
SwFootnoteSave::~SwFootnoteSave()
{
if( pFnt )
{
// Put back SwFont
*pFnt = *pOld;
pFnt->GetTox() = pOld->GetTox();
pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
delete pOld;
}
}
SwFootnotePortion::SwFootnotePortion( const OUString &rExpand,
SwTextFootnote *pFootn, sal_uInt16 nReal )
: SwFieldPortion( rExpand, 0 )
, pFootnote(pFootn)
, nOrigHeight( nReal )
// #i98418#
, mbPreferredScriptTypeSet( false )
, mnPreferredScriptType( SW_LATIN )
{
SetLen(1);
SetWhichPor( POR_FTN );
}
bool SwFootnotePortion::GetExpText( const SwTextSizeInfo &, OUString &rText ) const
{
rText = aExpand;
return true;
}
bool SwFootnotePortion::Format( SwTextFormatInfo &rInf )
{
// #i98418#
// SwFootnoteSave aFootnoteSave( rInf, pFootnote );
SwFootnoteSave aFootnoteSave( rInf, pFootnote, mbPreferredScriptTypeSet, mnPreferredScriptType );
// the idx is manipulated in SwExpandPortion::Format
// this flag indicates, that a footnote is allowed to trigger
// an underflow during SwTextGuess::Guess
rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
const bool bFull = SwFieldPortion::Format( rInf );
rInf.SetFakeLineStart( false );
SetAscent( rInf.GetAscent() );
Height( rInf.GetTextHeight() );
rInf.SetFootnoteDone( !bFull );
if( !bFull )
rInf.SetParaFootnote();
return bFull;
}
void SwFootnotePortion::Paint( const SwTextPaintInfo &rInf ) const
{
// #i98418#
// SwFootnoteSave aFootnoteSave( rInf, pFootnote );
SwFootnoteSave aFootnoteSave( rInf, pFootnote, mbPreferredScriptTypeSet, mnPreferredScriptType );
rInf.DrawViewOpt( *this, POR_FTN );
SwExpandPortion::Paint( rInf );
}
SwPosSize SwFootnotePortion::GetTextSize( const SwTextSizeInfo &rInfo ) const
{
// #i98418#
// SwFootnoteSave aFootnoteSave( rInfo, pFootnote );
SwFootnoteSave aFootnoteSave( rInfo, pFootnote, mbPreferredScriptTypeSet, mnPreferredScriptType );
return SwExpandPortion::GetTextSize( rInfo );
}
// #i98418#
void SwFootnotePortion::SetPreferredScriptType( sal_uInt8 nPreferredScriptType )
{
mbPreferredScriptTypeSet = true;
mnPreferredScriptType = nPreferredScriptType;
}
SwFieldPortion *SwQuoVadisPortion::Clone( const OUString &rExpand ) const
{
return new SwQuoVadisPortion( rExpand, aErgo );
}
SwQuoVadisPortion::SwQuoVadisPortion( const OUString &rExp, const OUString& rStr )
: SwFieldPortion( rExp ), aErgo(rStr)
{
SetLen(0);
SetWhichPor( POR_QUOVADIS );
}
bool SwQuoVadisPortion::Format( SwTextFormatInfo &rInf )
{
// First try; maybe the Text fits
CheckScript( rInf );
bool bFull = SwFieldPortion::Format( rInf );
SetLen( 0 );
if( bFull )
{
// Second try; we make the String shorter
aExpand = "...";
bFull = SwFieldPortion::Format( rInf );
SetLen( 0 );
if( bFull )
// Third try; we're done: we crush
Width( sal_uInt16(rInf.Width() - rInf.X()) );
// No multiline Fields for QuoVadis and ErgoSum
if( rInf.GetRest() )
{
delete rInf.GetRest();
rInf.SetRest( 0 );
}
}
return bFull;
}
bool SwQuoVadisPortion::GetExpText( const SwTextSizeInfo &, OUString &rText ) const
{
rText = aExpand;
// if this QuoVadisPortion has a follow, the follow is responsible for
// the ergo text.
if ( ! HasFollow() )
rText += aErgo;
return true;
}
void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
{
rPH.Special( GetLen(), aExpand + aErgo, GetWhichPor() );
}
void SwQuoVadisPortion::Paint( const SwTextPaintInfo &rInf ) const
{
// We _always_ want to ouput per DrawStretchText, because nErgo
// can quickly switch
if( PrtWidth() )
{
rInf.DrawViewOpt( *this, POR_QUOVADIS );
SwTextSlot aDiffText( &rInf, this, true, false );
SwFontSave aSave( rInf, pFnt );
rInf.DrawText( *this, rInf.GetLen(), true );
}
}
SwFieldPortion *SwErgoSumPortion::Clone( const OUString &rExpand ) const
{
return new SwErgoSumPortion( rExpand, OUString() );
}
SwErgoSumPortion::SwErgoSumPortion(const OUString &rExp, const OUString& rStr)
: SwFieldPortion( rExp )
{
SetLen(0);
aExpand += rStr;
// One blank distance to the text
aExpand += " ";
SetWhichPor( POR_ERGOSUM );
}
sal_Int32 SwErgoSumPortion::GetCrsrOfst( const sal_uInt16 ) const
{
return 0;
}
bool SwErgoSumPortion::Format( SwTextFormatInfo &rInf )
{
const bool bFull = SwFieldPortion::Format( rInf );
SetLen( 0 );
rInf.SetErgoDone( true );
// No multiline Fields for QuoVadis and 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 false;
}
void SwParaPortion::SetErgoSumNum( const OUString& rErgo )
{
SwLineLayout *pLay = this;
while( pLay->GetNext() )
{
pLay = pLay->GetNext();
}
SwLinePortion *pPor = pLay;
SwQuoVadisPortion *pQuo = 0;
while( pPor && !pQuo )
{
if ( pPor->IsQuoVadisPortion() )
pQuo = static_cast<SwQuoVadisPortion*>(pPor);
pPor = pPor->GetPortion();
}
if( pQuo )
pQuo->SetNumber( rErgo );
}
/**
* Is called in SwTextFrm::Prepare()
*/
bool SwParaPortion::UpdateQuoVadis( const OUString &rQuo )
{
SwLineLayout *pLay = this;
while( pLay->GetNext() )
{
pLay = pLay->GetNext();
}
SwLinePortion *pPor = pLay;
SwQuoVadisPortion *pQuo = 0;
while( pPor && !pQuo )
{
if ( pPor->IsQuoVadisPortion() )
pQuo = static_cast<SwQuoVadisPortion*>(pPor);
pPor = pPor->GetPortion();
}
if( !pQuo )
return false;
return pQuo->GetQuoText() == rQuo;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */