blob: 78df43ba353fd9292354d36f45268939ad214770 [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 "swrect.hxx"
#include "paratr.hxx" // pTabStop, ADJ*
#include "viewopt.hxx" // SwViewOptions
#include "errhdl.hxx" // ASSERT
#include <SwPortionHandler.hxx>
#include "txtcfg.hxx"
#include "porglue.hxx"
#include "inftxt.hxx"
#include "porlay.hxx" // SwParaPortion, SetFull
#include "porfly.hxx" // SwParaPortion, SetFull
/*************************************************************************
* class SwGluePortion
*************************************************************************/
SwGluePortion::SwGluePortion( const KSHORT nInitFixWidth )
: nFixWidth( nInitFixWidth )
{
PrtWidth( nFixWidth );
SetWhichPor( POR_GLUE );
}
/*************************************************************************
* virtual SwGluePortion::GetCrsrOfst()
*************************************************************************/
xub_StrLen SwGluePortion::GetCrsrOfst( const KSHORT nOfst ) const
{
if( !GetLen() || nOfst > GetLen() || !Width() )
return SwLinePortion::GetCrsrOfst( nOfst );
else
return nOfst / (Width() / GetLen());
}
/*************************************************************************
* virtual SwGluePortion::GetTxtSize()
*************************************************************************/
SwPosSize SwGluePortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
{
if( 1 >= GetLen() || rInf.GetLen() > GetLen() || !Width() || !GetLen() )
return SwPosSize(*this);
else
return SwPosSize( (Width() / GetLen()) * rInf.GetLen(), Height() );
}
/*************************************************************************
* virtual SwGluePortion::GetExpTxt()
*************************************************************************/
sal_Bool SwGluePortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
{
if( GetLen() && rInf.OnWin() &&
rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() )
{
rTxt.Fill( GetLen(), CH_BULLET );
return sal_True;
}
return sal_False;
}
/*************************************************************************
* virtual SwGluePortion::Paint()
*************************************************************************/
void SwGluePortion::Paint( const SwTxtPaintInfo &rInf ) const
{
if( !GetLen() )
return;
if( rInf.GetFont()->IsPaintBlank() )
{
XubString aTxt;
aTxt.Fill( GetFixWidth() / GetLen(), ' ' );
SwTxtPaintInfo aInf( rInf, aTxt );
aInf.DrawText( *this, aTxt.Len(), sal_True );
}
if( rInf.OnWin() && rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() )
{
#ifdef DBG_UTIL
const xub_Unicode cChar = rInf.GetChar( rInf.GetIdx() );
ASSERT( CH_BLANK == cChar || CH_BULLET == cChar,
"SwGluePortion::Paint: blank expected" );
#endif
if( 1 == GetLen() )
{
String aBullet( CH_BULLET );
SwPosSize aBulletSize( rInf.GetTxtSize( aBullet ) );
Point aPos( rInf.GetPos() );
aPos.X() += (Width()/2) - (aBulletSize.Width()/2);
SwTxtPaintInfo aInf( rInf, aBullet );
aInf.SetPos( aPos );
SwTxtPortion aBulletPor;
aBulletPor.Width( aBulletSize.Width() );
aBulletPor.Height( aBulletSize.Height() );
aBulletPor.SetAscent( GetAscent() );
aInf.DrawText( aBulletPor, aBullet.Len(), sal_True );
}
else
{
SwTxtSlot aSlot( &rInf, this, true, false );
rInf.DrawText( *this, rInf.GetLen(), sal_True );
}
}
}
/*************************************************************************
* SwGluePortion::MoveGlue()
*************************************************************************/
void SwGluePortion::MoveGlue( SwGluePortion *pTarget, const short nPrtGlue )
{
short nPrt = Min( nPrtGlue, GetPrtGlue() );
if( 0 < nPrt )
{
pTarget->AddPrtWidth( nPrt );
SubPrtWidth( nPrt );
}
}
/*************************************************************************
* void SwGluePortion::Join()
*************************************************************************/
void SwGluePortion::Join( SwGluePortion *pVictim )
{
// Die GluePortion wird ausgesogen und weggespuelt ...
AddPrtWidth( pVictim->PrtWidth() );
SetLen( pVictim->GetLen() + GetLen() );
if( Height() < pVictim->Height() )
Height( pVictim->Height() );
AdjFixWidth();
Cut( pVictim );
delete pVictim;
}
/*************************************************************************
* class SwFixPortion
*************************************************************************/
// Wir erwarten ein framelokales SwRect !
SwFixPortion::SwFixPortion( const SwRect &rRect )
:SwGluePortion( KSHORT(rRect.Width()) ), nFix( KSHORT(rRect.Left()) )
{
Height( KSHORT(rRect.Height()) );
SetWhichPor( POR_FIX );
}
SwFixPortion::SwFixPortion(const KSHORT nFixedWidth, const KSHORT nFixedPos)
: SwGluePortion(nFixedWidth), nFix(nFixedPos)
{
SetWhichPor( POR_FIX );
}
/*************************************************************************
* class SwMarginPortion
*************************************************************************/
SwMarginPortion::SwMarginPortion( const KSHORT nFixedWidth )
:SwGluePortion( nFixedWidth )
{
SetWhichPor( POR_MARGIN );
}
/*************************************************************************
* SwMarginPortion::AdjustRight()
*
* In der umschliessenden Schleife werden alle Portions durchsucht,
* dabei werden erst die am Ende liegenden GluePortions verarbeitet.
* Das Ende wird nach jeder Schleife nach vorne verlegt, bis keine
* GluePortions mehr vorhanden sind.
* Es werden immer GluePortion-Paare betrachtet (pLeft und pRight),
* wobei Textportions zwischen pLeft und pRight hinter pRight verschoben
* werden, wenn pRight genuegend Glue besitzt. Bei jeder Verschiebung
* wandert ein Teil des Glues von pRight nach pLeft.
* Im naechsten Schleifendurchlauf ist pLeft das pRight und das Spiel
* beginnt von vorne.
*************************************************************************/
void SwMarginPortion::AdjustRight( const SwLineLayout *pCurr )
{
SwGluePortion *pRight = 0;
sal_Bool bNoMove = 0 != pCurr->GetpKanaComp();
while( pRight != this )
{
// 1) Wir suchen den linken Glue
SwLinePortion *pPos = (SwLinePortion*)this;
SwGluePortion *pLeft = 0;
while( pPos )
{
DBG_LOOP;
if( pPos->InFixMargGrp() )
pLeft = (SwGluePortion*)pPos;
pPos = pPos->GetPortion();
if( pPos == pRight)
pPos = 0;
}
// Zwei nebeneinander liegende FlyPortions verschmelzen
if( pRight && pLeft->GetPortion() == pRight )
{
pRight->MoveAllGlue( pLeft );
pRight = 0;
}
KSHORT nRightGlue = pRight && 0 < pRight->GetPrtGlue()
? KSHORT(pRight->GetPrtGlue()) : 0;
// 2) linken und rechten Glue ausgleichen
// Bei Tabs haengen wir nix um ...
if( pLeft && nRightGlue && !pRight->InTabGrp() )
{
// pPrev ist die Portion, die unmittelbar vor pRight liegt.
SwLinePortion *pPrev = pRight->FindPrevPortion( pLeft );
if ( pRight->IsFlyPortion() && pRight->GetLen() )
{
SwFlyPortion *pFly = (SwFlyPortion *)pRight;
if ( pFly->GetBlankWidth() < nRightGlue )
{
// Hier entsteht eine neue TxtPortion, die dass zuvor
// vom Fly verschluckte Blank reaktiviert.
nRightGlue = nRightGlue - pFly->GetBlankWidth();
pFly->SubPrtWidth( pFly->GetBlankWidth() );
pFly->SetLen( 0 );
SwTxtPortion *pNewPor = new SwTxtPortion;
pNewPor->SetLen( 1 );
pNewPor->Height( pFly->Height() );
pNewPor->Width( pFly->GetBlankWidth() );
pFly->Insert( pNewPor );
}
else
pPrev = pLeft;
}
while( pPrev != pLeft )
{
DBG_LOOP;
if( bNoMove || pPrev->PrtWidth() >= nRightGlue ||
pPrev->InHyphGrp() || pPrev->IsKernPortion() )
{
// Die Portion, die vor pRight liegt kann nicht
// verschoben werden, weil kein Glue mehr vorhanden ist.
// Wir fuehren die Abbruchbedingung herbei:
pPrev = pLeft;
}
else
{
nRightGlue = nRightGlue - pPrev->PrtWidth();
// pPrev wird hinter pRight verschoben.
// Dazu wird der Gluewert zwischen pRight und pLeft
// ausgeglichen.
pRight->MoveGlue( pLeft, short( pPrev->PrtWidth() ) );
// Jetzt wird die Verkettung gerichtet.
SwLinePortion *pPrevPrev = pPrev->FindPrevPortion( pLeft );
pPrevPrev->SetPortion( pRight );
pPrev->SetPortion( pRight->GetPortion() );
pRight->SetPortion( pPrev );
if ( pPrev->GetPortion() && pPrev->InTxtGrp()
&& pPrev->GetPortion()->IsHolePortion() )
{
SwHolePortion *pHolePor =
(SwHolePortion*)pPrev->GetPortion();
if ( !pHolePor->GetPortion() ||
!pHolePor->GetPortion()->InFixMargGrp() )
{
pPrev->AddPrtWidth( pHolePor->GetBlankWidth() );
pPrev->SetLen( pPrev->GetLen() + 1 );
pPrev->SetPortion( pHolePor->GetPortion() );
delete pHolePor;
}
}
pPrev = pPrevPrev;
}
}
}
// Wenn es keinen linken Glue mehr gibt, wird die Abbruchbedingung
// herbeigefuehrt.
pRight = pLeft ? pLeft : (SwGluePortion*)this;
}
}