Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "hintids.hxx"
30 : :
31 : : #include "layfrm.hxx"
32 : : #include "ftnboss.hxx"
33 : : #include "ndtxt.hxx"
34 : : #include "paratr.hxx"
35 : : #include <editeng/orphitem.hxx>
36 : : #include <editeng/widwitem.hxx>
37 : : #include <editeng/keepitem.hxx>
38 : : #include <editeng/spltitem.hxx>
39 : : #include <frmatr.hxx>
40 : : #include <txtftn.hxx>
41 : : #include <fmtftn.hxx>
42 : : #include <rowfrm.hxx>
43 : :
44 : : #include "widorp.hxx"
45 : : #include "txtfrm.hxx"
46 : : #include "itrtxt.hxx"
47 : : #include "sectfrm.hxx" //SwSectionFrm
48 : : #include "ftnfrm.hxx"
49 : :
50 : : #undef WIDOWTWIPS
51 : :
52 : :
53 : : /*************************************************************************
54 : : * inline IsNastyFollow()
55 : : *************************************************************************/
56 : : // Ein Follow, der auf der selben Seite steht, wie sein Master ist nasty.
57 : 12410 : inline sal_Bool IsNastyFollow( const SwTxtFrm *pFrm )
58 : : {
59 : : OSL_ENSURE( !pFrm->IsFollow() || !pFrm->GetPrev() ||
60 : : ((const SwTxtFrm*)pFrm->GetPrev())->GetFollow() == pFrm,
61 : : "IsNastyFollow: Was ist denn hier los?" );
62 [ + + ][ - + ]: 12410 : return pFrm->IsFollow() && pFrm->GetPrev();
63 : : }
64 : :
65 : : /*************************************************************************
66 : : * SwTxtFrmBreak::SwTxtFrmBreak()
67 : : *************************************************************************/
68 : :
69 : 14871 : SwTxtFrmBreak::SwTxtFrmBreak( SwTxtFrm *pNewFrm, const SwTwips nRst )
70 : 14871 : : nRstHeight(nRst), pFrm(pNewFrm)
71 : : {
72 [ - + ][ # # ]: 14871 : SWAP_IF_SWAPPED( pFrm )
[ - + ]
73 [ - + ][ # # ]: 14871 : SWRECTFN( pFrm )
[ # # ][ - + ]
74 [ + - ]: 14871 : nOrigin = (pFrm->*fnRect->fnGetPrtTop)();
75 : : SwSectionFrm* pSct;
76 : 27281 : bKeep = !pFrm->IsMoveable() || IsNastyFollow( pFrm ) ||
77 : 12595 : ( pFrm->IsInSct() && (pSct=pFrm->FindSctFrm())->Lower()->IsColumnFrm()
78 : 34 : && !pSct->MoveAllowed( pFrm ) ) ||
79 : 12402 : !pFrm->GetTxtNode()->GetSwAttrSet().GetSplit().GetValue() ||
80 [ + + + + : 52312 : pFrm->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue();
+ + ][ + + ]
[ + + + -
+ + ]
81 : 14871 : bBreak = sal_False;
82 : :
83 [ + + ][ + + ]: 14871 : if( !nRstHeight && !pFrm->IsFollow() && pFrm->IsInFtn() && pFrm->HasPara() )
[ + + ][ + - ]
[ + + ]
84 : : {
85 : 231 : nRstHeight = pFrm->GetFtnFrmHeight();
86 [ + - ]: 231 : nRstHeight += (pFrm->Prt().*fnRect->fnGetHeight)() -
87 [ + - ]: 231 : (pFrm->Frm().*fnRect->fnGetHeight)();
88 [ - + ]: 231 : if( nRstHeight < 0 )
89 : 0 : nRstHeight = 0;
90 : : }
91 : :
92 [ - + ]: 14871 : UNDO_SWAP( pFrm )
93 : 14871 : }
94 : :
95 : : /* BP 18.6.93: Widows.
96 : : * Im Gegensatz zur ersten Implementierung werden die Widows nicht
97 : : * mehr vorausschauend berechnet, sondern erst beim Formatieren des
98 : : * gesplitteten Follows festgestellt. Im Master faellt die Widows-
99 : : * Berechnung also generell weg (nWidows wird manipuliert).
100 : : * Wenn der Follow feststellt, dass die Widowsregel zutrifft,
101 : : * verschickt er an seinen Vorgaenger ein Prepare.
102 : : * Ein besonderes Problem ergibt sich, wenn die Widows zuschlagen,
103 : : * aber im Master noch ein paar Zeilen zur Verfuegung stehen.
104 : : *
105 : : */
106 : :
107 : : /*************************************************************************
108 : : * SwTxtFrmBreak::IsInside()
109 : : *************************************************************************/
110 : :
111 : : /* BP(22.07.92): Berechnung von Witwen und Waisen.
112 : : * Die Methode liefert sal_True zurueck, wenn eine dieser Regelung zutrifft.
113 : : *
114 : : * Eine Schwierigkeit gibt es im Zusammenhang mit Widows und
115 : : * unterschiedlichen Formaten zwischen Master- und Folgeframes:
116 : : * Beispiel: Wenn die erste Spalte 3cm und die zweite 4cm breit ist
117 : : * und Widows auf sagen wir 3 gesetzt ist, so ist erst bei der Formatierung
118 : : * des Follows entscheidbar, ob die Widowsbedingung einhaltbar ist oder
119 : : * nicht. Leider ist davon abhaengig, ob der Absatz als Ganzes auf die
120 : : * naechste Seite rutscht.
121 : : */
122 : :
123 : 86340 : sal_Bool SwTxtFrmBreak::IsInside( SwTxtMargin &rLine ) const
124 : : {
125 : 86340 : sal_Bool bFit = sal_False;
126 : :
127 [ - + ][ # # ]: 86340 : SWAP_IF_SWAPPED( pFrm )
[ - + ]
128 [ - + ][ # # ]: 86340 : SWRECTFN( pFrm )
[ # # ][ - + ]
129 : : // nOrigin is an absolut value, rLine referes to the swapped situation.
130 : :
131 : : SwTwips nTmpY;
132 [ - + ]: 86340 : if ( pFrm->IsVertical() )
133 : 0 : nTmpY = pFrm->SwitchHorizontalToVertical( rLine.Y() + rLine.GetLineHeight() );
134 : : else
135 : 86340 : nTmpY = rLine.Y() + rLine.GetLineHeight();
136 : :
137 : 86340 : SwTwips nLineHeight = (*fnRect->fnYDiff)( nTmpY , nOrigin );
138 : :
139 : : // 7455 und 6114: Raum fuer die Umrandung unten einkalkulieren.
140 [ + - ]: 86340 : nLineHeight += (pFrm->*fnRect->fnGetBottomMargin)();
141 : :
142 [ + + ]: 86340 : if( nRstHeight )
143 : 1723 : bFit = nRstHeight >= nLineHeight;
144 : : else
145 : : {
146 : : // Der Frm besitzt eine Hoehe, mit der er auf die Seite passt.
147 : : SwTwips nHeight =
148 [ + - ]: 84617 : (*fnRect->fnYDiff)( (pFrm->GetUpper()->*fnRect->fnGetPrtBottom)(), nOrigin );
149 : : // Wenn sich alles innerhalb des bestehenden Frames abspielt,
150 : : // ist das Ergebnis sal_True;
151 : 84617 : bFit = nHeight >= nLineHeight;
152 : :
153 : : // --> OD #i103292#
154 [ + + ]: 84617 : if ( !bFit )
155 : : {
156 [ + + - + : 2093 : if ( rLine.GetNext() &&
# # # # ]
[ - + ]
157 : 54 : pFrm->IsInTab() && !pFrm->GetFollow() && !pFrm->GetIndNext() )
158 : : {
159 : : // add additional space taken as lower space as last content in a table
160 : : // for all text lines except the last one.
161 : 0 : nHeight += pFrm->CalcAddLowerSpaceAsLastInTableCell();
162 : 0 : bFit = nHeight >= nLineHeight;
163 : : }
164 : : }
165 : : // <--
166 [ + + ]: 84617 : if( !bFit )
167 : : {
168 : : // Die LineHeight sprengt die aktuelle Frm-Hoehe.
169 : : // Nun rufen wir ein Probe-Grow, um zu ermitteln, ob der
170 : : // Frame um den gewuenschten Bereich wachsen wuerde.
171 : 2039 : nHeight += pFrm->GrowTst( LONG_MAX );
172 : :
173 : : // Das Grow() returnt die Hoehe, um die der Upper des TxtFrm
174 : : // den TxtFrm wachsen lassen wuerde.
175 : : // Der TxtFrm selbst darf wachsen wie er will.
176 : 2039 : bFit = nHeight >= nLineHeight;
177 : : }
178 : : }
179 : :
180 [ - + ]: 86340 : UNDO_SWAP( pFrm );
181 : :
182 : 86340 : return bFit;
183 : : }
184 : :
185 : : /*************************************************************************
186 : : * SwTxtFrmBreak::IsBreakNow()
187 : : *************************************************************************/
188 : :
189 : 99056 : sal_Bool SwTxtFrmBreak::IsBreakNow( SwTxtMargin &rLine )
190 : : {
191 [ - + ][ # # ]: 99056 : SWAP_IF_SWAPPED( pFrm )
[ - + ]
192 : :
193 : : // bKeep ist staerker als IsBreakNow()
194 : : // Ist noch genug Platz ?
195 [ + + ][ + + ]: 99056 : if( bKeep || IsInside( rLine ) )
[ + + ]
196 : 96520 : bBreak = sal_False;
197 : : else
198 : : {
199 : : /* Diese Klasse geht davon aus, dass der SwTxtMargin von Top nach Bottom
200 : : * durchgearbeitet wird. Aus Performancegruenden wird in folgenden
201 : : * Faellen der Laden fuer das weitere Aufspalten dicht gemacht:
202 : : * Wenn eine einzige Zeile nicht mehr passt.
203 : : * Sonderfall: bei DummyPortions ist LineNr == 1, obwohl wir splitten
204 : : * wollen.
205 : : */
206 : : // 6010: DropLines mit einbeziehen
207 : :
208 [ + + ][ + + ]: 2536 : sal_Bool bFirstLine = 1 == rLine.GetLineNr() && !rLine.GetPrev();
209 : 2536 : bBreak = sal_True;
210 [ + + ]: 5045 : if( ( bFirstLine && pFrm->GetIndPrev() )
[ + + - + ]
[ + + ]
211 : 2509 : || ( rLine.GetLineNr() <= rLine.GetDropLines() ) )
212 : : {
213 : 27 : bKeep = sal_True;
214 : 27 : bBreak = sal_False;
215 : : }
216 [ + + ][ - + ]: 2509 : else if(bFirstLine && pFrm->IsInFtn() && !pFrm->FindFtnFrm()->GetPrev())
[ # # ][ - + ]
217 : : {
218 : 0 : SwLayoutFrm* pTmp = pFrm->FindFtnBossFrm()->FindBodyCont();
219 [ # # ][ # # ]: 0 : if( !pTmp || !pTmp->Lower() )
[ # # ]
220 : 0 : bBreak = sal_False;
221 : : }
222 : : }
223 : :
224 [ - + ]: 99056 : UNDO_SWAP( pFrm )
225 : :
226 : 99056 : return bBreak;
227 : : }
228 : :
229 : : // OD 2004-02-27 #106629# - no longer inline
230 : 323 : void SwTxtFrmBreak::SetRstHeight( const SwTxtMargin &rLine )
231 : : {
232 : : // OD, FME 2004-02-27 #106629# - consider bottom margin
233 [ - + ][ # # ]: 323 : SWRECTFN( pFrm )
[ # # ][ - + ]
234 : :
235 [ + - ]: 323 : nRstHeight = (pFrm->*fnRect->fnGetBottomMargin)();
236 : :
237 [ - + ]: 323 : if ( bVert )
238 : : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
239 : : {
240 [ # # ]: 0 : if ( pFrm->IsVertLR() )
241 : 0 : nRstHeight = (*fnRect->fnYDiff)( pFrm->SwitchHorizontalToVertical( rLine.Y() ) , nOrigin );
242 : : else
243 : 0 : nRstHeight += nOrigin - pFrm->SwitchHorizontalToVertical( rLine.Y() );
244 : : }
245 : : else
246 : 323 : nRstHeight += rLine.Y() - nOrigin;
247 : 323 : }
248 : :
249 : : /*************************************************************************
250 : : * WidowsAndOrphans::WidowsAndOrphans()
251 : : *************************************************************************/
252 : :
253 : 14871 : WidowsAndOrphans::WidowsAndOrphans( SwTxtFrm *pNewFrm, const SwTwips nRst,
254 : : sal_Bool bChkKeep )
255 : 14871 : : SwTxtFrmBreak( pNewFrm, nRst ), nWidLines( 0 ), nOrphLines( 0 )
256 : : {
257 [ # # ][ - + ]: 14871 : SWAP_IF_SWAPPED( pFrm )
[ - + ]
258 : :
259 [ + + ]: 14871 : if( bKeep )
260 : : {
261 : : // 5652: bei Absaetzen, die zusammengehalten werden sollen und
262 : : // groesser sind als die Seite wird bKeep aufgehoben.
263 [ + - ][ + + ]: 5111 : if( bChkKeep && !pFrm->GetPrev() && !pFrm->IsInFtn() &&
[ + - + +
+ + - + ]
[ + + ]
264 : 2464 : pFrm->IsMoveable() &&
265 : 91 : ( !pFrm->IsInSct() || pFrm->FindSctFrm()->MoveAllowed(pFrm) ) )
266 : 15 : bKeep = sal_False;
267 : : //Auch bei gesetztem Keep muessen Orphans beachtet werden,
268 : : //z.B. bei verketteten Rahmen erhaelt ein Follow im letzten Rahmen ein Keep,
269 : : //da er nicht (vorwaerts) Moveable ist,
270 : : //er darf aber trotzdem vom Master Zeilen anfordern wg. der Orphanregel.
271 [ - + ]: 2556 : if( pFrm->IsFollow() )
272 : 0 : nWidLines = pFrm->GetTxtNode()->GetSwAttrSet().GetWidows().GetValue();
273 : : }
274 : : else
275 : : {
276 : 12315 : const SwAttrSet& rSet = pFrm->GetTxtNode()->GetSwAttrSet();
277 : 12315 : const SvxOrphansItem &rOrph = rSet.GetOrphans();
278 [ + + ]: 12315 : if ( rOrph.GetValue() > 1 )
279 : 301 : nOrphLines = rOrph.GetValue();
280 [ + + ]: 12315 : if ( pFrm->IsFollow() )
281 : 1726 : nWidLines = rSet.GetWidows().GetValue();
282 : :
283 : : }
284 : :
285 [ + + ][ + - ]: 14871 : if ( bKeep || nWidLines || nOrphLines )
[ + + ]
286 : : {
287 : 2842 : bool bResetFlags = false;
288 : :
289 [ + + ]: 2842 : if ( pFrm->IsInTab() )
290 : : {
291 : : // For compatibility reasons, we disable Keep/Widows/Orphans
292 : : // inside splittable row frames:
293 [ + - ][ - + ]: 2078 : if ( pFrm->GetNextCellLeaf( MAKEPAGE_NONE ) || pFrm->IsInFollowFlowRow() )
[ - + ]
294 : : {
295 : 0 : const SwFrm* pTmpFrm = pFrm->GetUpper();
296 [ # # ]: 0 : while ( !pTmpFrm->IsRowFrm() )
297 : 0 : pTmpFrm = pTmpFrm->GetUpper();
298 [ # # ]: 0 : if ( static_cast<const SwRowFrm*>(pTmpFrm)->IsRowSplitAllowed() )
299 : 0 : bResetFlags = true;
300 : : }
301 : : }
302 : :
303 [ - + ][ # # ]: 2842 : if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
[ - + ]
304 : : {
305 : : // Innerhalb von Fussnoten gibt es gute Gruende, das Keep-Attribut und
306 : : // die Widows/Orphans abzuschalten.
307 : 0 : SwFtnFrm *pFtn = pFrm->FindFtnFrm();
308 : 0 : sal_Bool bFt = !pFtn->GetAttr()->GetFtn().IsEndNote();
309 [ # # ][ # # : 0 : if( !pFtn->GetPrev() &&
# # # # #
# ]
310 : 0 : pFtn->FindFtnBossFrm( bFt ) != pFtn->GetRef()->FindFtnBossFrm( bFt )
311 : 0 : && ( !pFrm->IsInSct() || pFrm->FindSctFrm()->MoveAllowed(pFrm) ) )
312 : : {
313 : 0 : bResetFlags = true;
314 : : }
315 : : }
316 : :
317 [ - + ]: 2842 : if ( bResetFlags )
318 : : {
319 : 0 : bKeep = sal_False;
320 : 0 : nOrphLines = 0;
321 : 0 : nWidLines = 0;
322 : : }
323 : : }
324 : :
325 [ - + ]: 14871 : UNDO_SWAP( pFrm )
326 : 14871 : }
327 : :
328 : : /*************************************************************************
329 : : * WidowsAndOrphans::FindBreak()
330 : : *************************************************************************/
331 : :
332 : : /* Die Find*-Methoden suchen nicht nur, sondern stellen den SwTxtMargin auf
333 : : * die Zeile ein, wo der Absatz gebrochen werden soll und kuerzen ihn dort.
334 : : * FindBreak()
335 : : */
336 : :
337 : 14711 : sal_Bool WidowsAndOrphans::FindBreak( SwTxtFrm *pFrame, SwTxtMargin &rLine,
338 : : sal_Bool bHasToFit )
339 : : {
340 : : // OD 2004-02-25 #i16128# - Why member <pFrm> _*and*_ parameter <pFrame>??
341 : : // Thus, assertion on situation, that these are different to figure out why.
342 : : OSL_ENSURE( pFrm == pFrame, "<WidowsAndOrphans::FindBreak> - pFrm != pFrame" );
343 : :
344 [ - + ][ # # ]: 14711 : SWAP_IF_SWAPPED( pFrm )
[ - + ]
345 : :
346 : 14711 : sal_Bool bRet = sal_True;
347 : 14711 : MSHORT nOldOrphans = nOrphLines;
348 [ + + ]: 14711 : if( bHasToFit )
349 : 26 : nOrphLines = 0;
350 : 14711 : rLine.Bottom();
351 : : // OD 2004-02-25 #i16128# - method renamed
352 [ + + ]: 14711 : if( !IsBreakNowWidAndOrp( rLine ) )
353 : 13891 : bRet = sal_False;
354 [ + - ]: 14711 : if( !FindWidows( pFrame, rLine ) )
355 : : {
356 : 14711 : sal_Bool bBack = sal_False;
357 : : // OD 2004-02-25 #i16128# - method renamed
358 [ + + ]: 15426 : while( IsBreakNowWidAndOrp( rLine ) )
359 : : {
360 [ + + ]: 841 : if( rLine.PrevLine() )
361 : 715 : bBack = sal_True;
362 : : else
363 : 126 : break;
364 : : }
365 : : // Eigentlich werden bei HasToFit Schusterjungen (Orphans) nicht
366 : : // beruecksichtigt, wenn allerdings Dummy-Lines im Spiel sind und
367 : : // die Orphansregel verletzt wird, machen wir mal eine Ausnahme:
368 : : // Wir lassen einfach eine Dummyline zurueck und wandern mit dem Text
369 : : // komplett auf die naechste Seite/Spalte.
370 [ + + + + ]: 15021 : if( rLine.GetLineNr() <= nOldOrphans &&
[ - + ]
[ # # - + ]
[ - + ]
371 : 286 : rLine.GetInfo().GetParaPortion()->IsDummy() &&
372 : 24 : ( ( bHasToFit && bRet ) || IsBreakNow( rLine ) ) )
373 : 0 : rLine.Top();
374 : :
375 : 14711 : rLine.TruncLines( sal_True );
376 : 14711 : bRet = bBack;
377 : : }
378 : 14711 : nOrphLines = nOldOrphans;
379 : :
380 [ - + ]: 14711 : UNDO_SWAP( pFrm )
381 : :
382 : 14711 : return bRet;
383 : : }
384 : :
385 : : /*************************************************************************
386 : : * WidowsAndOrphans::FindWidows()
387 : : *************************************************************************/
388 : :
389 : : /* FindWidows positioniert den SwTxtMargin des Masters auf die umzubrechende
390 : : * Zeile, indem der Follow formatiert und untersucht wird.
391 : : * Liefert sal_True zurueck, wenn die Widows-Regelung in Kraft tritt,
392 : : * d.h. der Absatz _zusammengehalten_ werden soll !
393 : : */
394 : :
395 : 14711 : sal_Bool WidowsAndOrphans::FindWidows( SwTxtFrm *pFrame, SwTxtMargin &rLine )
396 : : {
397 : : OSL_ENSURE( ! pFrame->IsVertical() || ! pFrame->IsSwapped(),
398 : : "WidowsAndOrphans::FindWidows with swapped frame" );
399 : :
400 [ - + ][ # # ]: 14711 : if( !nWidLines || !pFrame->IsFollow() )
[ + - ]
401 : 14711 : return sal_False;
402 : :
403 [ # # ]: 0 : rLine.Bottom();
404 : :
405 : : // Wir koennen noch was abzwacken
406 [ # # ]: 0 : SwTxtFrm *pMaster = pFrame->FindMaster();
407 : : OSL_ENSURE(pMaster, "+WidowsAndOrphans::FindWidows: Widows in a master?");
408 [ # # ]: 0 : if( !pMaster )
409 : 0 : return sal_False;
410 : :
411 : : // 5156: Wenn die erste Zeile des Follows nicht passt, wird der Master
412 : : // wohl voll mit Dummies sein. In diesem Fall waere ein PREP_WIDOWS fatal.
413 [ # # ]: 0 : if( pMaster->GetOfst() == pFrame->GetOfst() )
414 : 0 : return sal_False;
415 : :
416 : : // Resthoehe des Masters
417 [ # # ][ # # ]: 0 : SWRECTFN( pFrame )
[ # # ][ # # ]
[ # # ]
418 : :
419 [ # # ][ # # ]: 0 : const SwTwips nDocPrtTop = (pFrame->*fnRect->fnGetPrtTop)();
420 : : SwTwips nOldHeight;
421 : 0 : SwTwips nTmpY = rLine.Y() + rLine.GetLineHeight();
422 : :
423 [ # # ]: 0 : if ( bVert )
424 : : {
425 [ # # ]: 0 : nTmpY = pFrame->SwitchHorizontalToVertical( nTmpY );
426 [ # # ][ # # ]: 0 : nOldHeight = -(pFrame->Prt().*fnRect->fnGetHeight)();
427 : : }
428 : : else
429 [ # # ][ # # ]: 0 : nOldHeight = (pFrame->Prt().*fnRect->fnGetHeight)();
430 : :
431 [ # # ]: 0 : const SwTwips nChg = (*fnRect->fnYDiff)( nTmpY, nDocPrtTop + nOldHeight );
432 : :
433 : : // Unterhalb der Widows-Schwelle...
434 [ # # ]: 0 : if( rLine.GetLineNr() >= nWidLines )
435 : : {
436 : : // 8575: Follow to Master I
437 : : // Wenn der Follow *waechst*, so besteht fuer den Master die Chance,
438 : : // Zeilen entgegenzunehmen, die er vor Kurzem gezwungen war an den
439 : : // Follow abzugeben: Prepare(Need); diese Abfrage unterhalb von nChg!
440 : : // (0W, 2O, 2M, 2F) + 1F = 3M, 2F
441 [ # # ][ # # ]: 0 : if( rLine.GetLineNr() > nWidLines && pFrame->IsJustWidow() )
[ # # ]
442 : : {
443 : : // Wenn der Master gelockt ist, so hat er vermutlich gerade erst
444 : : // eine Zeile an uns abgegeben, diese geben nicht zurueck, nur
445 : : // weil bei uns daraus mehrere geworden sind (z.B. durch Rahmen).
446 [ # # ][ # # ]: 0 : if( !pMaster->IsLocked() && pMaster->GetUpper() )
[ # # ]
447 : : {
448 : 0 : const SwTwips nTmpRstHeight = (pMaster->Frm().*fnRect->fnBottomDist)
449 [ # # ][ # # ]: 0 : ( (pMaster->GetUpper()->*fnRect->fnGetPrtBottom)() );
[ # # ][ # # ]
450 [ # # ]: 0 : if ( nTmpRstHeight >=
451 : 0 : SwTwips(rLine.GetInfo().GetParaPortion()->Height() ) )
452 : : {
453 [ # # ]: 0 : pMaster->Prepare( PREP_ADJUST_FRM );
454 [ # # ]: 0 : pMaster->_InvalidateSize();
455 [ # # ]: 0 : pMaster->InvalidatePage();
456 : : }
457 : : }
458 : :
459 : 0 : pFrame->SetJustWidow( sal_False );
460 : : }
461 : 0 : return sal_False;
462 : : }
463 : :
464 : : // 8575: Follow to Master II
465 : : // Wenn der Follow *schrumpft*, so besteht fuer den Master die Chance,
466 : : // den kompletten Orphan zu inhalieren.
467 : : // (0W, 2O, 2M, 1F) - 1F = 3M, 0F -> PREP_ADJUST_FRM
468 : : // (0W, 2O, 3M, 2F) - 1F = 2M, 2F -> PREP_WIDOWS
469 : :
470 [ # # ][ # # ]: 0 : if( 0 > nChg && !pMaster->IsLocked() && pMaster->GetUpper() )
[ # # ][ # # ]
471 : : {
472 : 0 : SwTwips nTmpRstHeight = (pMaster->Frm().*fnRect->fnBottomDist)
473 [ # # ][ # # ]: 0 : ( (pMaster->GetUpper()->*fnRect->fnGetPrtBottom)() );
[ # # ][ # # ]
474 [ # # ]: 0 : if( nTmpRstHeight >= SwTwips(rLine.GetInfo().GetParaPortion()->Height() ) )
475 : : {
476 [ # # ]: 0 : pMaster->Prepare( PREP_ADJUST_FRM );
477 [ # # ]: 0 : pMaster->_InvalidateSize();
478 [ # # ]: 0 : pMaster->InvalidatePage();
479 : 0 : pFrame->SetJustWidow( sal_False );
480 : 0 : return sal_False;
481 : : }
482 : : }
483 : :
484 : : // Master to Follow
485 : : // Wenn der Follow nach seiner Formatierung weniger Zeilen enthaelt
486 : : // als Widows, so besteht noch die Chance, einige Zeilen des Masters
487 : : // abzuzwacken. Wenn dadurch die Orphans-Regel des Masters in Kraft
488 : : // tritt muss im CalcPrep() des Master-Frame der Frame so vergroessert
489 : : // werden, dass er nicht mehr auf seine urspruengliche Seite passt.
490 : : // Wenn er noch ein paar Zeilen entbehren kann, dann muss im CalcPrep()
491 : : // ein Shrink() erfolgen, der Follow mit dem Widows rutscht dann auf
492 : : // die Seite des Masters, haelt sich aber zusammen, so dass er (endlich)
493 : : // auf die naechste Seite rutscht. - So die Theorie!
494 : :
495 : :
496 : : // Wir fordern nur noch ein Zeile zur Zeit an, weil eine Zeile des Masters
497 : : // bei uns durchaus mehrere Zeilen ergeben koennten.
498 : : // Dafuer behaelt CalcFollow solange die Kontrolle, bis der Follow alle
499 : : // notwendigen Zeilen bekommen hat.
500 : 0 : MSHORT nNeed = 1; // frueher: nWidLines - rLine.GetLineNr();
501 : :
502 : : // Special case: Master cannot give lines to follow
503 : : // #i91421#
504 [ # # ][ # # ]: 0 : if ( !pMaster->GetIndPrev() )
505 : : {
506 : 0 : sal_uLong nLines = pMaster->GetThisLines();
507 [ # # ][ # # ]: 0 : if(nLines == 0 && pMaster->HasPara())
[ # # ][ # # ]
508 : : {
509 [ # # ]: 0 : const SwParaPortion *pMasterPara = pMaster->GetPara();
510 [ # # ][ # # ]: 0 : if(pMasterPara && pMasterPara->GetNext())
[ # # ]
511 : 0 : nLines = 2;
512 : : }
513 [ # # ]: 0 : if( nLines <= nNeed )
514 : 0 : return sal_False;
515 : : }
516 : :
517 [ # # ]: 0 : pMaster->Prepare( PREP_WIDOWS, (void*)&nNeed );
518 : 14711 : return sal_True;
519 : : }
520 : :
521 : : /*************************************************************************
522 : : * WidowsAndOrphans::WouldFit()
523 : : *************************************************************************/
524 : :
525 : 60 : sal_Bool WidowsAndOrphans::WouldFit( SwTxtMargin &rLine, SwTwips &rMaxHeight, sal_Bool bTst )
526 : : {
527 : : // Here it does not matter, if pFrm is swapped or not.
528 : : // IsInside() takes care for itself
529 : :
530 : : // Wir erwarten, dass rLine auf der letzten Zeile steht!!
531 : : OSL_ENSURE( !rLine.GetNext(), "WouldFit: aLine::Bottom missed!" );
532 : 60 : MSHORT nLineCnt = rLine.GetLineNr();
533 : :
534 : : // Erstmal die Orphansregel und den Initialenwunsch erfuellen ...
535 : 60 : const MSHORT nMinLines = Max( GetOrphansLines(), rLine.GetDropLines() );
536 [ - + ]: 60 : if ( nLineCnt < nMinLines )
537 : 0 : return sal_False;
538 : :
539 : 60 : rLine.Top();
540 : 60 : SwTwips nLineSum = rLine.GetLineHeight();
541 : :
542 [ - + ]: 60 : while( nMinLines > rLine.GetLineNr() )
543 : : {
544 [ # # ]: 0 : if( !rLine.NextLine() )
545 : 0 : return sal_False;
546 : 0 : nLineSum += rLine.GetLineHeight();
547 : : }
548 : :
549 : : // Wenn wir jetzt schon nicht mehr passen ...
550 [ + + ]: 60 : if( !IsInside( rLine ) )
551 : 54 : return sal_False;
552 : :
553 : : // Jetzt noch die Widows-Regel ueberpruefen
554 [ + - ][ + - ]: 6 : if( !nWidLines && !pFrm->IsFollow() )
[ + - ]
555 : : {
556 : : // I.A. brauchen Widows nur ueberprueft werden, wenn wir ein Follow
557 : : // sind. Bei WouldFit muss aber auch fuer den Master die Regel ueber-
558 : : // prueft werden, weil wir ja gerade erst die Trennstelle ermitteln.
559 : : // Im Ctor von WidowsAndOrphans wurde nWidLines aber nur fuer Follows
560 : : // aus dem AttrSet ermittelt, deshalb holen wir es hier nach:
561 : 6 : const SwAttrSet& rSet = pFrm->GetTxtNode()->GetSwAttrSet();
562 : 6 : nWidLines = rSet.GetWidows().GetValue();
563 : : }
564 : :
565 : : // Sind nach Orphans/Initialen noch genug Zeilen fuer die Widows uebrig?
566 : : // #111937#: If we are currently doing a test formatting, we may not
567 : : // consider the widows rule for two reasons:
568 : : // 1. The columns may have different widths.
569 : : // Widow lines would have wrong width.
570 : : // 2. Test formatting is only done up to the given space.
571 : : // we do not have any lines for widows at all.
572 [ + + ][ + - ]: 6 : if( bTst || nLineCnt - nMinLines >= GetWidowsLines() )
[ + - ]
573 : : {
574 [ + - ]: 6 : if( rMaxHeight >= nLineSum )
575 : : {
576 : 6 : rMaxHeight -= nLineSum;
577 : 6 : return sal_True;
578 : : }
579 : : }
580 : 60 : return sal_False;
581 : : }
582 : :
583 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|