Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "viewsh.hxx"
21 : #include "doc.hxx"
22 : #include "pagefrm.hxx"
23 : #include "rootfrm.hxx"
24 : #include "ndtxt.hxx"
25 : #include "txtatr.hxx"
26 : #include <SwPortionHandler.hxx>
27 : #include <txtftn.hxx>
28 : #include <flyfrm.hxx>
29 : #include <fmtftn.hxx>
30 : #include <ftninfo.hxx>
31 : #include <charfmt.hxx>
32 : #include <dflyobj.hxx>
33 : #include <rowfrm.hxx>
34 : #include <editeng/brushitem.hxx>
35 : #include <editeng/charrotateitem.hxx>
36 : #include <breakit.hxx>
37 : #include <com/sun/star/i18n/ScriptType.hpp>
38 : #include <tabfrm.hxx>
39 : // #i28701#
40 : #include <sortedobjs.hxx>
41 :
42 : #include "swfont.hxx"
43 : #include "porftn.hxx"
44 : #include "porfly.hxx"
45 : #include "porlay.hxx"
46 : #include "txtfrm.hxx"
47 : #include "itrform2.hxx"
48 : #include "ftnfrm.hxx"
49 : #include "pagedesc.hxx"
50 : #include "redlnitr.hxx"
51 : #include "sectfrm.hxx"
52 : #include "layouter.hxx"
53 : #include "frmtool.hxx"
54 : #include "ndindex.hxx"
55 :
56 : using namespace ::com::sun::star;
57 :
58 193 : bool SwTxtFrm::_IsFtnNumFrm() const
59 : {
60 193 : const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster();
61 386 : while( pFtn && !pFtn->ContainsCntnt() )
62 0 : pFtn = pFtn->GetMaster();
63 193 : return !pFtn;
64 : }
65 :
66 : // Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn
67 246 : SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn )
68 : {
69 246 : SwTxtFrm *pFrm = this;
70 246 : const bool bFwd = *pFtn->GetStart() >= GetOfst();
71 563 : while( pFrm )
72 : {
73 246 : if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) )
74 175 : return pFrm;
75 : pFrm = bFwd ? pFrm->GetFollow() :
76 71 : pFrm->IsFollow() ? pFrm->FindMaster() : 0;
77 : }
78 71 : return pFrm;
79 : }
80 :
81 : #ifdef DBG_UTIL
82 : void SwTxtFrm::CalcFtnFlag( sal_Int32 nStop )// For testing the SplitFrm
83 : #else
84 15604 : void SwTxtFrm::CalcFtnFlag()
85 : #endif
86 : {
87 15604 : bFtn = false;
88 :
89 15604 : const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
90 15604 : if( !pHints )
91 17074 : return;
92 :
93 14134 : const sal_uInt16 nSize = pHints->Count();
94 :
95 : #ifdef DBG_UTIL
96 : const sal_Int32 nEnd = nStop != COMPLETE_STRING ? nStop
97 : : GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
98 : #else
99 14134 : const sal_Int32 nEnd = GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
100 : #endif
101 :
102 46058 : for ( sal_uInt16 i = 0; i < nSize; ++i )
103 : {
104 32044 : const SwTxtAttr *pHt = (*pHints)[i];
105 32044 : if ( pHt->Which() == RES_TXTATR_FTN )
106 : {
107 120 : const sal_Int32 nIdx = *pHt->GetStart();
108 120 : if ( nEnd < nIdx )
109 0 : break;
110 120 : if( GetOfst() <= nIdx )
111 : {
112 120 : bFtn = true;
113 120 : break;
114 : }
115 : }
116 : }
117 : }
118 :
119 16 : bool SwTxtFrm::CalcPrepFtnAdjust()
120 : {
121 : OSL_ENSURE( HasFtn(), "Wer ruft mich da?" );
122 16 : SwFtnBossFrm *pBoss = FindFtnBossFrm( true );
123 16 : const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this );
124 44 : if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos &&
125 17 : ( !pBoss->GetUpper()->IsSctFrm() ||
126 3 : !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) )
127 : {
128 14 : const SwFtnContFrm *pCont = pBoss->FindFtnCont();
129 14 : bool bReArrange = true;
130 :
131 14 : SWRECTFN( this )
132 56 : if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
133 42 : (Frm().*fnRect->fnGetBottom)() ) > 0 )
134 : {
135 28 : pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), false,
136 42 : pFtn->GetAttr() );
137 14 : ValidateBodyFrm();
138 14 : ValidateFrm();
139 14 : pFtn = pBoss->FindFirstFtn( this );
140 : }
141 : else
142 0 : bReArrange = false;
143 14 : if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) )
144 : {
145 2 : SwTxtFormatInfo aInf( this );
146 4 : SwTxtFormatter aLine( this, &aInf );
147 2 : aLine.TruncLines();
148 2 : SetPara( 0 ); //Wird ggf. geloescht!
149 2 : ResetPreps();
150 4 : return false;
151 : }
152 : }
153 14 : return true;
154 : }
155 :
156 : /*************************************************************************
157 : * lcl_GetFtnLower()
158 : *
159 : * Local helper function. Checks if nLower should be taken as the boundary
160 : * for the footnote.
161 : *************************************************************************/
162 :
163 228 : static SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower )
164 : {
165 : // nLower is an absolute value. It denotes the bottom of the line
166 : // containing the footnote.
167 228 : SWRECTFN( pFrm )
168 :
169 : OSL_ENSURE( !pFrm->IsVertical() || !pFrm->IsSwapped(),
170 : "lcl_GetFtnLower with swapped frame" );
171 :
172 : SwTwips nAdd;
173 228 : SwTwips nRet = nLower;
174 :
175 : // Check if text is inside a table.
176 228 : if ( pFrm->IsInTab() )
177 : {
178 : // If pFrm is inside a table, we have to check if
179 : // a) The table is not allowed to split or
180 : // b) The table row is not allowed to split
181 :
182 : // Inside a table, there are no footnotes,
183 : // see SwFrm::FindFtnBossFrm. So we don't have to check
184 : // the case that pFrm is inside a (footnote collecting) section
185 : // within the table.
186 0 : const SwFrm* pRow = pFrm;
187 0 : while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
188 0 : pRow = pRow->GetUpper();
189 0 : const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper();
190 :
191 : OSL_ENSURE( pTabFrm && pRow &&
192 : pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" );
193 :
194 0 : const bool bDontSplit = !pTabFrm->IsFollow() &&
195 0 : !pTabFrm->IsLayoutSplitAllowed();
196 :
197 0 : SwTwips nMin = 0;
198 0 : if ( bDontSplit )
199 0 : nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)();
200 0 : else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() )
201 0 : nMin = (pRow->Frm().*fnRect->fnGetBottom)();
202 :
203 0 : if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 )
204 0 : nRet = nMin;
205 :
206 0 : nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)();
207 : }
208 : else
209 228 : nAdd = (pFrm->*fnRect->fnGetBottomMargin)();
210 :
211 228 : if( nAdd > 0 )
212 : {
213 0 : if ( bVert )
214 0 : nRet -= nAdd;
215 : else
216 0 : nRet += nAdd;
217 : }
218 :
219 : // #i10770#: If there are fly frames anchored at previous paragraphs,
220 : // the deadline should consider their lower borders.
221 228 : const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower();
222 : OSL_ENSURE( pStartFrm, "Upper has no lower" );
223 228 : SwTwips nFlyLower = bVert ? LONG_MAX : 0;
224 737 : while ( pStartFrm != pFrm )
225 : {
226 : OSL_ENSURE( pStartFrm, "Frame chain is broken" );
227 281 : if ( pStartFrm->GetDrawObjs() )
228 : {
229 0 : const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
230 0 : for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
231 : {
232 0 : SwAnchoredObject* pAnchoredObj = rObjs[i];
233 0 : SwRect aRect( pAnchoredObj->GetObjRect() );
234 :
235 0 : if ( !pAnchoredObj->ISA(SwFlyFrm) ||
236 0 : static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() )
237 : {
238 0 : const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
239 0 : if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 )
240 0 : nFlyLower = nBottom;
241 : }
242 : }
243 : }
244 :
245 281 : pStartFrm = pStartFrm->GetNext();
246 : }
247 :
248 228 : if ( bVert )
249 0 : nRet = std::min( nRet, nFlyLower );
250 : else
251 228 : nRet = std::max( nRet, nFlyLower );
252 :
253 228 : return nRet;
254 : }
255 :
256 105 : SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const
257 : {
258 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
259 : "SwTxtFrm::GetFtnLine with swapped frame" );
260 :
261 105 : SwTxtFrm *pThis = (SwTxtFrm*)this;
262 :
263 105 : if( !HasPara() )
264 : {
265 : // #109071# GetFormatted() does not work here, bacause most probably
266 : // the frame is currently locked. We return the previous value.
267 0 : return pThis->mnFtnLine > 0 ?
268 : pThis->mnFtnLine :
269 0 : IsVertical() ? Frm().Left() : Frm().Bottom();
270 : }
271 :
272 105 : SWAP_IF_NOT_SWAPPED( this )
273 :
274 105 : SwTxtInfo aInf( pThis );
275 105 : SwTxtIter aLine( pThis, &aInf );
276 105 : const sal_Int32 nPos = *pFtn->GetStart();
277 105 : aLine.CharToLine( nPos );
278 :
279 105 : SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
280 105 : if( IsVertical() )
281 0 : nRet = SwitchHorizontalToVertical( nRet );
282 :
283 105 : UNDO_SWAP( this )
284 :
285 105 : nRet = lcl_GetFtnLower( pThis, nRet );
286 :
287 105 : pThis->mnFtnLine = nRet;
288 105 : return nRet;
289 : }
290 :
291 : // Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich.
292 : // Sie wird eingeschraenkt durch den unteren Rand der Zeile mit
293 : // der Ftn-Referenz.
294 211 : SwTwips SwTxtFrm::_GetFtnFrmHeight() const
295 : {
296 : OSL_ENSURE( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" );
297 :
298 211 : const SwFtnFrm *pFtnFrm = FindFtnFrm();
299 211 : const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef();
300 211 : const SwFtnBossFrm *pBoss = FindFtnBossFrm();
301 422 : if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()->
302 211 : GetFtn().IsEndNote() ) )
303 22 : return 0;
304 :
305 189 : SWAP_IF_SWAPPED( this )
306 :
307 189 : SwTwips nHeight = pRef->IsInFtnConnect() ?
308 189 : 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() );
309 189 : if( nHeight )
310 : {
311 : // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich
312 : // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text
313 : // eingeben.
314 189 : const SwFrm *pCont = pFtnFrm->GetUpper();
315 : //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf.
316 189 : SWRECTFN( pCont )
317 378 : SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
318 567 : (Frm().*fnRect->fnGetTop)() );
319 :
320 : #if OSL_DEBUG_LEVEL > 0
321 : if( nTmp < 0 )
322 : {
323 : bool bInvalidPos = false;
324 : const SwLayoutFrm* pTmp = GetUpper();
325 : while( !bInvalidPos && pTmp )
326 : {
327 : bInvalidPos = !pTmp->GetValidPosFlag() ||
328 : !pTmp->Lower()->GetValidPosFlag();
329 : if( pTmp == pCont )
330 : break;
331 : pTmp = pTmp->GetUpper();
332 : }
333 : OSL_ENSURE( bInvalidPos, "Hanging below FtnCont" );
334 : }
335 : #endif
336 :
337 189 : if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
338 : {
339 : //Wachstumspotential den Containers.
340 189 : if ( !pRef->IsInFtnConnect() )
341 : {
342 53 : SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight );
343 53 : nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, true );
344 : }
345 : else
346 136 : nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, true );
347 :
348 189 : nHeight += nTmp;
349 189 : if( nHeight < 0 )
350 0 : nHeight = 0;
351 : }
352 : else
353 : { // The container has to shrink
354 0 : nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight);
355 0 : if( nTmp > 0 )
356 0 : nHeight = nTmp;
357 : else
358 0 : nHeight = 0;
359 : }
360 : }
361 :
362 189 : UNDO_SWAP( this )
363 :
364 189 : return nHeight;
365 : }
366 :
367 87 : SwTxtFrm *SwTxtFrm::FindQuoVadisFrm()
368 : {
369 : // Erstmal feststellen, ob wir in einem FtnFrm stehen:
370 87 : if( GetIndPrev() || !IsInFtn() )
371 0 : return 0;
372 :
373 : // Zum Vorgaenger-FtnFrm
374 87 : SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster();
375 87 : if( !pFtnFrm )
376 87 : return 0;
377 :
378 : // Nun den letzten Cntnt:
379 0 : const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt();
380 0 : if( !pCnt )
381 0 : return NULL;
382 : const SwCntntFrm *pLast;
383 0 : do
384 0 : { pLast = pCnt;
385 0 : pCnt = pCnt->GetNextCntntFrm();
386 0 : } while( pCnt && pFtnFrm->IsAnLower( pCnt ) );
387 0 : return (SwTxtFrm*)pLast;
388 : }
389 :
390 17876 : void SwTxtFrm::RemoveFtn( const sal_Int32 nStart, const sal_Int32 nLen )
391 : {
392 17876 : if ( !IsFtnAllowed() )
393 4035 : return;
394 :
395 13841 : SwpHints *pHints = GetTxtNode()->GetpSwpHints();
396 13841 : if( !pHints )
397 78 : return;
398 :
399 13763 : bool bRollBack = nLen != COMPLETE_STRING;
400 13763 : sal_uInt16 nSize = pHints->Count();
401 : sal_Int32 nEnd;
402 : SwTxtFrm* pSource;
403 13763 : if( bRollBack )
404 : {
405 114 : nEnd = nStart + nLen;
406 114 : pSource = GetFollow();
407 114 : if( !pSource )
408 0 : return;
409 : }
410 : else
411 : {
412 13649 : nEnd = COMPLETE_STRING;
413 13649 : pSource = this;
414 : }
415 :
416 13763 : if( nSize )
417 : {
418 13761 : SwPageFrm* pUpdate = NULL;
419 13761 : bool bRemove = false;
420 13761 : SwFtnBossFrm *pFtnBoss = 0;
421 13761 : SwFtnBossFrm *pEndBoss = 0;
422 : bool bFtnEndDoc
423 13761 : = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos;
424 58542 : for ( sal_uInt16 i = nSize; i; )
425 : {
426 31131 : SwTxtAttr *pHt = pHints->GetTextHint(--i);
427 31131 : if ( RES_TXTATR_FTN != pHt->Which() )
428 31020 : continue;
429 :
430 111 : const sal_Int32 nIdx = *pHt->GetStart();
431 111 : if( nStart > nIdx )
432 111 : break;
433 :
434 0 : if( nEnd >= nIdx )
435 : {
436 0 : SwTxtFtn *pFtn = (SwTxtFtn*)pHt;
437 0 : const bool bEndn = pFtn->GetFtn().IsEndNote();
438 :
439 0 : if( bEndn )
440 : {
441 0 : if( !pEndBoss )
442 0 : pEndBoss = pSource->FindFtnBossFrm();
443 : }
444 : else
445 : {
446 0 : if( !pFtnBoss )
447 : {
448 0 : pFtnBoss = pSource->FindFtnBossFrm( true );
449 0 : if( pFtnBoss->GetUpper()->IsSctFrm() )
450 : {
451 : SwSectionFrm* pSect = (SwSectionFrm*)
452 0 : pFtnBoss->GetUpper();
453 0 : if( pSect->IsFtnAtEnd() )
454 0 : bFtnEndDoc = false;
455 : }
456 : }
457 : }
458 :
459 : // Wir loeschen nicht, sondern wollen die Ftn verschieben.
460 : // Drei Faelle koennen auftreten:
461 : // 1) Es gibt weder Follow noch PrevFollow
462 : // -> RemoveFtn() (vielleicht sogar ein OSL_ENSURE(wert)
463 : // 2) nStart > GetOfst, ich habe einen Follow
464 : // -> Ftn wandert in den Follow
465 : // 3) nStart < GetOfst, ich bin ein Follow
466 : // -> Ftn wandert in den PrevFollow
467 : // beide muessen auf einer Seite/in einer Spalte stehen.
468 :
469 : SwFtnFrm *pFtnFrm = bEndn ? pEndBoss->FindFtn( pSource, pFtn ) :
470 0 : pFtnBoss->FindFtn( pSource, pFtn );
471 :
472 0 : if( pFtnFrm )
473 : {
474 0 : const bool bEndDoc = bEndn || bFtnEndDoc;
475 0 : if( bRollBack )
476 : {
477 0 : while ( pFtnFrm )
478 : {
479 0 : pFtnFrm->SetRef( this );
480 0 : pFtnFrm = pFtnFrm->GetFollow();
481 0 : SetFtn( true );
482 : }
483 : }
484 0 : else if( GetFollow() )
485 : {
486 0 : SwCntntFrm *pDest = GetFollow();
487 0 : while( pDest->GetFollow() && ((SwTxtFrm*)pDest->
488 0 : GetFollow())->GetOfst() <= nIdx )
489 0 : pDest = pDest->GetFollow();
490 : OSL_ENSURE( !pDest->FindFtnBossFrm( !bEndn )->FindFtn(
491 : pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists");
492 :
493 : //Nicht ummelden sondern immer Moven.
494 : // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)>
495 0 : if ( bEndDoc ||
496 0 : !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) )
497 : )
498 : {
499 0 : SwPageFrm* pTmp = pFtnFrm->FindPageFrm();
500 0 : if( pUpdate && pUpdate != pTmp )
501 0 : pUpdate->UpdateFtnNum();
502 0 : pUpdate = pTmp;
503 0 : while ( pFtnFrm )
504 : {
505 0 : pFtnFrm->SetRef( pDest );
506 0 : pFtnFrm = pFtnFrm->GetFollow();
507 : }
508 : }
509 : else
510 : {
511 0 : pFtnBoss->MoveFtns( this, pDest, pFtn );
512 0 : bRemove = true;
513 : }
514 0 : ((SwTxtFrm*)pDest)->SetFtn( true );
515 :
516 : OSL_ENSURE( pDest->FindFtnBossFrm( !bEndn )->FindFtn( pDest,
517 : pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed");
518 : }
519 : else
520 : {
521 0 : if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
522 0 : !SwLayouter::Collecting( GetNode()->GetDoc(),
523 0 : pEndBoss->FindSctFrm(), NULL ) ) )
524 : {
525 0 : if( bEndn )
526 0 : pEndBoss->RemoveFtn( this, pFtn );
527 : else
528 0 : pFtnBoss->RemoveFtn( this, pFtn );
529 0 : bRemove = bRemove || !bEndDoc;
530 : OSL_ENSURE( bEndn ? !pEndBoss->FindFtn( this, pFtn ) :
531 : !pFtnBoss->FindFtn( this, pFtn ),
532 : "SwTxtFrm::RemoveFtn: can't get off that footnote" );
533 : }
534 : }
535 : }
536 : }
537 : }
538 13761 : if( pUpdate )
539 0 : pUpdate->UpdateFtnNum();
540 : // Wir bringen die Oszillation zum stehen:
541 13761 : if( bRemove && !bFtnEndDoc && HasPara() )
542 : {
543 0 : ValidateBodyFrm();
544 0 : ValidateFrm();
545 : }
546 : }
547 : // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen,
548 : // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset
549 : // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist
550 : // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig
551 : // der Follow-Offset manipuliert.
552 13763 : sal_Int32 nOldOfst = COMPLETE_STRING;
553 13763 : if( HasFollow() && nStart > GetOfst() )
554 : {
555 617 : nOldOfst = GetFollow()->GetOfst();
556 617 : GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
557 : }
558 13763 : pSource->CalcFtnFlag();
559 13763 : if( nOldOfst < COMPLETE_STRING )
560 616 : GetFollow()->ManipOfst( nOldOfst );
561 : }
562 :
563 : // false, wenn irgendetwas schief gegangen ist.
564 : // Es gibt eigentlich nur zwei Moeglichkeiten:
565 : // a) Die Ftn ist bereits vorhanden
566 : // => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde
567 : // b) Die Ftn ist nicht vorhanden
568 : // => dann wird sie fuer uns angelegt.
569 : // Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht,
570 : // spielt in diesem Zusammenhang keine Rolle.
571 : // Optimierungen bei Endnoten.
572 : // Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die
573 : // Ftn verschoben werden.
574 123 : void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine )
575 : {
576 : OSL_ENSURE( !IsVertical() || !IsSwapped(),
577 : "SwTxtFrm::ConnectFtn with swapped frame" );
578 :
579 123 : bFtn = true;
580 123 : bInFtnConnect = true; //Bloss zuruecksetzen!
581 123 : const bool bEnd = pFtn->GetFtn().IsEndNote();
582 :
583 : // We want to store this value, because it is needed as a fallback
584 : // in GetFtnLine(), if there is no paragraph information available
585 123 : mnFtnLine = nDeadLine;
586 :
587 : // Wir brauchen immer einen Boss (Spalte/Seite)
588 : SwSectionFrm *pSect;
589 123 : SwCntntFrm *pCntnt = this;
590 123 : if( bEnd && IsInSct() )
591 : {
592 14 : pSect = FindSctFrm();
593 14 : if( pSect->IsEndnAtEnd() )
594 0 : pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE );
595 14 : if( !pCntnt )
596 0 : pCntnt = this;
597 : }
598 :
599 123 : SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd );
600 :
601 : #if OSL_DEBUG_LEVEL > 1
602 : SwTwips nRstHeight = GetRstHeight();
603 : #endif
604 :
605 123 : pSect = pBoss->FindSctFrm();
606 38 : bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
607 170 : ( !( pSect && pSect->IsFtnAtEnd() ) &&
608 331 : FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos );
609 : //Ftn kann beim Follow angemeldet sein.
610 123 : SwCntntFrm *pSrcFrm = FindFtnRef( pFtn );
611 :
612 123 : if( bDocEnd )
613 : {
614 39 : if( pSect && pSrcFrm )
615 : {
616 9 : SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
617 9 : if( pFtnFrm && pFtnFrm->IsInSct() )
618 : {
619 0 : pBoss->RemoveFtn( pSrcFrm, pFtn );
620 0 : pSrcFrm = 0;
621 : }
622 : }
623 : }
624 84 : else if( bEnd && pSect )
625 : {
626 0 : SwFtnFrm *pFtnFrm = pSrcFrm ? pBoss->FindFtn( pSrcFrm, pFtn ) : NULL;
627 0 : if( pFtnFrm && !pFtnFrm->GetUpper() )
628 0 : pFtnFrm = NULL;
629 0 : SwDoc *pDoc = GetNode()->GetDoc();
630 0 : if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) )
631 : {
632 0 : if( !pSrcFrm )
633 : {
634 0 : SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,this,pFtn);
635 0 : SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 );
636 0 : ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
637 0 : GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
638 : }
639 0 : else if( pSrcFrm != this )
640 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
641 0 : bInFtnConnect = false;
642 0 : return;
643 : }
644 0 : else if( pSrcFrm )
645 : {
646 0 : SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
647 0 : if( !pFtnBoss->IsInSct() ||
648 0 : pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
649 : {
650 0 : pBoss->RemoveFtn( pSrcFrm, pFtn );
651 0 : pSrcFrm = 0;
652 : }
653 : }
654 : }
655 :
656 123 : if( bDocEnd || bEnd )
657 : {
658 39 : if( !pSrcFrm )
659 16 : pBoss->AppendFtn( this, pFtn );
660 23 : else if( pSrcFrm != this )
661 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
662 39 : bInFtnConnect = false;
663 39 : return;
664 : }
665 :
666 84 : SwSaveFtnHeight aHeight( pBoss, nDeadLine );
667 :
668 84 : if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden.
669 55 : pBoss->AppendFtn( this, pFtn );
670 : else
671 : {
672 29 : SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
673 29 : SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
674 :
675 29 : bool bBrutal = false;
676 :
677 29 : if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte.
678 : {
679 27 : SwFrm *pCont = pFtnFrm->GetUpper();
680 :
681 27 : SWRECTFN ( pCont )
682 54 : long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
683 81 : nDeadLine );
684 :
685 27 : if( nDiff >= 0 )
686 : {
687 : //Wenn die Fussnote bei einem Follow angemeldet ist, so ist
688 : //es jetzt an der Zeit sie umzumelden.
689 27 : if ( pSrcFrm != this )
690 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
691 : //Es steht Platz zur Verfuegung, also kann die Fussnote evtl.
692 : //wachsen.
693 27 : if ( pFtnFrm->GetFollow() && nDiff > 0 )
694 : {
695 0 : SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
696 0 : pBoss->RearrangeFtns( nDeadLine, false, pFtn );
697 0 : ValidateBodyFrm();
698 0 : ValidateFrm();
699 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
700 0 : if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
701 : //Damit uns nix durch die Lappen geht.
702 0 : pSh->InvalidateWindows( pCont->Frm() );
703 : }
704 27 : bInFtnConnect = false;
705 27 : return;
706 : }
707 : else
708 0 : bBrutal = true;
709 : }
710 : else
711 : {
712 : // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig.
713 2 : SwFrm* pTmp = this;
714 4 : while( pTmp->GetNext() && pSrcFrm != pTmp )
715 0 : pTmp = pTmp->GetNext();
716 2 : if( pSrcFrm == pTmp )
717 2 : bBrutal = true;
718 : else
719 : { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf
720 : // der Seite schon einen FtnContainer gibt, hilft nur die brutale
721 : // Methode
722 0 : if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() )
723 0 : bBrutal = true;
724 : // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)>
725 0 : else if ( !pFtnFrm->GetPrev() ||
726 0 : pFtnBoss->IsBefore( pBoss )
727 : )
728 : {
729 0 : SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd );
730 0 : pSrcBoss->MoveFtns( pSrcFrm, this, pFtn );
731 : }
732 : else
733 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
734 : }
735 : }
736 :
737 : // Die brutale Loesung: Fussnote entfernen und appenden.
738 : // Es muss SetFtnDeadLine() gerufen werden, weil nach
739 : // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche
740 : // eingestellt werden kann.
741 2 : if( bBrutal )
742 : {
743 2 : pBoss->RemoveFtn( pSrcFrm, pFtn, false );
744 : SwSaveFtnHeight *pHeight = bEnd ? NULL :
745 2 : new SwSaveFtnHeight( pBoss, nDeadLine );
746 2 : pBoss->AppendFtn( this, pFtn );
747 2 : delete pHeight;
748 : }
749 : }
750 :
751 : // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen,
752 : // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch
753 : // nicht kalkuliert worden ist.
754 57 : if( !pSect || !pSect->Growable() )
755 : {
756 : // Umgebung validieren, um Oszillationen zu verhindern.
757 57 : SwSaveFtnHeight aNochmal( pBoss, nDeadLine );
758 57 : ValidateBodyFrm();
759 57 : pBoss->RearrangeFtns( nDeadLine, true );
760 57 : ValidateFrm();
761 : }
762 0 : else if( pSect->IsFtnAtEnd() )
763 : {
764 0 : ValidateBodyFrm();
765 0 : ValidateFrm();
766 : }
767 :
768 : #if OSL_DEBUG_LEVEL > 1
769 : // pFtnFrm kann sich durch Calc veraendert haben ...
770 : SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn );
771 : if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) )
772 : {
773 : int bla = 5;
774 : (void)bla;
775 : }
776 : nRstHeight = GetRstHeight();
777 : (void)nRstHeight;
778 : #endif
779 57 : bInFtnConnect = false;
780 57 : return;
781 : }
782 :
783 : // Die Portion fuer die Ftn-Referenz im Text
784 123 : SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf,
785 : SwTxtAttr *pHint )
786 : {
787 : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
788 : "NewFtnPortion with unswapped frame" );
789 :
790 123 : if( !pFrm->IsFtnAllowed() )
791 0 : return 0;
792 :
793 123 : SwTxtFtn *pFtn = (SwTxtFtn*)pHint;
794 123 : SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
795 123 : SwDoc *pDoc = pFrm->GetNode()->GetDoc();
796 :
797 123 : if( rInf.IsTest() )
798 0 : return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFtn );
799 :
800 123 : SWAP_IF_SWAPPED( pFrm )
801 :
802 : KSHORT nReal;
803 : {
804 123 : KSHORT nOldReal = pCurr->GetRealHeight();
805 123 : KSHORT nOldAscent = pCurr->GetAscent();
806 123 : KSHORT nOldHeight = pCurr->Height();
807 123 : ((SwTxtFormatter*)this)->CalcRealHeight();
808 123 : nReal = pCurr->GetRealHeight();
809 123 : if( nReal < nOldReal )
810 0 : nReal = nOldReal;
811 123 : pCurr->SetRealHeight( nOldReal );
812 123 : pCurr->Height( nOldHeight );
813 123 : pCurr->SetAscent( nOldAscent );
814 : }
815 :
816 123 : SwTwips nLower = Y() + nReal;
817 :
818 123 : const bool bVertical = pFrm->IsVertical();
819 123 : if( bVertical )
820 0 : nLower = pFrm->SwitchHorizontalToVertical( nLower );
821 :
822 123 : nLower = lcl_GetFtnLower( pFrm, nLower );
823 :
824 : //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix
825 : //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die
826 : //Ftn wegwerfen und neu erzeugen.
827 :
828 123 : if( !rInf.IsQuick() )
829 123 : pFrm->ConnectFtn( pFtn, nLower );
830 :
831 123 : SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn );
832 123 : SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() );
833 123 : SwFtnFrm *pFtnFrm = NULL;
834 123 : if( pScrFrm )
835 123 : pFtnFrm = pBoss->FindFtn( pScrFrm, pFtn );
836 :
837 : // Wir erkundigen uns, ob durch unser Append irgendeine
838 : // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet
839 : // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten
840 : // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr.
841 : // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die
842 : // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte.
843 : // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt,
844 : // so sollte die Ftn2-Referenz auch auf die naechste wandern.
845 123 : if( !rFtn.IsEndNote() )
846 : {
847 85 : SwSectionFrm *pSct = pBoss->FindSctFrm();
848 85 : bool bAtSctEnd = pSct && pSct->IsFtnAtEnd();
849 85 : if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd )
850 : {
851 84 : SwFrm* pFtnCont = pBoss->FindFtnCont();
852 : // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine
853 : // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte
854 : // ist, duerfen wir ausweichen
855 170 : if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
856 66 : ( !bAtSctEnd && pFrm->GetIndPrev() ) ||
857 2 : ( pSct && pBoss->GetPrev() ) ) )
858 : {
859 53 : if( !pFtnCont )
860 : {
861 0 : rInf.SetStop( true );
862 0 : UNDO_SWAP( pFrm )
863 0 : return 0;
864 : }
865 : else
866 : {
867 : // Es darf keine Fussnotencontainer in spaltigen Bereichen und
868 : // gleichzeitig auf der Seite/Seitenspalte geben
869 53 : if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich?
870 : {
871 5 : SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( true );
872 5 : SwFtnContFrm* pFtnC = pTmp->FindFtnCont();
873 5 : if( pFtnC )
874 : {
875 0 : SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower();
876 0 : if( pTmpFrm && *pTmpFrm < pFtn )
877 : {
878 0 : rInf.SetStop( true );
879 0 : UNDO_SWAP( pFrm )
880 0 : return 0;
881 : }
882 : }
883 : }
884 : // Ist dies die letzte passende Zeile?
885 53 : SwTwips nTmpBot = Y() + nReal * 2;
886 :
887 53 : if( bVertical )
888 0 : nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
889 :
890 53 : SWRECTFN( pFtnCont )
891 :
892 : const long nDiff = (*fnRect->fnYDiff)(
893 106 : (pFtnCont->Frm().*fnRect->fnGetTop)(),
894 159 : nTmpBot );
895 :
896 53 : if( pScrFrm && nDiff < 0 )
897 : {
898 0 : if( pFtnFrm )
899 : {
900 0 : SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
901 0 : if( pFtnBoss != pBoss )
902 : {
903 : // Wir sind in der letzte Zeile und die Fussnote
904 : // ist auf eine andere Seite gewandert, dann wollen
905 : // wir mit ...
906 0 : rInf.SetStop( true );
907 0 : UNDO_SWAP( pFrm )
908 0 : return 0;
909 : }
910 : }
911 : }
912 : }
913 : }
914 : }
915 : }
916 : // Endlich: FtnPortion anlegen und raus hier...
917 : SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ),
918 123 : pFtn, nReal );
919 123 : rInf.SetFtnInside( true );
920 :
921 123 : UNDO_SWAP( pFrm )
922 :
923 123 : return pRet;
924 : }
925 :
926 : // Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich
927 103 : SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const
928 : {
929 : OSL_ENSURE( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(),
930 : "This is the wrong place for a ftnnumber" );
931 206 : if( rInf.GetTxtStart() != nStart ||
932 103 : rInf.GetTxtStart() != rInf.GetIdx() )
933 0 : return 0;
934 :
935 103 : const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm();
936 103 : const SwTxtFtn* pFtn = pFtnFrm->GetAttr();
937 :
938 : // Aha, wir sind also im Fussnotenbereich
939 103 : SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
940 :
941 103 : SwDoc *pDoc = pFrm->GetNode()->GetDoc();
942 103 : OUString aFtnTxt( rFtn.GetViewNumStr( *pDoc, true ));
943 :
944 : const SwEndNoteInfo* pInfo;
945 103 : if( rFtn.IsEndNote() )
946 16 : pInfo = &pDoc->GetEndNoteInfo();
947 : else
948 87 : pInfo = &pDoc->GetFtnInfo();
949 103 : const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet();
950 :
951 103 : const SwAttrSet* pParSet = &rInf.GetCharAttr();
952 103 : const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess();
953 103 : SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
954 :
955 : // #i37142#
956 : // Underline style of paragraph font should not be considered
957 : // Overline style of paragraph font should not be considered
958 : // Weight style of paragraph font should not be considered
959 : // Posture style of paragraph font should not be considered
960 : // See also #i18463# and SwTxtFormatter::NewNumberPortion()
961 103 : pNumFnt->SetUnderline( UNDERLINE_NONE );
962 103 : pNumFnt->SetOverline( UNDERLINE_NONE );
963 103 : pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
964 103 : pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
965 103 : pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
966 103 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
967 103 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
968 103 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
969 :
970 103 : pNumFnt->SetDiffFnt(&rSet, pIDSA );
971 103 : pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
972 :
973 103 : SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt );
974 103 : pNewPor->SetLeft( !pFrm->IsRightToLeft() );
975 103 : return pNewPor;
976 : }
977 :
978 : /*************************************************************************
979 : * SwTxtFormatter::NewErgoSumPortion()
980 : *************************************************************************/
981 0 : OUString lcl_GetPageNumber( const SwPageFrm* pPage )
982 : {
983 : OSL_ENSURE( pPage, "GetPageNumber: Homeless TxtFrm" );
984 0 : MSHORT nVirtNum = pPage->GetVirtPageNum();
985 0 : const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
986 0 : return rNum.GetNumStr( nVirtNum );
987 : }
988 :
989 103 : SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const
990 : {
991 : // Wir koennen nicht davon ausgehen, dass wir ein Follow sind
992 : // 7983: GetIdx() nicht nStart
993 412 : if( !pFrm->IsInFtn() || pFrm->GetPrev() ||
994 412 : rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
995 103 : pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
996 16 : return 0;
997 :
998 : // Aha, wir sind also im Fussnotenbereich
999 87 : const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1000 87 : SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
1001 87 : if( !pQuoFrm )
1002 87 : return 0;
1003 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
1004 0 : const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
1005 0 : if( pPage == pQuoFrm->FindPageFrm() )
1006 0 : return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht
1007 0 : const OUString aPage = lcl_GetPageNumber( pPage );
1008 0 : SwParaPortion *pPara = pQuoFrm->GetPara();
1009 0 : if( pPara )
1010 0 : pPara->SetErgoSumNum( aPage );
1011 0 : if( rFtnInfo.aErgoSum.isEmpty() )
1012 0 : return 0;
1013 : SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum,
1014 0 : lcl_GetPageNumber( pQuoPage ) );
1015 0 : return pErgo;
1016 : }
1017 :
1018 185 : sal_Int32 SwTxtFormatter::FormatQuoVadis( const sal_Int32 nOffset )
1019 : {
1020 : OSL_ENSURE( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
1021 : "SwTxtFormatter::FormatQuoVadis with swapped frame" );
1022 :
1023 185 : if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
1024 20 : return nOffset;
1025 :
1026 165 : const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow();
1027 165 : if( !pErgoFrm && pFrm->HasFollow() )
1028 0 : pErgoFrm = pFrm->GetFollow();
1029 165 : if( !pErgoFrm )
1030 165 : return nOffset;
1031 :
1032 0 : if( pErgoFrm == pFrm->GetNext() )
1033 : {
1034 0 : SwFrm *pCol = pFrm->FindColFrm();
1035 0 : while( pCol && !pCol->GetNext() )
1036 0 : pCol = pCol->GetUpper()->FindColFrm();
1037 0 : if( pCol )
1038 0 : return nOffset;
1039 : }
1040 : else
1041 : {
1042 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
1043 0 : const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm();
1044 0 : if( pPage == pErgoPage )
1045 0 : return nOffset; // Wenn der ErgoSum auf der selben Seite steht
1046 : }
1047 :
1048 0 : SwTxtFormatInfo &rInf = GetInfo();
1049 0 : const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1050 0 : if( rFtnInfo.aQuoVadis.isEmpty() )
1051 0 : return nOffset;
1052 :
1053 : // Ein Wort zu QuoVadis/ErgoSum:
1054 : // Fuer diese Texte wird der am Absatz eingestellte Font verwendet.
1055 : // Wir initialisieren uns also:
1056 : // ResetFont();
1057 0 : FeedInf( rInf );
1058 0 : SeekStartAndChg( rInf, true );
1059 0 : if( GetRedln() && pCurr->HasRedline() )
1060 0 : GetRedln()->Seek( *pFnt, nOffset, 0 );
1061 :
1062 : // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen
1063 : // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen.
1064 : // Erst mal sehen, ob es so schlimm ist:
1065 0 : SwLinePortion *pPor = pCurr->GetFirstPortion();
1066 0 : KSHORT nLastLeft = 0;
1067 0 : while( pPor )
1068 : {
1069 0 : if ( pPor->IsFlyPortion() )
1070 0 : nLastLeft = ( (SwFlyPortion*) pPor)->Fix() +
1071 0 : ( (SwFlyPortion*) pPor)->Width();
1072 0 : pPor = pPor->GetPortion();
1073 : }
1074 : // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten
1075 : // Stelle umbricht, also beeinflussen wir die Width.
1076 : // nLastLeft ist jetzt quasi der rechte Rand.
1077 0 : const KSHORT nOldRealWidth = rInf.RealWidth();
1078 0 : rInf.RealWidth( nOldRealWidth - nLastLeft );
1079 :
1080 0 : OUString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
1081 0 : SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo );
1082 0 : pQuo->SetAscent( rInf.GetAscent() );
1083 0 : pQuo->Height( rInf.GetTxtHeight() );
1084 0 : pQuo->Format( rInf );
1085 0 : sal_uInt16 nQuoWidth = pQuo->Width();
1086 0 : SwLinePortion* pCurrPor = pQuo;
1087 :
1088 0 : while ( rInf.GetRest() )
1089 : {
1090 0 : SwLinePortion* pFollow = rInf.GetRest();
1091 0 : rInf.SetRest( 0 );
1092 0 : pCurrPor->Move( rInf );
1093 :
1094 : OSL_ENSURE( pFollow->IsQuoVadisPortion(),
1095 : "Quo Vadis, rest of QuoVadisPortion" );
1096 :
1097 : // format the rest and append it to the other QuoVadis parts
1098 0 : pFollow->Format( rInf );
1099 0 : nQuoWidth = nQuoWidth + pFollow->Width();
1100 :
1101 0 : pCurrPor->Append( pFollow );
1102 0 : pCurrPor = pFollow;
1103 : }
1104 :
1105 0 : nLastLeft = nOldRealWidth - nQuoWidth;
1106 0 : Right( Right() - nQuoWidth );
1107 :
1108 0 : SWAP_IF_NOT_SWAPPED( pFrm )
1109 :
1110 0 : const sal_Int32 nRet = FormatLine( nStart );
1111 :
1112 0 : UNDO_SWAP( pFrm )
1113 :
1114 0 : Right( rInf.Left() + nOldRealWidth - 1 );
1115 :
1116 0 : nLastLeft = nOldRealWidth - pCurr->Width();
1117 0 : FeedInf( rInf );
1118 :
1119 : // Es kann durchaus sein, dass am Ende eine Marginportion steht,
1120 : // die beim erneuten Aufspannen nur Aerger bereiten wuerde.
1121 0 : pPor = pCurr->FindLastPortion();
1122 0 : SwGluePortion *pGlue = pPor->IsMarginPortion() ?
1123 0 : (SwMarginPortion*) pPor : 0;
1124 0 : if( pGlue )
1125 : {
1126 0 : pGlue->Height( 0 );
1127 0 : pGlue->Width( 0 );
1128 0 : pGlue->SetLen( 0 );
1129 0 : pGlue->SetAscent( 0 );
1130 0 : pGlue->SetPortion( NULL );
1131 0 : pGlue->SetFixWidth(0);
1132 : }
1133 :
1134 : // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer,
1135 : // dass der QuoVadis-Text rechts erscheint:
1136 0 : nLastLeft = nLastLeft - nQuoWidth;
1137 0 : if( nLastLeft )
1138 : {
1139 0 : if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand
1140 : {
1141 0 : switch( GetAdjust() )
1142 : {
1143 : case SVX_ADJUST_BLOCK:
1144 : {
1145 0 : if( !pCurr->GetLen() ||
1146 0 : CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1))
1147 0 : nLastLeft = pQuo->GetAscent();
1148 0 : nQuoWidth = nQuoWidth + nLastLeft;
1149 0 : break;
1150 : }
1151 : case SVX_ADJUST_RIGHT:
1152 : {
1153 0 : nLastLeft = pQuo->GetAscent();
1154 0 : nQuoWidth = nQuoWidth + nLastLeft;
1155 0 : break;
1156 : }
1157 : case SVX_ADJUST_CENTER:
1158 : {
1159 0 : nQuoWidth = nQuoWidth + pQuo->GetAscent();
1160 0 : long nDiff = nLastLeft - nQuoWidth;
1161 0 : if( nDiff < 0 )
1162 : {
1163 0 : nLastLeft = pQuo->GetAscent();
1164 0 : nQuoWidth = (sal_uInt16)(-nDiff + nLastLeft);
1165 : }
1166 : else
1167 : {
1168 0 : nQuoWidth = 0;
1169 0 : nLastLeft = sal_uInt16(( pQuo->GetAscent() + nDiff ) / 2);
1170 : }
1171 0 : break;
1172 : }
1173 : default:
1174 0 : nQuoWidth = nQuoWidth + nLastLeft;
1175 : }
1176 : }
1177 : else
1178 0 : nQuoWidth = nQuoWidth + nLastLeft;
1179 0 : if( nLastLeft )
1180 : {
1181 0 : pGlue = new SwGluePortion(0);
1182 0 : pGlue->Width( nLastLeft );
1183 0 : pPor->Append( pGlue );
1184 0 : pPor = pPor->GetPortion();
1185 : }
1186 : }
1187 :
1188 : // Jetzt aber: die QuoVadis-Portion wird angedockt:
1189 0 : pCurrPor = pQuo;
1190 0 : while ( pCurrPor )
1191 : {
1192 : // pPor->Append deletes the pPortoin pointer of pPor. Therefore
1193 : // we have to keep a pointer to the next portion
1194 0 : pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion();
1195 0 : pPor->Append( pCurrPor );
1196 0 : pPor = pPor->GetPortion();
1197 0 : pCurrPor = pQuo;
1198 : }
1199 :
1200 0 : pCurr->Width( pCurr->Width() + KSHORT( nQuoWidth ) );
1201 :
1202 : // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt
1203 : // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig
1204 : // einen kleineren Font eingestellt als der vom QuoVadis-Text ...
1205 0 : CalcAdjustLine( pCurr );
1206 :
1207 : // Uff...
1208 0 : return nRet;
1209 : }
1210 :
1211 : // MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand
1212 : // reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen
1213 : // zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden.
1214 : // Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn-
1215 : // Oszillationen verwendet.
1216 0 : void SwTxtFormatter::MakeDummyLine()
1217 : {
1218 0 : KSHORT nRstHeight = GetFrmRstHeight();
1219 0 : if( pCurr && nRstHeight > pCurr->Height() )
1220 : {
1221 0 : SwLineLayout *pLay = new SwLineLayout;
1222 0 : nRstHeight = nRstHeight - pCurr->Height();
1223 0 : pLay->Height( nRstHeight );
1224 0 : pLay->SetAscent( nRstHeight );
1225 0 : Insert( pLay );
1226 0 : Next();
1227 : }
1228 0 : }
1229 :
1230 : class SwFtnSave
1231 : {
1232 : SwTxtSizeInfo *pInf;
1233 : SwFont *pFnt;
1234 : SwFont *pOld;
1235 : public:
1236 : SwFtnSave( const SwTxtSizeInfo &rInf,
1237 : const SwTxtFtn *pTxtFtn,
1238 : const bool bApplyGivenScriptType,
1239 : const sal_uInt8 nGivenScriptType );
1240 : ~SwFtnSave();
1241 : };
1242 :
1243 213 : SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf,
1244 : const SwTxtFtn* pTxtFtn,
1245 : const bool bApplyGivenScriptType,
1246 : const sal_uInt8 nGivenScriptType )
1247 : : pInf( &((SwTxtSizeInfo&)rInf) )
1248 : , pFnt( 0 )
1249 213 : , pOld( 0 )
1250 : {
1251 213 : if( pTxtFtn && rInf.GetTxtFrm() )
1252 : {
1253 213 : pFnt = ((SwTxtSizeInfo&)rInf).GetFont();
1254 213 : pOld = new SwFont( *pFnt );
1255 213 : pOld->GetTox() = pFnt->GetTox();
1256 213 : pFnt->GetTox() = 0;
1257 213 : SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
1258 213 : const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
1259 :
1260 : // #i98418#
1261 213 : if ( bApplyGivenScriptType )
1262 : {
1263 213 : pFnt->SetActual( nGivenScriptType );
1264 : }
1265 : else
1266 : {
1267 : // examine text and set script
1268 0 : OUString aTmpStr( rFtn.GetViewNumStr( *pDoc ) );
1269 0 : pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
1270 : }
1271 :
1272 : const SwEndNoteInfo* pInfo;
1273 213 : if( rFtn.IsEndNote() )
1274 61 : pInfo = &pDoc->GetEndNoteInfo();
1275 : else
1276 152 : pInfo = &pDoc->GetFtnInfo();
1277 213 : const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
1278 213 : pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() );
1279 :
1280 : // we reduce footnote size, if we are inside a double line portion
1281 213 : if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() )
1282 : {
1283 0 : Size aSize = pFnt->GetSize( pFnt->GetActual() );
1284 0 : pFnt->SetSize( Size( (long)aSize.Width() / 2,
1285 0 : (long)aSize.Height() / 2 ),
1286 0 : pFnt->GetActual() );
1287 : }
1288 :
1289 : // set the correct rotation at the footnote font
1290 : const SfxPoolItem* pItem;
1291 213 : if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1292 213 : true, &pItem ))
1293 0 : pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(),
1294 0 : rInf.GetTxtFrm()->IsVertical() );
1295 :
1296 213 : pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1297 :
1298 213 : if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
1299 213 : true, &pItem ))
1300 0 : pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) );
1301 : }
1302 : else
1303 0 : pFnt = NULL;
1304 213 : }
1305 :
1306 213 : SwFtnSave::~SwFtnSave()
1307 : {
1308 213 : if( pFnt )
1309 : {
1310 : // SwFont zurueckstellen
1311 213 : *pFnt = *pOld;
1312 213 : pFnt->GetTox() = pOld->GetTox();
1313 213 : pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1314 213 : delete pOld;
1315 : }
1316 213 : }
1317 :
1318 123 : SwFtnPortion::SwFtnPortion( const OUString &rExpand,
1319 : SwTxtFtn *pFootn, KSHORT nReal )
1320 : : SwFldPortion( rExpand, 0 )
1321 : , pFtn(pFootn)
1322 : , nOrigHeight( nReal )
1323 : // #i98418#
1324 : , mbPreferredScriptTypeSet( false )
1325 123 : , mnPreferredScriptType( SW_LATIN )
1326 : {
1327 123 : SetLen(1);
1328 123 : SetWhichPor( POR_FTN );
1329 123 : }
1330 :
1331 502 : bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, OUString &rTxt ) const
1332 : {
1333 502 : rTxt = aExpand;
1334 502 : return true;
1335 : }
1336 :
1337 123 : bool SwFtnPortion::Format( SwTxtFormatInfo &rInf )
1338 : {
1339 : // #i98418#
1340 : // SwFtnSave aFtnSave( rInf, pFtn );
1341 123 : SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1342 : // the idx is manipulated in SwExpandPortion::Format
1343 : // this flag indicates, that a footnote is allowed to trigger
1344 : // an underflow during SwTxtGuess::Guess
1345 123 : rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
1346 123 : const bool bFull = SwFldPortion::Format( rInf );
1347 123 : rInf.SetFakeLineStart( false );
1348 123 : SetAscent( rInf.GetAscent() );
1349 123 : Height( rInf.GetTxtHeight() );
1350 123 : rInf.SetFtnDone( !bFull );
1351 123 : if( !bFull )
1352 123 : rInf.SetParaFtn();
1353 123 : return bFull;
1354 : }
1355 :
1356 90 : void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const
1357 : {
1358 : // #i98418#
1359 : // SwFtnSave aFtnSave( rInf, pFtn );
1360 90 : SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1361 90 : rInf.DrawViewOpt( *this, POR_FTN );
1362 90 : SwExpandPortion::Paint( rInf );
1363 90 : }
1364 :
1365 0 : SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const
1366 : {
1367 : // #i98418#
1368 : // SwFtnSave aFtnSave( rInfo, pFtn );
1369 0 : SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1370 0 : return SwExpandPortion::GetTxtSize( rInfo );
1371 : }
1372 :
1373 : // #i98418#
1374 123 : void SwFtnPortion::SetPreferredScriptType( sal_uInt8 nPreferredScriptType )
1375 : {
1376 123 : mbPreferredScriptTypeSet = true;
1377 123 : mnPreferredScriptType = nPreferredScriptType;
1378 123 : }
1379 :
1380 0 : SwFldPortion *SwQuoVadisPortion::Clone( const OUString &rExpand ) const
1381 : {
1382 0 : return new SwQuoVadisPortion( rExpand, aErgo );
1383 : }
1384 :
1385 0 : SwQuoVadisPortion::SwQuoVadisPortion( const OUString &rExp, const OUString& rStr )
1386 0 : : SwFldPortion( rExp ), aErgo(rStr)
1387 : {
1388 0 : SetLen(0);
1389 0 : SetWhichPor( POR_QUOVADIS );
1390 0 : }
1391 :
1392 0 : bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf )
1393 : {
1394 : // erster Versuch, vielleicht passt der Text
1395 0 : CheckScript( rInf );
1396 0 : bool bFull = SwFldPortion::Format( rInf );
1397 0 : SetLen( 0 );
1398 :
1399 0 : if( bFull )
1400 : {
1401 : // zweiter Versuch, wir kuerzen den String:
1402 0 : aExpand = "...";
1403 0 : bFull = SwFldPortion::Format( rInf );
1404 0 : SetLen( 0 );
1405 0 : if( bFull )
1406 : // dritter Versuch, es langt: jetzt wird gestaucht:
1407 0 : Width( sal_uInt16(rInf.Width() - rInf.X()) );
1408 :
1409 : // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
1410 0 : if( rInf.GetRest() )
1411 : {
1412 0 : delete rInf.GetRest();
1413 0 : rInf.SetRest( 0 );
1414 : }
1415 : }
1416 0 : return bFull;
1417 : }
1418 :
1419 0 : bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, OUString &rTxt ) const
1420 : {
1421 0 : rTxt = aExpand;
1422 : // if this QuoVadisPortion has a follow, the follow is responsible for
1423 : // the ergo text.
1424 0 : if ( ! HasFollow() )
1425 0 : rTxt += aErgo;
1426 0 : return true;
1427 : }
1428 :
1429 0 : void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
1430 : {
1431 0 : OUString aString( aExpand );
1432 0 : aString += aErgo;
1433 0 : rPH.Special( GetLen(), aString, GetWhichPor() );
1434 0 : }
1435 :
1436 0 : void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const
1437 : {
1438 : // Wir wollen _immer_ per DrawStretchText ausgeben,
1439 : // weil nErgo schnell mal wechseln kann.
1440 0 : if( PrtWidth() )
1441 : {
1442 0 : rInf.DrawViewOpt( *this, POR_QUOVADIS );
1443 0 : SwTxtSlot aDiffTxt( &rInf, this, true, false );
1444 0 : SwFontSave aSave( rInf, pFnt );
1445 0 : rInf.DrawText( *this, rInf.GetLen(), true );
1446 : }
1447 0 : }
1448 :
1449 0 : SwFldPortion *SwErgoSumPortion::Clone( const OUString &rExpand ) const
1450 : {
1451 0 : return new SwErgoSumPortion( rExpand, OUString() );
1452 : }
1453 :
1454 0 : SwErgoSumPortion::SwErgoSumPortion(const OUString &rExp, const OUString& rStr)
1455 0 : : SwFldPortion( rExp )
1456 : {
1457 0 : SetLen(0);
1458 0 : aExpand += rStr;
1459 :
1460 : // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text
1461 0 : aExpand += " ";
1462 0 : SetWhichPor( POR_ERGOSUM );
1463 0 : }
1464 :
1465 0 : sal_Int32 SwErgoSumPortion::GetCrsrOfst( const KSHORT ) const
1466 : {
1467 0 : return 0;
1468 : }
1469 :
1470 0 : bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf )
1471 : {
1472 0 : const bool bFull = SwFldPortion::Format( rInf );
1473 0 : SetLen( 0 );
1474 0 : rInf.SetErgoDone( true );
1475 :
1476 : // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
1477 0 : if( bFull && rInf.GetRest() )
1478 : {
1479 0 : delete rInf.GetRest();
1480 0 : rInf.SetRest( 0 );
1481 : }
1482 :
1483 : // We return false in order to get some text into the current line,
1484 : // even if it's full (better than looping)
1485 0 : return false;
1486 : }
1487 :
1488 0 : void SwParaPortion::SetErgoSumNum( const OUString& rErgo )
1489 : {
1490 0 : SwLineLayout *pLay = this;
1491 0 : while( pLay->GetNext() )
1492 : {
1493 0 : pLay = pLay->GetNext();
1494 : }
1495 0 : SwLinePortion *pPor = pLay;
1496 0 : SwQuoVadisPortion *pQuo = 0;
1497 0 : while( pPor && !pQuo )
1498 : {
1499 0 : if ( pPor->IsQuoVadisPortion() )
1500 0 : pQuo = (SwQuoVadisPortion*)pPor;
1501 0 : pPor = pPor->GetPortion();
1502 : }
1503 0 : if( pQuo )
1504 0 : pQuo->SetNumber( rErgo );
1505 0 : }
1506 :
1507 : /*************************************************************************
1508 : * SwParaPortion::UpdateQuoVadis()
1509 : *
1510 : * Wird im SwTxtFrm::Prepare() gerufen
1511 : *************************************************************************/
1512 :
1513 27 : bool SwParaPortion::UpdateQuoVadis( const OUString &rQuo )
1514 : {
1515 27 : SwLineLayout *pLay = this;
1516 54 : while( pLay->GetNext() )
1517 : {
1518 0 : pLay = pLay->GetNext();
1519 : }
1520 27 : SwLinePortion *pPor = pLay;
1521 27 : SwQuoVadisPortion *pQuo = 0;
1522 112 : while( pPor && !pQuo )
1523 : {
1524 58 : if ( pPor->IsQuoVadisPortion() )
1525 0 : pQuo = (SwQuoVadisPortion*)pPor;
1526 58 : pPor = pPor->GetPortion();
1527 : }
1528 :
1529 27 : if( !pQuo )
1530 27 : return false;
1531 :
1532 0 : return pQuo->GetQuoTxt() == rQuo;
1533 : }
1534 :
1535 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|