merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / text / txtftn.cxx
blob4b3befe53ac04f7170a29dd0e6c9e0e749438a80
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: txtftn.cxx,v $
10 * $Revision: 1.51.208.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include "viewsh.hxx"
34 #include "doc.hxx"
35 #include "pagefrm.hxx"
36 #include "ndtxt.hxx"
37 #include "txtatr.hxx"
38 #include <SwPortionHandler.hxx>
39 #include <txtftn.hxx>
40 #include <flyfrm.hxx>
41 #include <fmtftn.hxx>
42 #include <ftninfo.hxx>
43 #include <charfmt.hxx>
44 #include <dflyobj.hxx>
45 #include <rowfrm.hxx>
46 #include <svx/brshitem.hxx>
47 #include <svx/charrotateitem.hxx>
48 #include <breakit.hxx>
49 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
50 #include <com/sun/star/i18n/ScriptType.hdl>
51 #endif
52 #include <tabfrm.hxx>
53 // OD 2004-05-24 #i28701#
54 #include <sortedobjs.hxx>
56 #include "txtcfg.hxx"
57 #include "swfont.hxx" // new SwFont
58 #include "porftn.hxx"
59 #include "porfly.hxx"
60 #include "porlay.hxx"
61 #include "txtfrm.hxx"
62 #include "itrform2.hxx"
63 #include "ftnfrm.hxx" // FindQuoVadisFrm(),
64 #include "pagedesc.hxx"
65 #include "redlnitr.hxx" // SwRedlnItr
66 #include "sectfrm.hxx" // SwSectionFrm
67 #include "layouter.hxx" // Endnote-Collection
68 #include "frmtool.hxx"
69 #include "ndindex.hxx"
71 using namespace ::com::sun::star;
73 /*************************************************************************
74 * _IsFtnNumFrm()
75 *************************************************************************/
77 sal_Bool SwTxtFrm::_IsFtnNumFrm() const
79 const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster();
80 while( pFtn && !pFtn->ContainsCntnt() )
81 pFtn = pFtn->GetMaster();
82 return !pFtn;
85 /*************************************************************************
86 * FindFtn()
87 *************************************************************************/
89 // Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn
91 SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn )
93 SwTxtFrm *pFrm = this;
94 const sal_Bool bFwd = *pFtn->GetStart() >= GetOfst();
95 while( pFrm )
97 if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) )
98 return pFrm;
99 pFrm = bFwd ? pFrm->GetFollow() :
100 pFrm->IsFollow() ? pFrm->FindMaster() : 0;
102 return pFrm;
105 /*************************************************************************
106 * CalcFtnFlag()
107 *************************************************************************/
109 #ifdef PRODUCT
110 void SwTxtFrm::CalcFtnFlag()
111 #else
112 void SwTxtFrm::CalcFtnFlag( xub_StrLen nStop )//Fuer den Test von SplitFrm
113 #endif
115 bFtn = sal_False;
117 const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
118 if( !pHints )
119 return;
121 const USHORT nSize = pHints->Count();
123 #ifdef PRODUCT
124 const xub_StrLen nEnd = GetFollow() ? GetFollow()->GetOfst() : STRING_LEN;
125 #else
126 const xub_StrLen nEnd = nStop != STRING_LEN ? nStop
127 : GetFollow() ? GetFollow()->GetOfst() : STRING_LEN;
128 #endif
130 for ( USHORT i = 0; i < nSize; ++i )
132 const SwTxtAttr *pHt = (*pHints)[i];
133 if ( pHt->Which() == RES_TXTATR_FTN )
135 const xub_StrLen nIdx = *pHt->GetStart();
136 if ( nEnd < nIdx )
137 break;
138 if( GetOfst() <= nIdx )
140 bFtn = sal_True;
141 break;
147 /*************************************************************************
148 * CalcPrepFtnAdjust()
149 *************************************************************************/
151 sal_Bool SwTxtFrm::CalcPrepFtnAdjust()
153 ASSERT( HasFtn(), "Wer ruft mich da?" );
154 SwFtnBossFrm *pBoss = FindFtnBossFrm( sal_True );
155 const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this );
156 if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos &&
157 ( !pBoss->GetUpper()->IsSctFrm() ||
158 !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) )
160 const SwFtnContFrm *pCont = pBoss->FindFtnCont();
161 sal_Bool bReArrange = sal_True;
163 SWRECTFN( this )
164 if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
165 (Frm().*fnRect->fnGetBottom)() ) > 0 )
167 pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), sal_False,
168 pFtn->GetAttr() );
169 ValidateBodyFrm();
170 ValidateFrm();
171 pFtn = pBoss->FindFirstFtn( this );
173 else
174 bReArrange = sal_False;
175 if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) )
177 SwTxtFormatInfo aInf( this );
178 SwTxtFormatter aLine( this, &aInf );
179 aLine.TruncLines();
180 SetPara( 0 ); //Wird ggf. geloescht!
181 ResetPreps();
182 return sal_False;
185 return sal_True;
189 /*************************************************************************
190 * lcl_GetFtnLower()
192 * Local helper function. Checks if nLower should be taken as the boundary
193 * for the footnote.
194 *************************************************************************/
196 SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower )
198 // nLower is an absolute value. It denotes the bottom of the line
199 // containing the footnote.
200 SWRECTFN( pFrm )
202 ASSERT( !pFrm->IsVertical() || !pFrm->IsSwapped(),
203 "lcl_GetFtnLower with swapped frame" );
205 SwTwips nAdd;
206 SwTwips nRet = nLower;
209 // Check if text is inside a table.
211 if ( pFrm->IsInTab() )
214 // If pFrm is inside a table, we have to check if
215 // a) The table is not allowed to split or
216 // b) The table row is not allowed to split
218 // Inside a table, there are no footnotes,
219 // see SwFrm::FindFtnBossFrm. So we don't have to check
220 // the case that pFrm is inside a (footnote collecting) section
221 // within the table.
223 const SwFrm* pRow = pFrm;
224 while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
225 pRow = pRow->GetUpper();
226 const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper();
228 ASSERT( pTabFrm && pRow &&
229 pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" )
231 const BOOL bDontSplit = !pTabFrm->IsFollow() &&
232 !pTabFrm->IsLayoutSplitAllowed();
234 SwTwips nMin = 0;
235 if ( bDontSplit )
236 nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)();
237 else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() )
238 nMin = (pRow->Frm().*fnRect->fnGetBottom)();
240 if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 )
241 nRet = nMin;
243 nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)();
245 else
246 nAdd = (pFrm->*fnRect->fnGetBottomMargin)();
248 if( nAdd > 0 )
250 if ( bVert )
251 nRet -= nAdd;
252 else
253 nRet += nAdd;
256 // #i10770#: If there are fly frames anchored at previous paragraphs,
257 // the deadline should consider their lower borders.
258 const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower();
259 ASSERT( pStartFrm, "Upper has no lower" )
260 SwTwips nFlyLower = bVert ? LONG_MAX : 0;
261 while ( pStartFrm != pFrm )
263 ASSERT( pStartFrm, "Frame chain is broken" )
264 if ( pStartFrm->GetDrawObjs() )
266 const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
267 for ( USHORT i = 0; i < rObjs.Count(); ++i )
269 SwAnchoredObject* pAnchoredObj = rObjs[i];
270 SwRect aRect( pAnchoredObj->GetObjRect() );
272 if ( !pAnchoredObj->ISA(SwFlyFrm) ||
273 static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() )
275 const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
276 if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 )
277 nFlyLower = nBottom;
282 pStartFrm = pStartFrm->GetNext();
285 if ( bVert )
286 nRet = Min( nRet, nFlyLower );
287 else
288 nRet = Max( nRet, nFlyLower );
290 return nRet;
294 /*************************************************************************
295 * SwTxtFrm::GetFtnLine()
296 *************************************************************************/
298 SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const
300 ASSERT( ! IsVertical() || ! IsSwapped(),
301 "SwTxtFrm::GetFtnLine with swapped frame" )
303 SwTxtFrm *pThis = (SwTxtFrm*)this;
305 if( !HasPara() )
307 // #109071# GetFormatted() does not work here, bacause most probably
308 // the frame is currently locked. We return the previous value.
309 return pThis->mnFtnLine > 0 ?
310 pThis->mnFtnLine :
311 IsVertical() ? Frm().Left() : Frm().Bottom();
314 SWAP_IF_NOT_SWAPPED( this )
316 SwTxtInfo aInf( pThis );
317 SwTxtIter aLine( pThis, &aInf );
318 const xub_StrLen nPos = *pFtn->GetStart();
319 aLine.CharToLine( nPos );
321 SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
322 if( IsVertical() )
323 nRet = SwitchHorizontalToVertical( nRet );
325 UNDO_SWAP( this )
327 nRet = lcl_GetFtnLower( pThis, nRet );
329 pThis->mnFtnLine = nRet;
330 return nRet;
333 /*************************************************************************
334 * SwTxtFrm::GetFtnRstHeight()
335 *************************************************************************/
337 // Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich.
338 // Sie wird eingeschraenkt durch den unteren Rand der Zeile mit
339 // der Ftn-Referenz.
341 SwTwips SwTxtFrm::_GetFtnFrmHeight() const
343 ASSERT( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" );
345 const SwFtnFrm *pFtnFrm = FindFtnFrm();
346 const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef();
347 const SwFtnBossFrm *pBoss = FindFtnBossFrm();
348 if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()->
349 GetFtn().IsEndNote() ) )
350 return 0;
352 SWAP_IF_SWAPPED( this )
354 SwTwips nHeight = pRef->IsInFtnConnect() ?
355 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() );
356 if( nHeight )
358 // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich
359 // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text
360 // eingeben.
361 const SwFrm *pCont = pFtnFrm->GetUpper();
362 //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf.
363 SWRECTFN( pCont )
364 SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
365 (Frm().*fnRect->fnGetTop)() );
367 #ifndef PRODUCT
368 if( nTmp < 0 )
370 sal_Bool bInvalidPos = sal_False;
371 const SwLayoutFrm* pTmp = GetUpper();
372 while( !bInvalidPos && pTmp )
374 bInvalidPos = !pTmp->GetValidPosFlag() ||
375 !pTmp->Lower()->GetValidPosFlag();
376 if( pTmp == pCont )
377 break;
378 pTmp = pTmp->GetUpper();
380 ASSERT( bInvalidPos, "Hanging below FtnCont" );
382 #endif
384 if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
386 //Wachstumspotential den Containers.
387 if ( !pRef->IsInFtnConnect() )
389 SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight );
390 nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True );
392 else
393 nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True );
395 nHeight += nTmp;
396 if( nHeight < 0 )
397 nHeight = 0;
399 else
400 { // The container has to shrink
401 nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight);
402 if( nTmp > 0 )
403 nHeight = nTmp;
404 else
405 nHeight = 0;
409 UNDO_SWAP( this )
411 return nHeight;
414 /*************************************************************************
415 * SwTxtFrm::FindQuoVadisFrm()
416 *************************************************************************/
418 SwTxtFrm *SwTxtFrm::FindQuoVadisFrm()
420 // Erstmal feststellen, ob wir in einem FtnFrm stehen:
421 if( GetIndPrev() || !IsInFtn() )
422 return 0;
424 // Zum Vorgaenger-FtnFrm
425 SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster();
426 if( !pFtnFrm )
427 return 0;
429 // Nun den letzten Cntnt:
430 const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt();
431 if( !pCnt )
432 return NULL;
433 const SwCntntFrm *pLast;
435 { pLast = pCnt;
436 pCnt = pCnt->GetNextCntntFrm();
437 } while( pCnt && pFtnFrm->IsAnLower( pCnt ) );
438 return (SwTxtFrm*)pLast;
441 /*************************************************************************
442 * SwTxtFrm::RemoveFtn()
443 *************************************************************************/
445 void SwTxtFrm::RemoveFtn( const xub_StrLen nStart, const xub_StrLen nLen )
447 if ( !IsFtnAllowed() )
448 return;
450 SwpHints *pHints = GetTxtNode()->GetpSwpHints();
451 if( !pHints )
452 return;
454 sal_Bool bRollBack = nLen != STRING_LEN;
455 USHORT nSize = pHints->Count();
456 xub_StrLen nEnd;
457 SwTxtFrm* pSource;
458 if( bRollBack )
460 nEnd = nStart + nLen;
461 pSource = GetFollow();
462 if( !pSource )
463 return;
465 else
467 nEnd = STRING_LEN;
468 pSource = this;
471 if( nSize )
473 SwPageFrm* pUpdate = NULL;
474 sal_Bool bRemove = sal_False;
475 SwFtnBossFrm *pFtnBoss = 0;
476 SwFtnBossFrm *pEndBoss = 0;
477 sal_Bool bFtnEndDoc
478 = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos;
479 for ( USHORT i = nSize; i; )
481 SwTxtAttr *pHt = pHints->GetTextHint(--i);
482 if ( RES_TXTATR_FTN != pHt->Which() )
483 continue;
485 const xub_StrLen nIdx = *pHt->GetStart();
486 if( nStart > nIdx )
487 break;
489 if( nEnd >= nIdx )
491 SwTxtFtn *pFtn = (SwTxtFtn*)pHt;
492 sal_Bool bEndn = pFtn->GetFtn().IsEndNote();
494 if( bEndn )
496 if( !pEndBoss )
497 pEndBoss = pSource->FindFtnBossFrm();
499 else
501 if( !pFtnBoss )
503 pFtnBoss = pSource->FindFtnBossFrm( sal_True );
504 if( pFtnBoss->GetUpper()->IsSctFrm() )
506 SwSectionFrm* pSect = (SwSectionFrm*)
507 pFtnBoss->GetUpper();
508 if( pSect->IsFtnAtEnd() )
509 bFtnEndDoc = sal_False;
514 // Wir loeschen nicht, sondern wollen die Ftn verschieben.
515 // Drei Faelle koennen auftreten:
516 // 1) Es gibt weder Follow noch PrevFollow
517 // -> RemoveFtn() (vielleicht sogar ein ASSERT wert)
518 // 2) nStart > GetOfst, ich habe einen Follow
519 // -> Ftn wandert in den Follow
520 // 3) nStart < GetOfst, ich bin ein Follow
521 // -> Ftn wandert in den PrevFollow
522 // beide muessen auf einer Seite/in einer Spalte stehen.
524 SwFtnFrm *pFtnFrm = bEndn ? pEndBoss->FindFtn( pSource, pFtn ) :
525 pFtnBoss->FindFtn( pSource, pFtn );
527 if( pFtnFrm )
529 const sal_Bool bEndDoc = bEndn ? sal_True : bFtnEndDoc;
530 if( bRollBack )
532 while ( pFtnFrm )
534 pFtnFrm->SetRef( this );
535 pFtnFrm = pFtnFrm->GetFollow();
536 SetFtn( sal_True );
539 else if( GetFollow() )
541 SwCntntFrm *pDest = GetFollow();
542 while( pDest->GetFollow() && ((SwTxtFrm*)pDest->
543 GetFollow())->GetOfst() <= nIdx )
544 pDest = pDest->GetFollow();
545 ASSERT( !pDest->FindFtnBossFrm( !bEndn )->FindFtn(
546 pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists");
548 //Nicht ummelden sondern immer Moven.
549 // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)>
550 if ( bEndDoc ||
551 !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) )
554 SwPageFrm* pTmp = pFtnFrm->FindPageFrm();
555 if( pUpdate && pUpdate != pTmp )
556 pUpdate->UpdateFtnNum();
557 pUpdate = pTmp;
558 while ( pFtnFrm )
560 pFtnFrm->SetRef( pDest );
561 pFtnFrm = pFtnFrm->GetFollow();
564 else
566 if( bEndn )
567 pEndBoss->MoveFtns( this, pDest, pFtn );
568 else
569 pFtnBoss->MoveFtns( this, pDest, pFtn );
570 bRemove = sal_True;
572 ((SwTxtFrm*)pDest)->SetFtn( sal_True );
574 ASSERT( pDest->FindFtnBossFrm( !bEndn )->FindFtn( pDest,
575 pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed");
577 else
579 if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
580 !SwLayouter::Collecting( GetNode()->GetDoc(),
581 pEndBoss->FindSctFrm(), NULL ) ) )
583 if( bEndn )
584 pEndBoss->RemoveFtn( this, pFtn );
585 else
586 pFtnBoss->RemoveFtn( this, pFtn );
587 bRemove = bRemove || !bEndDoc;
588 ASSERT( bEndn ? !pEndBoss->FindFtn( this, pFtn ) :
589 !pFtnBoss->FindFtn( this, pFtn ),
590 "SwTxtFrm::RemoveFtn: can't get off that footnote" );
596 if( pUpdate )
597 pUpdate->UpdateFtnNum();
598 // Wir bringen die Oszillation zum stehen:
599 if( bRemove && !bFtnEndDoc && HasPara() )
601 ValidateBodyFrm();
602 ValidateFrm();
605 // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen,
606 // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset
607 // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist
608 // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig
609 // der Follow-Offset manipuliert.
610 xub_StrLen nOldOfst = STRING_LEN;
611 if( HasFollow() && nStart > GetOfst() )
613 nOldOfst = GetFollow()->GetOfst();
614 GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
616 pSource->CalcFtnFlag();
617 if( nOldOfst < STRING_LEN )
618 GetFollow()->ManipOfst( nOldOfst );
621 /*************************************************************************
622 * SwTxtFormatter::ConnectFtn()
623 *************************************************************************/
624 // sal_False, wenn irgendetwas schief gegangen ist.
625 // Es gibt eigentlich nur zwei Moeglichkeiten:
626 // a) Die Ftn ist bereits vorhanden
627 // => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde
628 // b) Die Ftn ist nicht vorhanden
629 // => dann wird sie fuer uns angelegt.
630 // Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht,
631 // spielt in diesem Zusammenhang keine Rolle.
632 // Optimierungen bei Endnoten.
633 // Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die
634 // Ftn verschoben werden.
636 void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine )
638 ASSERT( !IsVertical() || !IsSwapped(),
639 "SwTxtFrm::ConnectFtn with swapped frame" );
641 bFtn = sal_True;
642 bInFtnConnect = sal_True; //Bloss zuruecksetzen!
643 sal_Bool bEnd = pFtn->GetFtn().IsEndNote();
646 // We want to store this value, because it is needed as a fallback
647 // in GetFtnLine(), if there is no paragraph information available
649 mnFtnLine = nDeadLine;
651 // Wir brauchen immer einen Boss (Spalte/Seite)
652 SwSectionFrm *pSect;
653 SwCntntFrm *pCntnt = this;
654 if( bEnd && IsInSct() )
656 pSect = FindSctFrm();
657 if( pSect->IsEndnAtEnd() )
658 pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE );
659 if( !pCntnt )
660 pCntnt = this;
663 SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd );
665 #if OSL_DEBUG_LEVEL > 1
666 SwTwips nRstHeight = GetRstHeight();
667 #endif
669 pSect = pBoss->FindSctFrm();
670 sal_Bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
671 ( !( pSect && pSect->IsFtnAtEnd() ) &&
672 FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos );
673 //Ftn kann beim Follow angemeldet sein.
674 SwCntntFrm *pSrcFrm = FindFtnRef( pFtn );
676 if( bDocEnd )
678 if( pSect && pSrcFrm )
680 SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
681 if( pFtnFrm && pFtnFrm->IsInSct() )
683 pBoss->RemoveFtn( pSrcFrm, pFtn );
684 pSrcFrm = 0;
688 else if( bEnd && pSect )
690 SwFtnFrm *pFtnFrm = pSrcFrm ? pBoss->FindFtn( pSrcFrm, pFtn ) : NULL;
691 if( pFtnFrm && !pFtnFrm->GetUpper() )
692 pFtnFrm = NULL;
693 SwDoc *pDoc = GetNode()->GetDoc();
694 if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) )
696 if( !pSrcFrm )
698 SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,pFtn);
699 SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 );
700 ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
701 GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
703 else if( pSrcFrm != this )
704 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
705 bInFtnConnect = sal_False;
706 return;
708 else if( pSrcFrm )
710 SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
711 if( !pFtnBoss->IsInSct() ||
712 pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
714 pBoss->RemoveFtn( pSrcFrm, pFtn );
715 pSrcFrm = 0;
720 if( bDocEnd || bEnd )
722 if( !pSrcFrm )
723 pBoss->AppendFtn( this, pFtn );
724 else if( pSrcFrm != this )
725 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
726 bInFtnConnect = sal_False;
727 return;
730 SwSaveFtnHeight aHeight( pBoss, nDeadLine );
732 if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden.
733 pBoss->AppendFtn( this, pFtn );
734 else
736 SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn );
737 SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
739 sal_Bool bBrutal = sal_False;
741 if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte.
743 SwFrm *pCont = pFtnFrm->GetUpper();
745 SWRECTFN ( pCont )
746 long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
747 nDeadLine );
749 if( nDiff >= 0 )
751 //Wenn die Fussnote bei einem Follow angemeldet ist, so ist
752 //es jetzt an der Zeit sie umzumelden.
753 if ( pSrcFrm != this )
754 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
755 //Es steht Platz zur Verfuegung, also kann die Fussnote evtl.
756 //wachsen.
757 if ( pFtnFrm->GetFollow() && nDiff > 0 )
759 SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
760 pBoss->RearrangeFtns( nDeadLine, sal_False, pFtn );
761 ValidateBodyFrm();
762 ValidateFrm();
763 ViewShell *pSh = GetShell();
764 if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
765 //Damit uns nix durch die Lappen geht.
766 pSh->InvalidateWindows( pCont->Frm() );
768 bInFtnConnect = sal_False;
769 return;
771 else
772 bBrutal = sal_True;
774 else
776 // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig.
777 SwFrm* pTmp = this;
778 while( pTmp->GetNext() && pSrcFrm != pTmp )
779 pTmp = pTmp->GetNext();
780 if( pSrcFrm == pTmp )
781 bBrutal = sal_True;
782 else
783 { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf
784 // der Seite schon einen FtnContainer gibt, hilft nur die brutale
785 // Methode
786 if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() )
787 bBrutal = sal_True;
788 // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)>
789 else if ( !pFtnFrm->GetPrev() ||
790 pFtnBoss->IsBefore( pBoss )
793 SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd );
794 pSrcBoss->MoveFtns( pSrcFrm, this, pFtn );
796 else
797 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
801 // Die brutale Loesung: Fussnote entfernen und appenden.
802 // Es muss SetFtnDeadLine() gerufen werden, weil nach
803 // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche
804 // eingestellt werden kann.
805 if( bBrutal )
807 pBoss->RemoveFtn( pSrcFrm, pFtn, sal_False );
808 SwSaveFtnHeight *pHeight = bEnd ? NULL :
809 new SwSaveFtnHeight( pBoss, nDeadLine );
810 pBoss->AppendFtn( this, pFtn );
811 delete pHeight;
815 // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen,
816 // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch
817 // nicht kalkuliert worden ist.
818 if( !pSect || !pSect->Growable() )
820 // Umgebung validieren, um Oszillationen zu verhindern.
821 SwSaveFtnHeight aNochmal( pBoss, nDeadLine );
822 ValidateBodyFrm();
823 pBoss->RearrangeFtns( nDeadLine, sal_True );
824 ValidateFrm();
826 else if( pSect->IsFtnAtEnd() )
828 ValidateBodyFrm();
829 ValidateFrm();
832 #if OSL_DEBUG_LEVEL > 1
833 // pFtnFrm kann sich durch Calc veraendert haben ...
834 SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn );
835 if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) )
837 int bla = 5;
838 (void)bla;
840 nRstHeight = GetRstHeight();
841 #endif
842 bInFtnConnect = sal_False;
843 return;
848 /*************************************************************************
849 * SwTxtFormatter::NewFtnPortion()
850 *************************************************************************/
852 // Die Portion fuer die Ftn-Referenz im Text
853 SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf,
854 SwTxtAttr *pHint )
856 ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
857 "NewFtnPortion with unswapped frame" );
859 if( !pFrm->IsFtnAllowed() )
860 return 0;
862 SwTxtFtn *pFtn = (SwTxtFtn*)pHint;
863 SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
864 SwDoc *pDoc = pFrm->GetNode()->GetDoc();
866 if( rInf.IsTest() )
867 return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFrm, pFtn );
869 SWAP_IF_SWAPPED( pFrm )
871 KSHORT nReal;
873 KSHORT nOldReal = pCurr->GetRealHeight();
874 KSHORT nOldAscent = pCurr->GetAscent();
875 KSHORT nOldHeight = pCurr->Height();
876 ((SwTxtFormatter*)this)->CalcRealHeight();
877 nReal = pCurr->GetRealHeight();
878 if( nReal < nOldReal )
879 nReal = nOldReal;
880 pCurr->SetRealHeight( nOldReal );
881 pCurr->Height( nOldHeight );
882 pCurr->SetAscent( nOldAscent );
885 SwTwips nLower = Y() + nReal;
887 const bool bVertical = pFrm->IsVertical();
888 if( bVertical )
889 nLower = pFrm->SwitchHorizontalToVertical( nLower );
891 nLower = lcl_GetFtnLower( pFrm, nLower );
893 //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix
894 //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die
895 //Ftn wegwerfen und neu erzeugen.
897 if( !rInf.IsQuick() )
898 pFrm->ConnectFtn( pFtn, nLower );
900 SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn );
901 SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() );
902 SwFtnFrm *pFtnFrm = NULL;
903 if( pScrFrm )
904 pFtnFrm = pBoss->FindFtn( pScrFrm, pFtn );
906 // Wir erkundigen uns, ob durch unser Append irgendeine
907 // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet
908 // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten
909 // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr.
910 // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die
911 // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte.
912 // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt,
913 // so sollte die Ftn2-Referenz auch auf die naechste wandern.
914 if( !rFtn.IsEndNote() )
916 SwSectionFrm *pSct = pBoss->FindSctFrm();
917 sal_Bool bAtSctEnd = pSct && pSct->IsFtnAtEnd();
918 if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd )
920 SwFrm* pFtnCont = pBoss->FindFtnCont();
921 // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine
922 // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte
923 // ist, duerfen wir ausweichen
924 if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
925 ( !bAtSctEnd && pFrm->GetIndPrev() ) ||
926 ( pSct && pBoss->GetPrev() ) ) )
928 if( !pFtnCont )
930 rInf.SetStop( sal_True );
931 UNDO_SWAP( pFrm )
932 return 0;
934 else
936 // Es darf keine Fussnotencontainer in spaltigen Bereichen und
937 // gleichzeitig auf der Seite/Seitenspalte geben
938 if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich?
940 SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( sal_True );
941 SwFtnContFrm* pFtnC = pTmp->FindFtnCont();
942 if( pFtnC )
944 SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower();
945 if( pTmpFrm && *pTmpFrm < pFtn )
947 rInf.SetStop( sal_True );
948 UNDO_SWAP( pFrm )
949 return 0;
953 // Ist dies die letzte passende Zeile?
954 SwTwips nTmpBot = Y() + nReal * 2;
956 if( bVertical )
957 nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
959 SWRECTFN( pFtnCont )
961 const long nDiff = (*fnRect->fnYDiff)(
962 (pFtnCont->Frm().*fnRect->fnGetTop)(),
963 nTmpBot );
965 if( pScrFrm && nDiff < 0 )
967 if( pFtnFrm )
969 SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
970 if( pFtnBoss != pBoss )
972 // Wir sind in der letzte Zeile und die Fussnote
973 // ist auf eine andere Seite gewandert, dann wollen
974 // wir mit ...
975 rInf.SetStop( sal_True );
976 UNDO_SWAP( pFrm )
977 return 0;
985 // Endlich: FtnPortion anlegen und raus hier...
986 SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ),
987 pFrm, pFtn, nReal );
988 rInf.SetFtnInside( sal_True );
990 UNDO_SWAP( pFrm )
992 return pRet;
995 /*************************************************************************
996 * SwTxtFormatter::NewFtnNumPortion()
997 *************************************************************************/
999 // Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich
1001 SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const
1003 ASSERT( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(),
1004 "This is the wrong place for a ftnnumber" );
1005 if( rInf.GetTxtStart() != nStart ||
1006 rInf.GetTxtStart() != rInf.GetIdx() )
1007 return 0;
1009 const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm();
1010 const SwTxtFtn* pFtn = pFtnFrm->GetAttr();
1012 // Aha, wir sind also im Fussnotenbereich
1013 SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
1015 SwDoc *pDoc = pFrm->GetNode()->GetDoc();
1016 XubString aFtnTxt( rFtn.GetViewNumStr( *pDoc, sal_True ));
1018 const SwEndNoteInfo* pInfo;
1019 if( rFtn.IsEndNote() )
1020 pInfo = &pDoc->GetEndNoteInfo();
1021 else
1022 pInfo = &pDoc->GetFtnInfo();
1023 const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet();
1025 const SwAttrSet* pParSet = &rInf.GetCharAttr();
1026 const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess();
1027 SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
1029 // --> FME 2005-02-17 #i37142#
1030 // Underline style of paragraph font should not be considered
1031 // Overline style of paragraph font should not be considered
1032 // Weight style of paragraph font should not be considered
1033 // Posture style of paragraph font should not be considered
1034 // See also #i18463# and SwTxtFormatter::NewNumberPortion()
1035 pNumFnt->SetUnderline( UNDERLINE_NONE );
1036 pNumFnt->SetOverline( UNDERLINE_NONE );
1037 pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
1038 pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
1039 pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
1040 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
1041 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
1042 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
1043 // <--
1045 pNumFnt->SetDiffFnt(&rSet, pIDSA );
1046 pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
1048 SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt );
1049 pNewPor->SetLeft( !pFrm->IsRightToLeft() );
1050 return pNewPor;
1053 /*************************************************************************
1054 * SwTxtFormatter::NewErgoSumPortion()
1055 *************************************************************************/
1057 XubString lcl_GetPageNumber( const SwPageFrm* pPage )
1059 ASSERT( pPage, "GetPageNumber: Homeless TxtFrm" );
1060 MSHORT nVirtNum = pPage->GetVirtPageNum();
1061 const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
1062 return rNum.GetNumStr( nVirtNum );
1065 SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const
1067 // Wir koennen nicht davon ausgehen, dass wir ein Follow sind
1068 // 7983: GetIdx() nicht nStart
1069 if( !pFrm->IsInFtn() || pFrm->GetPrev() ||
1070 rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
1071 pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
1072 return 0;
1074 // Aha, wir sind also im Fussnotenbereich
1075 const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1076 SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
1077 if( !pQuoFrm )
1078 return 0;
1079 const SwPageFrm* pPage = pFrm->FindPageFrm();
1080 const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
1081 if( pPage == pQuoFrm->FindPageFrm() )
1082 return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht
1083 const XubString aPage = lcl_GetPageNumber( pPage );
1084 SwParaPortion *pPara = pQuoFrm->GetPara();
1085 if( pPara )
1086 pPara->SetErgoSumNum( aPage );
1087 if( !rFtnInfo.aErgoSum.Len() )
1088 return 0;
1089 SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum,
1090 lcl_GetPageNumber( pQuoPage ) );
1091 return pErgo;
1094 /*************************************************************************
1095 * SwTxtFormatter::FormatQuoVadis()
1096 *************************************************************************/
1098 xub_StrLen SwTxtFormatter::FormatQuoVadis( const xub_StrLen nOffset )
1100 ASSERT( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
1101 "SwTxtFormatter::FormatQuoVadis with swapped frame" );
1103 if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
1104 return nOffset;
1106 const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow();
1107 if( !pErgoFrm && pFrm->HasFollow() )
1108 pErgoFrm = pFrm->GetFollow();
1109 if( !pErgoFrm )
1110 return nOffset;
1112 if( pErgoFrm == pFrm->GetNext() )
1114 SwFrm *pCol = pFrm->FindColFrm();
1115 while( pCol && !pCol->GetNext() )
1116 pCol = pCol->GetUpper()->FindColFrm();
1117 if( pCol )
1118 return nOffset;
1120 else
1122 const SwPageFrm* pPage = pFrm->FindPageFrm();
1123 const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm();
1124 if( pPage == pErgoPage )
1125 return nOffset; // Wenn der ErgoSum auf der selben Seite steht
1128 SwTxtFormatInfo &rInf = GetInfo();
1129 const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1130 if( !rFtnInfo.aQuoVadis.Len() )
1131 return nOffset;
1133 // Ein Wort zu QuoVadis/ErgoSum:
1134 // Fuer diese Texte wird der am Absatz eingestellte Font verwendet.
1135 // Wir initialisieren uns also:
1136 // ResetFont();
1137 FeedInf( rInf );
1138 SeekStartAndChg( rInf, sal_True );
1139 if( GetRedln() && pCurr->HasRedline() )
1140 GetRedln()->Seek( *pFnt, nOffset, 0 );
1142 // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen
1143 // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen.
1144 // Erst mal sehen, ob es so schlimm ist:
1145 SwLinePortion *pPor = pCurr->GetFirstPortion();
1146 KSHORT nLastLeft = 0;
1147 while( pPor )
1149 if ( pPor->IsFlyPortion() )
1150 nLastLeft = ( (SwFlyPortion*) pPor)->Fix() +
1151 ( (SwFlyPortion*) pPor)->Width();
1152 pPor = pPor->GetPortion();
1154 // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten
1155 // Stelle umbricht, also beeinflussen wir die Width.
1156 // nLastLeft ist jetzt quasi der rechte Rand.
1157 const KSHORT nOldRealWidth = rInf.RealWidth();
1158 rInf.RealWidth( nOldRealWidth - nLastLeft );
1160 XubString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
1161 SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo );
1162 pQuo->SetAscent( rInf.GetAscent() );
1163 pQuo->Height( rInf.GetTxtHeight() );
1164 pQuo->Format( rInf );
1165 USHORT nQuoWidth = pQuo->Width();
1166 SwLinePortion* pCurrPor = pQuo;
1168 while ( rInf.GetRest() )
1170 SwLinePortion* pFollow = rInf.GetRest();
1171 rInf.SetRest( 0 );
1172 pCurrPor->Move( rInf );
1174 ASSERT( pFollow->IsQuoVadisPortion(),
1175 "Quo Vadis, rest of QuoVadisPortion" )
1177 // format the rest and append it to the other QuoVadis parts
1178 pFollow->Format( rInf );
1179 nQuoWidth = nQuoWidth + pFollow->Width();
1181 pCurrPor->Append( pFollow );
1182 pCurrPor = pFollow;
1185 nLastLeft = nOldRealWidth - nQuoWidth;
1186 Right( Right() - nQuoWidth );
1188 SWAP_IF_NOT_SWAPPED( pFrm )
1190 const xub_StrLen nRet = FormatLine( nStart );
1192 UNDO_SWAP( pFrm )
1194 Right( rInf.Left() + nOldRealWidth - 1 );
1196 nLastLeft = nOldRealWidth - pCurr->Width();
1197 FeedInf( rInf );
1199 // Es kann durchaus sein, dass am Ende eine Marginportion steht,
1200 // die beim erneuten Aufspannen nur Aerger bereiten wuerde.
1201 pPor = pCurr->FindLastPortion();
1202 SwGluePortion *pGlue = pPor->IsMarginPortion() ?
1203 (SwMarginPortion*) pPor : 0;
1204 if( pGlue )
1206 pGlue->Height( 0 );
1207 pGlue->Width( 0 );
1208 pGlue->SetLen( 0 );
1209 pGlue->SetAscent( 0 );
1210 pGlue->SetPortion( NULL );
1211 pGlue->SetFixWidth(0);
1214 // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer,
1215 // dass der QuoVadis-Text rechts erscheint:
1216 nLastLeft = nLastLeft - nQuoWidth;
1217 if( nLastLeft )
1219 if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand
1221 switch( GetAdjust() )
1223 case SVX_ADJUST_BLOCK:
1225 if( !pCurr->GetLen() ||
1226 CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1))
1227 nLastLeft = pQuo->GetAscent();
1228 nQuoWidth = nQuoWidth + nLastLeft;
1229 break;
1231 case SVX_ADJUST_RIGHT:
1233 nLastLeft = pQuo->GetAscent();
1234 nQuoWidth = nQuoWidth + nLastLeft;
1235 break;
1237 case SVX_ADJUST_CENTER:
1239 nQuoWidth = nQuoWidth + pQuo->GetAscent();
1240 long nDiff = nLastLeft - nQuoWidth;
1241 if( nDiff < 0 )
1243 nLastLeft = pQuo->GetAscent();
1244 nQuoWidth = (USHORT)(-nDiff + nLastLeft);
1246 else
1248 nQuoWidth = 0;
1249 nLastLeft = USHORT(( pQuo->GetAscent() + nDiff ) / 2);
1251 break;
1253 default:
1254 nQuoWidth = nQuoWidth + nLastLeft;
1257 else
1258 nQuoWidth = nQuoWidth + nLastLeft;
1259 if( nLastLeft )
1261 pGlue = new SwGluePortion(0);
1262 pGlue->Width( nLastLeft );
1263 pPor->Append( pGlue );
1264 pPor = pPor->GetPortion();
1268 // Jetzt aber: die QuoVadis-Portion wird angedockt:
1269 pCurrPor = pQuo;
1270 while ( pCurrPor )
1272 // pPor->Append deletes the pPortoin pointer of pPor. Therefore
1273 // we have to keep a pointer to the next portion
1274 pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion();
1275 pPor->Append( pCurrPor );
1276 pPor = pPor->GetPortion();
1277 pCurrPor = pQuo;
1280 pCurr->Width( pCurr->Width() + KSHORT( nQuoWidth ) );
1282 // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt
1283 // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig
1284 // einen kleineren Font eingestellt als der vom QuoVadis-Text ...
1285 CalcAdjustLine( pCurr );
1287 #if OSL_DEBUG_LEVEL > 1
1288 if( OPTDBG( rInf ) )
1290 // aDbstream << "FormatQuoVadis:" << endl;
1291 // pCurr->DebugPortions( aDbstream, rInf.GetTxt(), nStart );
1293 #endif
1295 // Uff...
1296 return nRet;
1300 /*************************************************************************
1301 * SwTxtFormatter::MakeDummyLine()
1302 *************************************************************************/
1304 // MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand
1305 // reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen
1306 // zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden.
1307 // Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn-
1308 // Oszillationen verwendet.
1310 void SwTxtFormatter::MakeDummyLine()
1312 KSHORT nRstHeight = GetFrmRstHeight();
1313 if( pCurr && nRstHeight > pCurr->Height() )
1315 SwLineLayout *pLay = new SwLineLayout;
1316 nRstHeight = nRstHeight - pCurr->Height();
1317 pLay->Height( nRstHeight );
1318 pLay->SetAscent( nRstHeight );
1319 Insert( pLay );
1320 Next();
1324 /*************************************************************************
1325 * class SwFtnSave
1326 *************************************************************************/
1327 class SwFtnSave
1329 SwTxtSizeInfo *pInf;
1330 SwFont *pFnt;
1331 SwFont *pOld;
1332 public:
1333 SwFtnSave( const SwTxtSizeInfo &rInf,
1334 const SwTxtFtn *pTxtFtn,
1335 const bool bApplyGivenScriptType,
1336 const BYTE nGivenScriptType );
1337 ~SwFtnSave();
1340 /*************************************************************************
1341 * SwFtnSave::SwFtnSave()
1342 *************************************************************************/
1344 SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf,
1345 const SwTxtFtn* pTxtFtn,
1346 const bool bApplyGivenScriptType,
1347 const BYTE nGivenScriptType )
1348 : pInf( &((SwTxtSizeInfo&)rInf) )
1349 , pFnt( 0 )
1350 , pOld( 0 )
1352 if( pTxtFtn && rInf.GetTxtFrm() )
1354 pFnt = ((SwTxtSizeInfo&)rInf).GetFont();
1355 pOld = new SwFont( *pFnt );
1356 pOld->GetTox() = pFnt->GetTox();
1357 pFnt->GetTox() = 0;
1358 SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
1359 const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
1361 // --> OD 2009-01-29 #i98418#
1362 if ( bApplyGivenScriptType )
1364 pFnt->SetActual( nGivenScriptType );
1366 else
1368 // examine text and set script
1369 String aTmpStr( rFtn.GetViewNumStr( *pDoc ) );
1370 pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
1372 // <--
1374 const SwEndNoteInfo* pInfo;
1375 if( rFtn.IsEndNote() )
1376 pInfo = &pDoc->GetEndNoteInfo();
1377 else
1378 pInfo = &pDoc->GetFtnInfo();
1379 const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
1380 pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() );
1382 // we reduce footnote size, if we are inside a double line portion
1383 if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() )
1385 Size aSize = pFnt->GetSize( pFnt->GetActual() );
1386 pFnt->SetSize( Size( (long)aSize.Width() / 2,
1387 (long)aSize.Height() / 2 ),
1388 pFnt->GetActual() );
1391 // set the correct rotation at the footnote font
1392 const SfxPoolItem* pItem;
1393 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1394 sal_True, &pItem ))
1395 pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(),
1396 rInf.GetTxtFrm()->IsVertical() );
1398 pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1400 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
1401 sal_True, &pItem ))
1402 pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) );
1404 else
1405 pFnt = NULL;
1408 /*************************************************************************
1409 * SwFtnSave::~SwFtnSave()
1410 *************************************************************************/
1412 SwFtnSave::~SwFtnSave()
1414 if( pFnt )
1416 // SwFont zurueckstellen
1417 *pFnt = *pOld;
1418 pFnt->GetTox() = pOld->GetTox();
1419 pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1420 delete pOld;
1424 /*************************************************************************
1425 * SwFtnPortion::SwFtnPortion()
1426 *************************************************************************/
1428 SwFtnPortion::SwFtnPortion( const XubString &rExpand, SwTxtFrm *pFrame,
1429 SwTxtFtn *pFootn, KSHORT nReal )
1430 : SwFldPortion( rExpand, 0 )
1431 , pFrm(pFrame)
1432 , pFtn(pFootn)
1433 , nOrigHeight( nReal )
1434 // --> OD 2009-01-29 #i98418#
1435 , mbPreferredScriptTypeSet( false )
1436 , mnPreferredScriptType( SW_LATIN )
1437 // <--
1439 SetLen(1);
1440 SetWhichPor( POR_FTN );
1443 /*************************************************************************
1444 * SwFtnPortion::GetExpTxt()
1445 *************************************************************************/
1447 sal_Bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
1449 rTxt = aExpand;
1450 return sal_True;
1453 /*************************************************************************
1454 * virtual SwFtnPortion::Format()
1455 *************************************************************************/
1457 sal_Bool SwFtnPortion::Format( SwTxtFormatInfo &rInf )
1459 // --> OD 2009-01-29 #i98418#
1460 // SwFtnSave aFtnSave( rInf, pFtn );
1461 SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1462 // <--
1463 // the idx is manipulated in SwExpandPortion::Format
1464 // this flag indicates, that a footnote is allowed to trigger
1465 // an underflow during SwTxtGuess::Guess
1466 rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
1467 sal_Bool bFull = SwFldPortion::Format( rInf );
1468 rInf.SetFakeLineStart( sal_False );
1469 SetAscent( rInf.GetAscent() );
1470 Height( rInf.GetTxtHeight() );
1471 rInf.SetFtnDone( !bFull );
1472 if( !bFull )
1473 rInf.SetParaFtn();
1474 return bFull;
1477 /*************************************************************************
1478 * virtual SwFtnPortion::Paint()
1479 *************************************************************************/
1481 void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const
1483 // --> OD 2009-01-29 #i98418#
1484 // SwFtnSave aFtnSave( rInf, pFtn );
1485 SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1486 // <--
1487 rInf.DrawViewOpt( *this, POR_FTN );
1488 SwExpandPortion::Paint( rInf );
1491 /*************************************************************************
1492 * virtual SwFtnPortion::GetTxtSize()
1493 *************************************************************************/
1495 SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const
1497 // --> OD 2009-01-29 #i98418#
1498 // SwFtnSave aFtnSave( rInfo, pFtn );
1499 SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1500 // <--
1501 return SwExpandPortion::GetTxtSize( rInfo );
1504 // --> OD 2009-01-29 #i98418#
1505 void SwFtnPortion::SetPreferredScriptType( BYTE nPreferredScriptType )
1507 mbPreferredScriptTypeSet = true;
1508 mnPreferredScriptType = nPreferredScriptType;
1510 // <--
1512 /*************************************************************************
1513 * class SwQuoVadisPortion
1514 *************************************************************************/
1516 SwFldPortion *SwQuoVadisPortion::Clone( const XubString &rExpand ) const
1517 { return new SwQuoVadisPortion( rExpand, aErgo ); }
1519 SwQuoVadisPortion::SwQuoVadisPortion( const XubString &rExp, const XubString& rStr )
1520 : SwFldPortion( rExp ), aErgo(rStr)
1522 SetLen(0);
1523 SetWhichPor( POR_QUOVADIS );
1526 /*************************************************************************
1527 * virtual SwQuoVadisPortion::Format()
1528 *************************************************************************/
1530 sal_Bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf )
1532 // erster Versuch, vielleicht passt der Text
1533 CheckScript( rInf );
1534 sal_Bool bFull = SwFldPortion::Format( rInf );
1535 SetLen( 0 );
1537 if( bFull )
1539 // zweiter Versuch, wir kuerzen den String:
1540 aExpand = XubString( "...", RTL_TEXTENCODING_MS_1252 );
1541 bFull = SwFldPortion::Format( rInf );
1542 SetLen( 0 );
1543 if( bFull )
1544 // dritter Versuch, es langt: jetzt wird gestaucht:
1545 Width( USHORT(rInf.Width() - rInf.X()) );
1547 // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
1548 if( rInf.GetRest() )
1550 delete rInf.GetRest();
1551 rInf.SetRest( 0 );
1554 return bFull;
1557 /*************************************************************************
1558 * virtual SwQuoVadisPortion::GetExpTxt()
1559 *************************************************************************/
1561 sal_Bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
1563 rTxt = aExpand;
1564 // if this QuoVadisPortion has a follow, the follow is responsible for
1565 // the ergo text.
1566 if ( ! HasFollow() )
1567 rTxt += aErgo;
1568 return sal_True;
1571 /*************************************************************************
1572 * virtual SwQuoVadisPortion::HandlePortion()
1573 *************************************************************************/
1575 void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
1577 String aString( aExpand );
1578 aString += aErgo;
1579 rPH.Special( GetLen(), aString, GetWhichPor() );
1582 /*************************************************************************
1583 * virtual SwQuoVadisPortion::Paint()
1584 *************************************************************************/
1586 void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const
1588 // Wir wollen _immer_ per DrawStretchText ausgeben,
1589 // weil nErgo schnell mal wechseln kann.
1590 if( PrtWidth() )
1592 rInf.DrawViewOpt( *this, POR_QUOVADIS );
1593 SwTxtSlot aDiffTxt( &rInf, this, true, false );
1594 SwFontSave aSave( rInf, pFnt );
1595 rInf.DrawText( *this, rInf.GetLen(), sal_True );
1599 /*************************************************************************
1600 * class SwErgoSumPortion
1601 *************************************************************************/
1603 SwFldPortion *SwErgoSumPortion::Clone( const XubString &rExpand ) const
1605 UniString aTmp; // = UniString::CreateFromInt32( 0 );
1606 return new SwErgoSumPortion( rExpand, aTmp );
1609 SwErgoSumPortion::SwErgoSumPortion( const XubString &rExp, const XubString& rStr )
1610 : SwFldPortion( rExp )
1612 SetLen(0);
1613 aExpand += rStr;
1615 // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text
1616 aExpand += ' ';
1617 SetWhichPor( POR_ERGOSUM );
1620 xub_StrLen SwErgoSumPortion::GetCrsrOfst( const KSHORT ) const
1622 return 0;
1625 /*************************************************************************
1626 * virtual SwErgoSumPortion::Format()
1627 *************************************************************************/
1629 sal_Bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf )
1631 sal_Bool bFull = SwFldPortion::Format( rInf );
1632 SetLen( 0 );
1633 rInf.SetErgoDone( sal_True );
1635 // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
1636 if( bFull && rInf.GetRest() )
1638 delete rInf.GetRest();
1639 rInf.SetRest( 0 );
1642 // We return false in order to get some text into the current line,
1643 // even if it's full (better than looping)
1644 return sal_False;
1648 /*************************************************************************
1649 * SwParaPortion::SetErgoSumNum()
1650 *************************************************************************/
1652 void SwParaPortion::SetErgoSumNum( const XubString& rErgo )
1654 SwLineLayout *pLay = this;
1655 while( pLay->GetNext() )
1657 DBG_LOOP;
1658 pLay = pLay->GetNext();
1660 SwLinePortion *pPor = pLay;
1661 SwQuoVadisPortion *pQuo = 0;
1662 while( pPor && !pQuo )
1664 if ( pPor->IsQuoVadisPortion() )
1665 pQuo = (SwQuoVadisPortion*)pPor;
1666 pPor = pPor->GetPortion();
1668 if( pQuo )
1669 pQuo->SetNumber( rErgo );
1672 /*************************************************************************
1673 * SwParaPortion::UpdateQuoVadis()
1675 * Wird im SwTxtFrm::Prepare() gerufen
1676 *************************************************************************/
1678 sal_Bool SwParaPortion::UpdateQuoVadis( const XubString &rQuo )
1680 SwLineLayout *pLay = this;
1681 while( pLay->GetNext() )
1683 DBG_LOOP;
1684 pLay = pLay->GetNext();
1686 SwLinePortion *pPor = pLay;
1687 SwQuoVadisPortion *pQuo = 0;
1688 while( pPor && !pQuo )
1690 if ( pPor->IsQuoVadisPortion() )
1691 pQuo = (SwQuoVadisPortion*)pPor;
1692 pPor = pPor->GetPortion();
1695 if( !pQuo )
1696 return sal_False;
1698 return pQuo->GetQuoTxt() == rQuo;