xref: /AOO41X/main/sw/source/core/text/porglue.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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