xref: /trunk/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