1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 32 33 #include "swrect.hxx" 34 #include "paratr.hxx" // pTabStop, ADJ* 35 #include "viewopt.hxx" // SwViewOptions 36 #include "errhdl.hxx" // ASSERT 37 #include <SwPortionHandler.hxx> 38 39 #include "txtcfg.hxx" 40 #include "porglue.hxx" 41 #include "inftxt.hxx" 42 #include "porlay.hxx" // SwParaPortion, SetFull 43 #include "porfly.hxx" // SwParaPortion, SetFull 44 45 /************************************************************************* 46 * class SwGluePortion 47 *************************************************************************/ 48 49 SwGluePortion::SwGluePortion( const KSHORT nInitFixWidth ) 50 : nFixWidth( nInitFixWidth ) 51 { 52 PrtWidth( nFixWidth ); 53 SetWhichPor( POR_GLUE ); 54 } 55 56 /************************************************************************* 57 * virtual SwGluePortion::GetCrsrOfst() 58 *************************************************************************/ 59 60 xub_StrLen SwGluePortion::GetCrsrOfst( const KSHORT nOfst ) const 61 { 62 if( !GetLen() || nOfst > GetLen() || !Width() ) 63 return SwLinePortion::GetCrsrOfst( nOfst ); 64 else 65 return nOfst / (Width() / GetLen()); 66 } 67 68 /************************************************************************* 69 * virtual SwGluePortion::GetTxtSize() 70 *************************************************************************/ 71 72 SwPosSize SwGluePortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 73 { 74 if( 1 >= GetLen() || rInf.GetLen() > GetLen() || !Width() || !GetLen() ) 75 return SwPosSize(*this); 76 else 77 return SwPosSize( (Width() / GetLen()) * rInf.GetLen(), Height() ); 78 } 79 80 /************************************************************************* 81 * virtual SwGluePortion::GetExpTxt() 82 *************************************************************************/ 83 84 sal_Bool SwGluePortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 85 { 86 if( GetLen() && rInf.OnWin() && 87 rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() ) 88 { 89 rTxt.Fill( GetLen(), CH_BULLET ); 90 return sal_True; 91 } 92 return sal_False; 93 } 94 95 /************************************************************************* 96 * virtual SwGluePortion::Paint() 97 *************************************************************************/ 98 99 void SwGluePortion::Paint( const SwTxtPaintInfo &rInf ) const 100 { 101 if( !GetLen() ) 102 return; 103 104 if( rInf.GetFont()->IsPaintBlank() ) 105 { 106 XubString aTxt; 107 aTxt.Fill( GetFixWidth() / GetLen(), ' ' ); 108 SwTxtPaintInfo aInf( rInf, aTxt ); 109 aInf.DrawText( *this, aTxt.Len(), sal_True ); 110 } 111 112 if( rInf.OnWin() && rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() ) 113 { 114 #ifdef DBG_UTIL 115 const xub_Unicode cChar = rInf.GetChar( rInf.GetIdx() ); 116 ASSERT( CH_BLANK == cChar || CH_BULLET == cChar, 117 "SwGluePortion::Paint: blank expected" ); 118 #endif 119 if( 1 == GetLen() ) 120 { 121 String aBullet( CH_BULLET ); 122 SwPosSize aBulletSize( rInf.GetTxtSize( aBullet ) ); 123 Point aPos( rInf.GetPos() ); 124 aPos.X() += (Width()/2) - (aBulletSize.Width()/2); 125 SwTxtPaintInfo aInf( rInf, aBullet ); 126 aInf.SetPos( aPos ); 127 SwTxtPortion aBulletPor; 128 aBulletPor.Width( aBulletSize.Width() ); 129 aBulletPor.Height( aBulletSize.Height() ); 130 aBulletPor.SetAscent( GetAscent() ); 131 aInf.DrawText( aBulletPor, aBullet.Len(), sal_True ); 132 } 133 else 134 { 135 SwTxtSlot aSlot( &rInf, this, true, false ); 136 rInf.DrawText( *this, rInf.GetLen(), sal_True ); 137 } 138 } 139 } 140 141 /************************************************************************* 142 * SwGluePortion::MoveGlue() 143 *************************************************************************/ 144 145 void SwGluePortion::MoveGlue( SwGluePortion *pTarget, const short nPrtGlue ) 146 { 147 short nPrt = Min( nPrtGlue, GetPrtGlue() ); 148 if( 0 < nPrt ) 149 { 150 pTarget->AddPrtWidth( nPrt ); 151 SubPrtWidth( nPrt ); 152 } 153 } 154 155 /************************************************************************* 156 * void SwGluePortion::Join() 157 *************************************************************************/ 158 159 void SwGluePortion::Join( SwGluePortion *pVictim ) 160 { 161 // Die GluePortion wird ausgesogen und weggespuelt ... 162 AddPrtWidth( pVictim->PrtWidth() ); 163 SetLen( pVictim->GetLen() + GetLen() ); 164 if( Height() < pVictim->Height() ) 165 Height( pVictim->Height() ); 166 167 AdjFixWidth(); 168 Cut( pVictim ); 169 delete pVictim; 170 } 171 172 /************************************************************************* 173 * class SwFixPortion 174 *************************************************************************/ 175 176 // Wir erwarten ein framelokales SwRect ! 177 SwFixPortion::SwFixPortion( const SwRect &rRect ) 178 :SwGluePortion( KSHORT(rRect.Width()) ), nFix( KSHORT(rRect.Left()) ) 179 { 180 Height( KSHORT(rRect.Height()) ); 181 SetWhichPor( POR_FIX ); 182 } 183 184 SwFixPortion::SwFixPortion(const KSHORT nFixedWidth, const KSHORT nFixedPos) 185 : SwGluePortion(nFixedWidth), nFix(nFixedPos) 186 { 187 SetWhichPor( POR_FIX ); 188 } 189 190 /************************************************************************* 191 * class SwMarginPortion 192 *************************************************************************/ 193 194 SwMarginPortion::SwMarginPortion( const KSHORT nFixedWidth ) 195 :SwGluePortion( nFixedWidth ) 196 { 197 SetWhichPor( POR_MARGIN ); 198 } 199 200 /************************************************************************* 201 * SwMarginPortion::AdjustRight() 202 * 203 * In der umschliessenden Schleife werden alle Portions durchsucht, 204 * dabei werden erst die am Ende liegenden GluePortions verarbeitet. 205 * Das Ende wird nach jeder Schleife nach vorne verlegt, bis keine 206 * GluePortions mehr vorhanden sind. 207 * Es werden immer GluePortion-Paare betrachtet (pLeft und pRight), 208 * wobei Textportions zwischen pLeft und pRight hinter pRight verschoben 209 * werden, wenn pRight genuegend Glue besitzt. Bei jeder Verschiebung 210 * wandert ein Teil des Glues von pRight nach pLeft. 211 * Im naechsten Schleifendurchlauf ist pLeft das pRight und das Spiel 212 * beginnt von vorne. 213 *************************************************************************/ 214 215 void SwMarginPortion::AdjustRight( const SwLineLayout *pCurr ) 216 { 217 SwGluePortion *pRight = 0; 218 sal_Bool bNoMove = 0 != pCurr->GetpKanaComp(); 219 while( pRight != this ) 220 { 221 222 // 1) Wir suchen den linken Glue 223 SwLinePortion *pPos = (SwLinePortion*)this; 224 SwGluePortion *pLeft = 0; 225 while( pPos ) 226 { 227 DBG_LOOP; 228 if( pPos->InFixMargGrp() ) 229 pLeft = (SwGluePortion*)pPos; 230 pPos = pPos->GetPortion(); 231 if( pPos == pRight) 232 pPos = 0; 233 } 234 235 // Zwei nebeneinander liegende FlyPortions verschmelzen 236 if( pRight && pLeft->GetPortion() == pRight ) 237 { 238 pRight->MoveAllGlue( pLeft ); 239 pRight = 0; 240 } 241 KSHORT nRightGlue = pRight && 0 < pRight->GetPrtGlue() 242 ? KSHORT(pRight->GetPrtGlue()) : 0; 243 // 2) linken und rechten Glue ausgleichen 244 // Bei Tabs haengen wir nix um ... 245 if( pLeft && nRightGlue && !pRight->InTabGrp() ) 246 { 247 // pPrev ist die Portion, die unmittelbar vor pRight liegt. 248 SwLinePortion *pPrev = pRight->FindPrevPortion( pLeft ); 249 250 if ( pRight->IsFlyPortion() && pRight->GetLen() ) 251 { 252 SwFlyPortion *pFly = (SwFlyPortion *)pRight; 253 if ( pFly->GetBlankWidth() < nRightGlue ) 254 { 255 // Hier entsteht eine neue TxtPortion, die dass zuvor 256 // vom Fly verschluckte Blank reaktiviert. 257 nRightGlue = nRightGlue - pFly->GetBlankWidth(); 258 pFly->SubPrtWidth( pFly->GetBlankWidth() ); 259 pFly->SetLen( 0 ); 260 SwTxtPortion *pNewPor = new SwTxtPortion; 261 pNewPor->SetLen( 1 ); 262 pNewPor->Height( pFly->Height() ); 263 pNewPor->Width( pFly->GetBlankWidth() ); 264 pFly->Insert( pNewPor ); 265 } 266 else 267 pPrev = pLeft; 268 } 269 while( pPrev != pLeft ) 270 { 271 DBG_LOOP; 272 273 if( bNoMove || pPrev->PrtWidth() >= nRightGlue || 274 pPrev->InHyphGrp() || pPrev->IsKernPortion() ) 275 { 276 // Die Portion, die vor pRight liegt kann nicht 277 // verschoben werden, weil kein Glue mehr vorhanden ist. 278 // Wir fuehren die Abbruchbedingung herbei: 279 pPrev = pLeft; 280 } 281 else 282 { 283 nRightGlue = nRightGlue - pPrev->PrtWidth(); 284 // pPrev wird hinter pRight verschoben. 285 // Dazu wird der Gluewert zwischen pRight und pLeft 286 // ausgeglichen. 287 pRight->MoveGlue( pLeft, short( pPrev->PrtWidth() ) ); 288 // Jetzt wird die Verkettung gerichtet. 289 SwLinePortion *pPrevPrev = pPrev->FindPrevPortion( pLeft ); 290 pPrevPrev->SetPortion( pRight ); 291 pPrev->SetPortion( pRight->GetPortion() ); 292 pRight->SetPortion( pPrev ); 293 if ( pPrev->GetPortion() && pPrev->InTxtGrp() 294 && pPrev->GetPortion()->IsHolePortion() ) 295 { 296 SwHolePortion *pHolePor = 297 (SwHolePortion*)pPrev->GetPortion(); 298 if ( !pHolePor->GetPortion() || 299 !pHolePor->GetPortion()->InFixMargGrp() ) 300 { 301 pPrev->AddPrtWidth( pHolePor->GetBlankWidth() ); 302 pPrev->SetLen( pPrev->GetLen() + 1 ); 303 pPrev->SetPortion( pHolePor->GetPortion() ); 304 delete pHolePor; 305 } 306 } 307 pPrev = pPrevPrev; 308 } 309 } 310 } 311 // Wenn es keinen linken Glue mehr gibt, wird die Abbruchbedingung 312 // herbeigefuehrt. 313 pRight = pLeft ? pLeft : (SwGluePortion*)this; 314 } 315 } 316 317 318 319