1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
24 #include <fmtcntnt.hxx>
25 #include <fmthdft.hxx>
26 #include <fmtfsize.hxx>
27 #include "viewopt.hxx"
29 #include "rootfrm.hxx"
31 #include "sectfrm.hxx"
33 #include "frmtool.hxx"
34 #include "dflyobj.hxx"
36 #include "ndindex.hxx"
37 #include "hfspacingitem.hxx"
38 // OD 2004-05-24 #i28701#
39 #include <sortedobjs.hxx>
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();
50 switch (rSz
.GetHeightSizeType())
53 nMinHeight
= rSz
.GetHeight();
66 static SwTwips
lcl_CalcContentHeight(SwLayoutFrm
& frm
)
68 SwTwips nRemaining
= 0;
70 SwFrm
* pFrm
= frm
.Lower();
76 nTmp
= pFrm
->Frm().Height();
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
85 else if( pFrm
->IsSctFrm() && ((SwSectionFrm
*)pFrm
)->IsUndersized() )
87 nTmp
= ((SwSectionFrm
*)pFrm
)->Undersize();
90 pFrm
= pFrm
->GetNext();
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
)
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
;
122 sal_uLong nIndex
= rCnt
.GetCntntIdx()->GetIndex();
123 ::_InsertCnt( this, pFmt
->GetDoc(), ++nIndex
);
127 void SwHeadFootFrm::FormatPrt(SwTwips
& nUL
, const SwBorderAttrs
* pAttrs
)
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;
143 nOverlap
= -nMinHeight
;
147 /* Calculate desired height of content. The minimal height has to be
151 if ( ! HasFixSize() )
152 nHeight
= lcl_CalcContentHeight(*this);
154 nHeight
= nMinHeight
;
156 if (nHeight
< nMinHeight
)
157 nHeight
= nMinHeight
;
159 /* calculate initial spacing/line space */
160 SwTwips nSpace
, nLine
;
164 nSpace
= pAttrs
->CalcBottom();
165 nLine
= pAttrs
->CalcBottomLine();
169 nSpace
= pAttrs
->CalcTop();
170 nLine
= pAttrs
->CalcTopLine();
173 /* calculate overlap and correct spacing */
174 nOverlap
+= nHeight
- nMinHeight
;
175 if (nOverlap
< nSpace
- nLine
)
180 /* calculate real vertical space between frame and print area */
182 nUL
= pAttrs
->CalcTop() + nSpace
;
184 nUL
= pAttrs
->CalcBottom() + nSpace
;
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));
193 maPrt
.Top(pAttrs
->CalcTop());
197 maPrt
.Width(maFrm
.Width() - nLR
);
201 if (nUL
< maFrm
.Height())
202 nNewHeight
= maFrm
.Height() - nUL
;
206 maPrt
.Height(nNewHeight
);
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
)
233 mbValidSize
= mbValidPrtArea
= sal_True
;
235 const SwTwips nBorder
= nUL
;
236 SwTwips nMinHeight
= lcl_GetFrmMinHeight(*this);
237 nMinHeight
-= pAttrs
->CalcTop();
238 nMinHeight
-= pAttrs
->CalcBottom();
245 SwTwips nMaxHeight
= LONG_MAX
;
246 SwTwips nRemaining
, nOldHeight
;
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();
258 aOldFooterPrtPos
!= ( Frm().Pos() + Prt().Pos() ) )
260 pFrm
->_InvalidatePos();
261 aOldFooterPrtPos
= Frm().Pos() + Prt().Pos();
266 // #i43771# - format also object anchored
268 // #i46941# - frame has to be valid.
269 // Note: frame could be invalid after calling its format,
271 OSL_ENSURE( StackHack::IsLocked() || !pFrm
->IsTxtFrm() ||
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
285 pFrm
= pFrm
->GetNext();
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
;
313 nMaxHeight
= nOldHeight
;
315 if( nRemaining
<= nMinHeight
)
316 nRemaining
= ( nMaxHeight
+ nMinHeight
+ 1 ) / 2;
320 if (nOldHeight
> nMinHeight
)
321 nMinHeight
= nOldHeight
;
323 if( nRemaining
>= nMaxHeight
)
324 nRemaining
= ( nMaxHeight
+ nMinHeight
+ 1 ) / 2;
327 nDiff
= nRemaining
- nOldHeight
;
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
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();
367 // Quickly update the position
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() );
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
;
400 } while ( !mbValidSize
);
404 void SwHeadFootFrm::Format(const SwBorderAttrs
* pAttrs
)
406 OSL_ENSURE( pAttrs
, "SwFooterFrm::Format, pAttrs is 0." );
408 if ( mbValidPrtArea
&& mbValidSize
)
411 if ( ! GetEatSpacing() && IsHeaderFrm())
413 SwLayoutFrm::Format(pAttrs
);
417 lcl_LayoutFrmEnsureMinHeight(*this, pAttrs
);
419 long nUL
= pAttrs
->CalcTop() + pAttrs
->CalcBottom();
421 if ( !mbValidPrtArea
)
422 FormatPrt(nUL
, pAttrs
);
425 FormatSize(nUL
, pAttrs
);
429 SwTwips
SwHeadFootFrm::GrowFrm( SwTwips nDist
, sal_Bool bTst
, sal_Bool bInfo
)
437 else if (!GetEatSpacing())
439 nResult
= SwLayoutFrm::GrowFrm(nDist
, bTst
, bInfo
);
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
453 SwTwips nEat
= nDist
;
456 /* calculate maximum eatable spacing */
458 nMaxEat
= maFrm
.Height() - maPrt
.Top() - maPrt
.Height() - pAttrs
->CalcBottomLine();
460 nMaxEat
= maPrt
.Top() - pAttrs
->CalcTopLine();
467 /* If the frame is too small, eat less spacing thus letting the frame
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. */
478 else if (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
484 sal_Bool bNotifyFlys
= sal_False
;
491 maPrt
.Top(maPrt
.Top() - nEat
);
492 maPrt
.Height(maPrt
.Height() - nEat
);
499 // OD 14.04.2003 #108719# - trigger fly frame notify.
502 bNotifyFlys
= sal_True
;
506 if (nDist
- nEat
> 0)
509 SwLayoutFrm::GrowFrm( nDist
- nEat
, bTst
, bInfo
);
514 bNotifyFlys
= sal_False
;
518 // OD 10.04.2003 #108719# - notify fly frames, if necessary and triggered.
519 if ( ( nResult
> 0 ) && bNotifyFlys
)
525 if ( nResult
&& !bTst
)
531 SwTwips
SwHeadFootFrm::ShrinkFrm( SwTwips nDist
, sal_Bool bTst
, sal_Bool bInfo
)
539 else if (! GetEatSpacing())
541 nResult
= SwLayoutFrm::ShrinkFrm(nDist
, bTst
, bInfo
);
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
558 SwTwips nBiggerThanMin
= nOldHeight
- nMinHeight
;
560 if (nBiggerThanMin
< nDist
)
562 nRest
= nDist
- nBiggerThanMin
;
564 /* info: declaration of nRest -> else nRest = 0 */
567 /* The frame cannot shrink. Provide shrinking by spitting out
571 // OD 10.04.2003 #108719# - Notify fly frame, if header/footer frame
572 // shrinks. Consider, that 'normal' shrink of layout frame already notifys
574 sal_Bool bNotifyFlys
= sal_False
;
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
587 - pAttrs
->CalcBottom();
589 if (nMinPrtHeight
< 0)
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
;
609 if (! IsHeaderFrm() )
611 maPrt
.Top(maPrt
.Top() + nShrink
);
612 maPrt
.Height(maPrt
.Height() - nShrink
);
618 // OD 14.04.2003 #108719# - trigger fly frame notify.
621 bNotifyFlys
= sal_True
;
625 /* The shrinking not providable by spitting out spacing has to be done
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
)
647 sal_Bool
SwHeadFootFrm::GetEatSpacing() const
649 const SwFrmFmt
* pFmt
= GetFmt();
650 OSL_ENSURE(pFmt
, "SwHeadFootFrm: no format?");
652 if (pFmt
->GetHeaderAndFooterEatSpacing().GetValue())
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
) )
689 void SwPageFrm::PrepareHeader()
691 SwLayoutFrm
*pLay
= (SwLayoutFrm
*)Lower();
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 );
714 OSL_ENSURE( pLay
, "Where to with the Header?" );
715 SwHeaderFrm
*pH
= new SwHeaderFrm( (SwFrmFmt
*)rH
.GetHeaderFmt(), this );
716 pH
->Paste( this, pLay
);
718 ::RegistFlys( this, pH
);
720 else if ( pLay
&& pLay
->IsHeaderFrm() )
721 { // Remove header if present.
722 ::DelFlys( pLay
, this );
727 /*************************************************************************
729 |* SwPageFrm::PrepareFooter()
731 |* Description Creates or removes footer
733 |*************************************************************************/
736 void SwPageFrm::PrepareFooter()
738 SwLayoutFrm
*pLay
= (SwLayoutFrm
*)Lower();
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 );
761 SwFooterFrm
*pF
= new SwFooterFrm( (SwFrmFmt
*)rF
.GetFooterFmt(), this );
764 ::RegistFlys( this, pF
);
766 else if ( pLay
&& pLay
->IsFooterFrm() )
767 { // Remove footer if already present
768 ::DelFlys( pLay
, this );
770 if ( pLay
->GetPrev() && 0 != (pShell
= getRootFrm()->GetCurrShell()) &&
771 pShell
->VisArea().HasArea() )
772 pShell
->InvalidateWindows( pShell
->VisArea() );
780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */