update credits
[LibreOffice.git] / sw / source / core / layout / hffrm.cxx
blob2b2b3682714b7fc386258336f5022a720b068f8e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "pagefrm.hxx"
22 #include "viewsh.hxx"
23 #include "doc.hxx"
24 #include <fmtcntnt.hxx>
25 #include <fmthdft.hxx>
26 #include <fmtfsize.hxx>
27 #include "viewopt.hxx"
28 #include "hffrm.hxx"
29 #include "rootfrm.hxx"
30 #include "txtfrm.hxx"
31 #include "sectfrm.hxx"
32 #include "flyfrm.hxx"
33 #include "frmtool.hxx"
34 #include "dflyobj.hxx"
35 #include "frmfmt.hxx"
36 #include "ndindex.hxx"
37 #include "hfspacingitem.hxx"
38 // OD 2004-05-24 #i28701#
39 #include <sortedobjs.hxx>
40 // #i43771#
41 #include <objectformatter.hxx>
43 extern bool bObjsDirect; //frmtool.cxx
45 static SwTwips lcl_GetFrmMinHeight(const SwLayoutFrm & rFrm)
47 const SwFmtFrmSize &rSz = rFrm.GetFmt()->GetFrmSize();
48 SwTwips nMinHeight;
50 switch (rSz.GetHeightSizeType())
52 case ATT_MIN_SIZE:
53 nMinHeight = rSz.GetHeight();
55 break;
57 default:
58 nMinHeight = 0;
62 return nMinHeight;
66 static SwTwips lcl_CalcContentHeight(SwLayoutFrm & frm)
68 SwTwips nRemaining = 0;
69 sal_uInt16 nNum = 0;
70 SwFrm* pFrm = frm.Lower();
72 while ( pFrm )
74 SwTwips nTmp;
76 nTmp = pFrm->Frm().Height();
77 nRemaining += nTmp;
78 if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsUndersized() )
80 nTmp = ((SwTxtFrm*)pFrm)->GetParHeight()
81 - pFrm->Prt().Height();
82 // This TxtFrm would like to be a bit bigger
83 nRemaining += nTmp;
85 else if( pFrm->IsSctFrm() && ((SwSectionFrm*)pFrm)->IsUndersized() )
87 nTmp = ((SwSectionFrm*)pFrm)->Undersize();
88 nRemaining += nTmp;
90 pFrm = pFrm->GetNext();
92 nNum++;
95 return nRemaining;
98 static void lcl_LayoutFrmEnsureMinHeight(SwLayoutFrm & rFrm,
99 const SwBorderAttrs * )
101 SwTwips nMinHeight = lcl_GetFrmMinHeight(rFrm);
103 if (rFrm.Frm().Height() < nMinHeight)
105 rFrm.Grow(nMinHeight - rFrm.Frm().Height());
109 SwHeadFootFrm::SwHeadFootFrm( SwFrmFmt * pFmt, SwFrm* pSib, sal_uInt16 nTypeIn)
110 : SwLayoutFrm( pFmt, pSib )
112 mnType = nTypeIn;
113 SetDerivedVert( sal_False );
115 const SwFmtCntnt &rCnt = pFmt->GetCntnt();
117 OSL_ENSURE( rCnt.GetCntntIdx(), "No content for Header." );
119 // Have the objects created right now for header and footer
120 bool bOld = bObjsDirect;
121 bObjsDirect = true;
122 sal_uLong nIndex = rCnt.GetCntntIdx()->GetIndex();
123 ::_InsertCnt( this, pFmt->GetDoc(), ++nIndex );
124 bObjsDirect = bOld;
127 void SwHeadFootFrm::FormatPrt(SwTwips & nUL, const SwBorderAttrs * pAttrs)
129 if (GetEatSpacing())
131 /* The minimal height of the print area is the minimal height of the
132 frame without the height needed for borders and shadow. */
133 SwTwips nMinHeight = lcl_GetFrmMinHeight(*this);
135 nMinHeight -= pAttrs->CalcTop();
136 nMinHeight -= pAttrs->CalcBottom();
138 /* If the minimal height of the print area is negative, try to
139 compensate by overlapping */
140 SwTwips nOverlap = 0;
141 if (nMinHeight < 0)
143 nOverlap = -nMinHeight;
144 nMinHeight = 0;
147 /* Calculate desired height of content. The minimal height has to be
148 adhered. */
149 SwTwips nHeight;
151 if ( ! HasFixSize() )
152 nHeight = lcl_CalcContentHeight(*this);
153 else
154 nHeight = nMinHeight;
156 if (nHeight < nMinHeight)
157 nHeight = nMinHeight;
159 /* calculate initial spacing/line space */
160 SwTwips nSpace, nLine;
162 if (IsHeaderFrm())
164 nSpace = pAttrs->CalcBottom();
165 nLine = pAttrs->CalcBottomLine();
167 else
169 nSpace = pAttrs->CalcTop();
170 nLine = pAttrs->CalcTopLine();
173 /* calculate overlap and correct spacing */
174 nOverlap += nHeight - nMinHeight;
175 if (nOverlap < nSpace - nLine)
176 nSpace -= nOverlap;
177 else
178 nSpace = nLine;
180 /* calculate real vertical space between frame and print area */
181 if (IsHeaderFrm())
182 nUL = pAttrs->CalcTop() + nSpace;
183 else
184 nUL = pAttrs->CalcBottom() + nSpace;
186 /* set print area */
187 // OD 23.01.2003 #106895# - add first parameter to <SwBorderAttrs::CalcRight(..)>
188 SwTwips nLR = pAttrs->CalcLeft( this ) + pAttrs->CalcRight( this );
190 maPrt.Left(pAttrs->CalcLeft(this));
192 if (IsHeaderFrm())
193 maPrt.Top(pAttrs->CalcTop());
194 else
195 maPrt.Top(nSpace);
197 maPrt.Width(maFrm.Width() - nLR);
199 SwTwips nNewHeight;
201 if (nUL < maFrm.Height())
202 nNewHeight = maFrm.Height() - nUL;
203 else
204 nNewHeight = 0;
206 maPrt.Height(nNewHeight);
209 else
211 // Set position
212 maPrt.Left( pAttrs->CalcLeft( this ) );
213 maPrt.Top ( pAttrs->CalcTop() );
215 // Set sizes - the sizes are given by the surrounding Frm, just
216 // subtract the borders.
217 // OD 23.01.2003 #106895# - add first parameter to <SwBorderAttrs::CalcRight(..)>
218 SwTwips nLR = pAttrs->CalcLeft( this ) + pAttrs->CalcRight( this );
219 maPrt.Width ( maFrm.Width() - nLR );
220 maPrt.Height( maFrm.Height()- nUL );
224 mbValidPrtArea = sal_True;
227 void SwHeadFootFrm::FormatSize(SwTwips nUL, const SwBorderAttrs * pAttrs)
229 if ( !HasFixSize() )
231 if( !IsColLocked() )
233 mbValidSize = mbValidPrtArea = sal_True;
235 const SwTwips nBorder = nUL;
236 SwTwips nMinHeight = lcl_GetFrmMinHeight(*this);
237 nMinHeight -= pAttrs->CalcTop();
238 nMinHeight -= pAttrs->CalcBottom();
240 if (nMinHeight < 0)
241 nMinHeight = 0;
243 ColLock();
245 SwTwips nMaxHeight = LONG_MAX;
246 SwTwips nRemaining, nOldHeight;
247 // #i64301#
248 // use the position of the footer printing area to control invalidation
249 // of the first footer content.
250 Point aOldFooterPrtPos;
254 nOldHeight = Prt().Height();
255 SwFrm* pFrm = Lower();
256 // #i64301#
257 if ( pFrm &&
258 aOldFooterPrtPos != ( Frm().Pos() + Prt().Pos() ) )
260 pFrm->_InvalidatePos();
261 aOldFooterPrtPos = Frm().Pos() + Prt().Pos();
263 while( pFrm )
265 pFrm->Calc();
266 // #i43771# - format also object anchored
267 // at the frame
268 // #i46941# - frame has to be valid.
269 // Note: frame could be invalid after calling its format,
270 // if it's locked
271 OSL_ENSURE( StackHack::IsLocked() || !pFrm->IsTxtFrm() ||
272 pFrm->IsValid() ||
273 static_cast<SwTxtFrm*>(pFrm)->IsJoinLocked(),
274 "<SwHeadFootFrm::FormatSize(..)> - text frame invalid and not locked." );
275 if ( pFrm->IsTxtFrm() && pFrm->IsValid() )
277 if ( !SwObjectFormatter::FormatObjsAtFrm( *pFrm,
278 *(pFrm->FindPageFrm()) ) )
280 // restart format with first content
281 pFrm = Lower();
282 continue;
285 pFrm = pFrm->GetNext();
287 nRemaining = 0;
288 pFrm = Lower();
290 while ( pFrm )
292 nRemaining += pFrm->Frm().Height();
294 if( pFrm->IsTxtFrm() &&
295 ((SwTxtFrm*)pFrm)->IsUndersized() )
296 // This TxtFrm would like to be a bit bigger
297 nRemaining += ((SwTxtFrm*)pFrm)->GetParHeight()
298 - pFrm->Prt().Height();
299 else if( pFrm->IsSctFrm() &&
300 ((SwSectionFrm*)pFrm)->IsUndersized() )
301 nRemaining += ((SwSectionFrm*)pFrm)->Undersize();
302 pFrm = pFrm->GetNext();
304 if ( nRemaining < nMinHeight )
305 nRemaining = nMinHeight;
307 SwTwips nDiff = nRemaining - nOldHeight;
309 if( !nDiff )
310 break;
311 if( nDiff < 0 )
313 nMaxHeight = nOldHeight;
315 if( nRemaining <= nMinHeight )
316 nRemaining = ( nMaxHeight + nMinHeight + 1 ) / 2;
318 else
320 if (nOldHeight > nMinHeight)
321 nMinHeight = nOldHeight;
323 if( nRemaining >= nMaxHeight )
324 nRemaining = ( nMaxHeight + nMinHeight + 1 ) / 2;
327 nDiff = nRemaining - nOldHeight;
329 if ( nDiff )
331 ColUnlock();
332 if ( nDiff > 0 )
334 if ( Grow( nDiff ) )
336 pFrm = Lower();
338 while ( pFrm )
340 if( pFrm->IsTxtFrm())
342 SwTxtFrm * pTmpFrm = (SwTxtFrm*) pFrm;
343 if (pTmpFrm->IsUndersized() )
345 pTmpFrm->InvalidateSize();
346 pTmpFrm->Prepare(PREP_ADJUST_FRM);
349 /* #i3568# Undersized sections need to be
350 invalidated too. */
351 else if (pFrm->IsSctFrm())
353 SwSectionFrm * pTmpFrm =
354 (SwSectionFrm*) pFrm;
355 if (pTmpFrm->IsUndersized() )
357 pTmpFrm->InvalidateSize();
358 pTmpFrm->Prepare(PREP_ADJUST_FRM);
361 pFrm = pFrm->GetNext();
365 else
366 Shrink( -nDiff );
367 // Quickly update the position
369 MakePos();
370 ColLock();
372 else
373 break;
374 // Don't overwrite the lower edge of the upper
375 if ( GetUpper() && Frm().Height() )
377 const SwTwips nDeadLine = GetUpper()->Frm().Top() +
378 GetUpper()->Prt().Bottom();
379 const SwTwips nBot = Frm().Bottom();
380 if ( nBot > nDeadLine )
382 Frm().Bottom( nDeadLine );
383 Prt().SSize().Height() = Frm().Height() - nBorder;
386 mbValidSize = mbValidPrtArea = sal_True;
387 } while( nRemaining<=nMaxHeight && nOldHeight!=Prt().Height() );
388 ColUnlock();
390 mbValidSize = mbValidPrtArea = sal_True;
392 else //if ( GetType() & 0x0018 )
396 if ( Frm().Height() != pAttrs->GetSize().Height() )
397 ChgSize( Size( Frm().Width(), pAttrs->GetSize().Height()));
398 mbValidSize = sal_True;
399 MakePos();
400 } while ( !mbValidSize );
404 void SwHeadFootFrm::Format(const SwBorderAttrs * pAttrs)
406 OSL_ENSURE( pAttrs, "SwFooterFrm::Format, pAttrs is 0." );
408 if ( mbValidPrtArea && mbValidSize )
409 return;
411 if ( ! GetEatSpacing() && IsHeaderFrm())
413 SwLayoutFrm::Format(pAttrs);
415 else
417 lcl_LayoutFrmEnsureMinHeight(*this, pAttrs);
419 long nUL = pAttrs->CalcTop() + pAttrs->CalcBottom();
421 if ( !mbValidPrtArea )
422 FormatPrt(nUL, pAttrs);
424 if ( !mbValidSize )
425 FormatSize(nUL, pAttrs);
429 SwTwips SwHeadFootFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
431 SwTwips nResult;
433 if ( IsColLocked() )
435 nResult = 0;
437 else if (!GetEatSpacing())
439 nResult = SwLayoutFrm::GrowFrm(nDist, bTst, bInfo);
441 else
443 nResult = 0;
445 SwBorderAttrAccess * pAccess =
446 new SwBorderAttrAccess( SwFrm::GetCache(), this );
447 OSL_ENSURE(pAccess, "no border attributes");
449 SwBorderAttrs * pAttrs = pAccess->Get();
451 /* First assume the whole amount to grow can be provided by eating
452 spacing. */
453 SwTwips nEat = nDist;
454 SwTwips nMaxEat;
456 /* calculate maximum eatable spacing */
457 if (IsHeaderFrm())
458 nMaxEat = maFrm.Height() - maPrt.Top() - maPrt.Height() - pAttrs->CalcBottomLine();
459 else
460 nMaxEat = maPrt.Top() - pAttrs->CalcTopLine();
462 delete pAccess;
464 if (nMaxEat < 0)
465 nMaxEat = 0;
467 /* If the frame is too small, eat less spacing thus letting the frame
468 grow more. */
469 SwTwips nMinHeight = lcl_GetFrmMinHeight(*this);
470 SwTwips nFrameTooSmall = nMinHeight - Frm().Height();
472 if (nFrameTooSmall > 0)
473 nEat -= nFrameTooSmall;
475 /* No negative eating, not eating more than allowed. */
476 if (nEat < 0)
477 nEat = 0;
478 else if (nEat > nMaxEat)
479 nEat = nMaxEat;
481 // OD 10.04.2003 #108719# - Notify fly frame, if header frame
482 // grows. Consider, that 'normal' grow of layout frame already notifys
483 // the fly frames.
484 sal_Bool bNotifyFlys = sal_False;
485 if (nEat > 0)
487 if ( ! bTst)
489 if (! IsHeaderFrm())
491 maPrt.Top(maPrt.Top() - nEat);
492 maPrt.Height(maPrt.Height() - nEat);
495 InvalidateAll();
498 nResult += nEat;
499 // OD 14.04.2003 #108719# - trigger fly frame notify.
500 if ( IsHeaderFrm() )
502 bNotifyFlys = sal_True;
506 if (nDist - nEat > 0)
508 SwTwips nFrmGrow =
509 SwLayoutFrm::GrowFrm( nDist - nEat, bTst, bInfo );
511 nResult += nFrmGrow;
512 if ( nFrmGrow > 0 )
514 bNotifyFlys = sal_False;
518 // OD 10.04.2003 #108719# - notify fly frames, if necessary and triggered.
519 if ( ( nResult > 0 ) && bNotifyFlys )
521 NotifyLowerObjs();
525 if ( nResult && !bTst )
526 SetCompletePaint();
528 return nResult;
531 SwTwips SwHeadFootFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
533 SwTwips nResult;
535 if ( IsColLocked() )
537 nResult = 0;
539 else if (! GetEatSpacing())
541 nResult = SwLayoutFrm::ShrinkFrm(nDist, bTst, bInfo);
543 else
545 nResult = 0;
547 SwTwips nMinHeight = lcl_GetFrmMinHeight(*this);
548 SwTwips nOldHeight = Frm().Height();
549 SwTwips nRest = 0; // Amount to shrink by spitting out spacing
551 if ( nOldHeight >= nMinHeight )
553 /* If the frame's height is bigger than its minimum height, shrink
554 the frame towards its minimum height. If this is not sufficient
555 to provide the shrinking requested provide the rest by spitting
556 out spacing. */
558 SwTwips nBiggerThanMin = nOldHeight - nMinHeight;
560 if (nBiggerThanMin < nDist)
562 nRest = nDist - nBiggerThanMin;
564 /* info: declaration of nRest -> else nRest = 0 */
566 else
567 /* The frame cannot shrink. Provide shrinking by spitting out
568 spacing. */
569 nRest = nDist;
571 // OD 10.04.2003 #108719# - Notify fly frame, if header/footer frame
572 // shrinks. Consider, that 'normal' shrink of layout frame already notifys
573 // the fly frames.
574 sal_Bool bNotifyFlys = sal_False;
575 if (nRest > 0)
578 SwBorderAttrAccess * pAccess =
579 new SwBorderAttrAccess( SwFrm::GetCache(), this );
580 OSL_ENSURE(pAccess, "no border attributes");
582 SwBorderAttrs * pAttrs = pAccess->Get();
584 /* minimal height of print area */
585 SwTwips nMinPrtHeight = nMinHeight
586 - pAttrs->CalcTop()
587 - pAttrs->CalcBottom();
589 if (nMinPrtHeight < 0)
590 nMinPrtHeight = 0;
592 delete pAccess;
594 /* assume all shrinking can be provided */
595 SwTwips nShrink = nRest;
597 /* calculate maximum shrinking */
598 SwTwips nMaxShrink = maPrt.Height() - nMinPrtHeight;
600 /* shrink no more than maximum shrinking */
601 if (nShrink > nMaxShrink)
603 //nRest -= nShrink - nMaxShrink;
604 nShrink = nMaxShrink;
607 if (!bTst)
609 if (! IsHeaderFrm() )
611 maPrt.Top(maPrt.Top() + nShrink);
612 maPrt.Height(maPrt.Height() - nShrink);
615 InvalidateAll();
617 nResult += nShrink;
618 // OD 14.04.2003 #108719# - trigger fly frame notify.
619 if ( IsHeaderFrm() )
621 bNotifyFlys = sal_True;
625 /* The shrinking not providable by spitting out spacing has to be done
626 by the frame. */
627 if (nDist - nRest > 0)
629 SwTwips nShrinkAmount = SwLayoutFrm::ShrinkFrm( nDist - nRest, bTst, bInfo );
630 nResult += nShrinkAmount;
631 if ( nShrinkAmount > 0 )
633 bNotifyFlys = sal_False;
637 // OD 10.04.2003 #108719# - notify fly frames, if necessary.
638 if ( ( nResult > 0 ) && bNotifyFlys )
640 NotifyLowerObjs();
644 return nResult;
647 sal_Bool SwHeadFootFrm::GetEatSpacing() const
649 const SwFrmFmt * pFmt = GetFmt();
650 OSL_ENSURE(pFmt, "SwHeadFootFrm: no format?");
652 if (pFmt->GetHeaderAndFooterEatSpacing().GetValue())
653 return sal_True;
655 return sal_False;
659 /*************************************************************************
661 |* SwPageFrm::PrepareHeader()
663 |* Description Creates or removes headers
665 |*************************************************************************/
668 void DelFlys( SwLayoutFrm *pFrm, SwPageFrm *pPage )
670 for ( int i = 0; pPage->GetSortedObjs() &&
671 pPage->GetSortedObjs()->Count() &&
672 i < (int)pPage->GetSortedObjs()->Count(); ++i )
674 SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i];
675 if ( pObj->ISA(SwFlyFrm) )
677 SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pObj);
678 if ( pFrm->IsAnLower( pFlyFrm ) )
680 delete pFlyFrm;
681 --i;
689 void SwPageFrm::PrepareHeader()
691 SwLayoutFrm *pLay = (SwLayoutFrm*)Lower();
692 if ( !pLay )
693 return;
695 const SwFmtHeader &rH = ((SwFrmFmt*)GetRegisteredIn())->GetHeader();
697 const ViewShell *pSh = getRootFrm()->GetCurrShell();
698 const sal_Bool bOn = !(pSh && pSh->GetViewOptions()->getBrowseMode());
700 if ( bOn && rH.IsActive() )
701 { //Implant header, but remove first, if already present
702 OSL_ENSURE( rH.GetHeaderFmt(), "FrmFmt for Header not found." );
704 if ( pLay->GetFmt() == (SwFrmFmt*)rH.GetHeaderFmt() )
705 return; // Header is already the correct one.
707 if ( pLay->IsHeaderFrm() )
708 { SwLayoutFrm *pDel = pLay;
709 pLay = (SwLayoutFrm*)pLay->GetNext();
710 ::DelFlys( pDel, this );
711 pDel->Cut();
712 delete pDel;
714 OSL_ENSURE( pLay, "Where to with the Header?" );
715 SwHeaderFrm *pH = new SwHeaderFrm( (SwFrmFmt*)rH.GetHeaderFmt(), this );
716 pH->Paste( this, pLay );
717 if ( GetUpper() )
718 ::RegistFlys( this, pH );
720 else if ( pLay && pLay->IsHeaderFrm() )
721 { // Remove header if present.
722 ::DelFlys( pLay, this );
723 pLay->Cut();
724 delete pLay;
727 /*************************************************************************
729 |* SwPageFrm::PrepareFooter()
731 |* Description Creates or removes footer
733 |*************************************************************************/
736 void SwPageFrm::PrepareFooter()
738 SwLayoutFrm *pLay = (SwLayoutFrm*)Lower();
739 if ( !pLay )
740 return;
742 const SwFmtFooter &rF = ((SwFrmFmt*)GetRegisteredIn())->GetFooter();
743 while ( pLay->GetNext() )
744 pLay = (SwLayoutFrm*)pLay->GetNext();
746 const ViewShell *pSh = getRootFrm()->GetCurrShell();
747 const sal_Bool bOn = !(pSh && pSh->GetViewOptions()->getBrowseMode());
749 if ( bOn && rF.IsActive() )
750 { //Implant footer, but remove first, if already present
751 OSL_ENSURE( rF.GetFooterFmt(), "FrmFmt for Footer not found." );
753 if ( pLay->GetFmt() == (SwFrmFmt*)rF.GetFooterFmt() )
754 return; // Footer is already the correct one.
756 if ( pLay->IsFooterFrm() )
757 { ::DelFlys( pLay, this );
758 pLay->Cut();
759 delete pLay;
761 SwFooterFrm *pF = new SwFooterFrm( (SwFrmFmt*)rF.GetFooterFmt(), this );
762 pF->Paste( this );
763 if ( GetUpper() )
764 ::RegistFlys( this, pF );
766 else if ( pLay && pLay->IsFooterFrm() )
767 { // Remove footer if already present
768 ::DelFlys( pLay, this );
769 ViewShell *pShell;
770 if ( pLay->GetPrev() && 0 != (pShell = getRootFrm()->GetCurrShell()) &&
771 pShell->VisArea().HasArea() )
772 pShell->InvalidateWindows( pShell->VisArea() );
773 pLay->Cut();
774 delete pLay;
780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */