1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: hffrm.cxx,v $
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"
34 #include "pagefrm.hxx"
38 #include <fmtcntnt.hxx>
39 #include <fmthdft.hxx>
40 #include <fmtfsize.hxx>
43 #include "sectfrm.hxx"
45 #include "frmtool.hxx"
46 #include "dflyobj.hxx"
48 #include "ndindex.hxx"
49 #include "hfspacingitem.hxx"
50 // OD 2004-05-24 #i28701#
51 #include <sortedobjs.hxx>
52 // --> OD 2005-03-03 #i43771#
53 #include <objectformatter.hxx>
56 extern BOOL bObjsDirect
; //frmtool.cxx
58 static SwTwips
lcl_GetFrmMinHeight(const SwLayoutFrm
& rFrm
)
60 const SwFmtFrmSize
&rSz
= rFrm
.GetFmt()->GetFrmSize();
63 switch (rSz
.GetHeightSizeType())
66 nMinHeight
= rSz
.GetHeight();
79 static SwTwips
lcl_CalcContentHeight(SwLayoutFrm
& frm
)
81 SwFrm
* pFrm
= frm
.Lower();
83 SwTwips nRemaining
= 0;
90 nTmp
= pFrm
->Frm().Height();
92 if( pFrm
->IsTxtFrm() && ((SwTxtFrm
*)pFrm
)->IsUndersized() )
94 nTmp
= ((SwTxtFrm
*)pFrm
)->GetParHeight()
95 - pFrm
->Prt().Height();
96 // Dieser TxtFrm waere gern ein bisschen groesser
99 else if( pFrm
->IsSctFrm() && ((SwSectionFrm
*)pFrm
)->IsUndersized() )
101 nTmp
= ((SwSectionFrm
*)pFrm
)->Undersize();
104 pFrm
= pFrm
->GetNext();
112 static void lcl_LayoutFrmEnsureMinHeight(SwLayoutFrm
& rFrm
,
113 const SwBorderAttrs
* )
115 SwTwips nMinHeight
= lcl_GetFrmMinHeight(rFrm
);
117 if (rFrm
.Frm().Height() < nMinHeight
)
119 rFrm
.Grow(nMinHeight
- rFrm
.Frm().Height());
123 SwHeadFootFrm::SwHeadFootFrm( SwFrmFmt
* pFmt
, USHORT nTypeIn
)
127 SetDerivedVert( FALSE
);
129 const SwFmtCntnt
&rCnt
= pFmt
->GetCntnt();
131 ASSERT( rCnt
.GetCntntIdx(), "Kein Inhalt fuer Header." );
133 //Fuer Header Footer die Objekte gleich erzeugen lassen.
134 BOOL bOld
= bObjsDirect
;
136 ULONG nIndex
= rCnt
.GetCntntIdx()->GetIndex();
137 ::_InsertCnt( this, pFmt
->GetDoc(), ++nIndex
);
141 void SwHeadFootFrm::FormatPrt(SwTwips
& nUL
, const SwBorderAttrs
* pAttrs
)
145 /* The minimal height of the print area is the minimal height of the
146 frame without the height needed for borders and shadow. */
147 SwTwips nMinHeight
= lcl_GetFrmMinHeight(*this);
149 nMinHeight
-= pAttrs
->CalcTop();
150 nMinHeight
-= pAttrs
->CalcBottom();
152 /* If the minimal height of the print area is negative, try to
153 compensate by overlapping */
154 SwTwips nOverlap
= 0;
157 nOverlap
= -nMinHeight
;
161 /* Calculate desired height of content. The minimal height has to be
165 if ( ! HasFixSize() )
166 nHeight
= lcl_CalcContentHeight(*this);
168 nHeight
= nMinHeight
;
170 if (nHeight
< nMinHeight
)
171 nHeight
= nMinHeight
;
173 /* calculate initial spacing/line space */
174 SwTwips nSpace
, nLine
;
178 nSpace
= pAttrs
->CalcBottom();
179 nLine
= pAttrs
->CalcBottomLine();
183 nSpace
= pAttrs
->CalcTop();
184 nLine
= pAttrs
->CalcTopLine();
187 /* calculate overlap and correct spacing */
188 nOverlap
+= nHeight
- nMinHeight
;
189 if (nOverlap
< nSpace
- nLine
)
194 /* calculate real vertical space between frame and print area */
196 nUL
= pAttrs
->CalcTop() + nSpace
;
198 nUL
= pAttrs
->CalcBottom() + nSpace
;
201 // OD 23.01.2003 #106895# - add first parameter to <SwBorderAttrs::CalcRight(..)>
202 SwTwips nLR
= pAttrs
->CalcLeft( this ) + pAttrs
->CalcRight( this );
204 aPrt
.Left(pAttrs
->CalcLeft(this));
207 aPrt
.Top(pAttrs
->CalcTop());
211 aPrt
.Width(aFrm
.Width() - nLR
);
215 if (nUL
< aFrm
.Height())
216 nNewHeight
= aFrm
.Height() - nUL
;
220 aPrt
.Height(nNewHeight
);
225 //Position einstellen.
226 aPrt
.Left( pAttrs
->CalcLeft( this ) );
227 aPrt
.Top ( pAttrs
->CalcTop() );
229 //Sizes einstellen; die Groesse gibt der umgebende Frm vor, die
230 //die Raender werden einfach abgezogen.
231 // OD 23.01.2003 #106895# - add first parameter to <SwBorderAttrs::CalcRight(..)>
232 SwTwips nLR
= pAttrs
->CalcLeft( this ) + pAttrs
->CalcRight( this );
233 aPrt
.Width ( aFrm
.Width() - nLR
);
234 aPrt
.Height( aFrm
.Height()- nUL
);
238 bValidPrtArea
= TRUE
;
241 void SwHeadFootFrm::FormatSize(SwTwips nUL
, const SwBorderAttrs
* pAttrs
)
247 bValidSize
= bValidPrtArea
= TRUE
;
249 const SwTwips nBorder
= nUL
;
250 SwTwips nMinHeight
= lcl_GetFrmMinHeight(*this);
251 nMinHeight
-= pAttrs
->CalcTop();
252 nMinHeight
-= pAttrs
->CalcBottom();
259 SwTwips nMaxHeight
= LONG_MAX
;
260 SwTwips nRemaining
, nOldHeight
;
261 // --> OD 2006-05-24 #i64301#
262 // use the position of the footer printing area to control invalidation
263 // of the first footer content.
264 Point aOldFooterPrtPos
;
269 nOldHeight
= Prt().Height();
270 SwFrm
* pFrm
= Lower();
271 // --> OD 2006-05-24 #i64301#
273 aOldFooterPrtPos
!= ( Frm().Pos() + Prt().Pos() ) )
275 pFrm
->_InvalidatePos();
276 aOldFooterPrtPos
= Frm().Pos() + Prt().Pos();
282 // --> OD 2005-03-03 #i43771# - format also object anchored
284 // --> OD 2005-05-03 #i46941# - frame has to be valid.
285 // Note: frame could be invalid after calling its format,
287 ASSERT( StackHack::IsLocked() || !pFrm
->IsTxtFrm() ||
289 static_cast<SwTxtFrm
*>(pFrm
)->IsJoinLocked(),
290 "<SwHeadFootFrm::FormatSize(..)> - text frame invalid and not locked." );
291 if ( pFrm
->IsTxtFrm() && pFrm
->IsValid() )
293 if ( !SwObjectFormatter::FormatObjsAtFrm( *pFrm
,
294 *(pFrm
->FindPageFrm()) ) )
296 // restart format with first content
302 pFrm
= pFrm
->GetNext();
309 nRemaining
+= pFrm
->Frm().Height();
311 if( pFrm
->IsTxtFrm() &&
312 ((SwTxtFrm
*)pFrm
)->IsUndersized() )
313 // Dieser TxtFrm waere gern ein bisschen groesser
314 nRemaining
+= ((SwTxtFrm
*)pFrm
)->GetParHeight()
315 - pFrm
->Prt().Height();
316 else if( pFrm
->IsSctFrm() &&
317 ((SwSectionFrm
*)pFrm
)->IsUndersized() )
318 nRemaining
+= ((SwSectionFrm
*)pFrm
)->Undersize();
319 pFrm
= pFrm
->GetNext();
321 if ( nRemaining
< nMinHeight
)
322 nRemaining
= nMinHeight
;
324 SwTwips nDiff
= nRemaining
- nOldHeight
;
330 nMaxHeight
= nOldHeight
;
332 if( nRemaining
<= nMinHeight
)
333 nRemaining
= ( nMaxHeight
+ nMinHeight
+ 1 ) / 2;
337 if (nOldHeight
> nMinHeight
)
338 nMinHeight
= nOldHeight
;
340 if( nRemaining
>= nMaxHeight
)
341 nRemaining
= ( nMaxHeight
+ nMinHeight
+ 1 ) / 2;
344 nDiff
= nRemaining
- nOldHeight
;
357 if( pFrm
->IsTxtFrm())
359 SwTxtFrm
* pTmpFrm
= (SwTxtFrm
*) pFrm
;
360 if (pTmpFrm
->IsUndersized() )
362 pTmpFrm
->InvalidateSize();
363 pTmpFrm
->Prepare(PREP_ADJUST_FRM
);
366 /* #i3568# Undersized sections need to be
368 else if (pFrm
->IsSctFrm())
370 SwSectionFrm
* pTmpFrm
=
371 (SwSectionFrm
*) pFrm
;
372 if (pTmpFrm
->IsUndersized() )
374 pTmpFrm
->InvalidateSize();
375 pTmpFrm
->Prepare(PREP_ADJUST_FRM
);
378 pFrm
= pFrm
->GetNext();
384 //Schnell auf dem kurzen Dienstweg die Position updaten.
391 //Unterkante des Uppers nicht ueberschreiten.
392 if ( GetUpper() && Frm().Height() )
394 const SwTwips nDeadLine
= GetUpper()->Frm().Top() +
395 GetUpper()->Prt().Bottom();
396 const SwTwips nBot
= Frm().Bottom();
397 if ( nBot
> nDeadLine
)
399 Frm().Bottom( nDeadLine
);
400 Prt().SSize().Height() = Frm().Height() - nBorder
;
403 bValidSize
= bValidPrtArea
= TRUE
;
404 } while( nRemaining
<=nMaxHeight
&& nOldHeight
!=Prt().Height() );
407 bValidSize
= bValidPrtArea
= TRUE
;
409 else //if ( GetType() & 0x0018 )
413 if ( Frm().Height() != pAttrs
->GetSize().Height() )
414 ChgSize( Size( Frm().Width(), pAttrs
->GetSize().Height()));
417 } while ( !bValidSize
);
421 void SwHeadFootFrm::Format(const SwBorderAttrs
* pAttrs
)
423 ASSERT( pAttrs
, "SwFooterFrm::Format, pAttrs ist 0." );
425 if ( bValidPrtArea
&& bValidSize
)
428 if ( ! GetEatSpacing() && IsHeaderFrm())
430 SwLayoutFrm::Format(pAttrs
);
434 lcl_LayoutFrmEnsureMinHeight(*this, pAttrs
);
436 long nUL
= pAttrs
->CalcTop() + pAttrs
->CalcBottom();
438 if ( !bValidPrtArea
)
439 FormatPrt(nUL
, pAttrs
);
442 FormatSize(nUL
, pAttrs
);
446 SwTwips
SwHeadFootFrm::GrowFrm( SwTwips nDist
, BOOL bTst
, BOOL bInfo
)
454 else if (!GetEatSpacing())
456 nResult
= SwLayoutFrm::GrowFrm(nDist
, bTst
, bInfo
);
462 SwBorderAttrAccess
* pAccess
=
463 new SwBorderAttrAccess( SwFrm::GetCache(), this );
464 ASSERT(pAccess
, "no border attributes");
466 SwBorderAttrs
* pAttrs
= pAccess
->Get();
468 /* First assume the whole amount to grow can be provided by eating
470 SwTwips nEat
= nDist
;
473 /* calculate maximum eatable spacing */
475 nMaxEat
= aFrm
.Height() - aPrt
.Top() - aPrt
.Height() - pAttrs
->CalcBottomLine();
477 nMaxEat
= aPrt
.Top() - pAttrs
->CalcTopLine();
484 /* If the frame is too small, eat less spacing thus letting the frame
486 SwTwips nMinHeight
= lcl_GetFrmMinHeight(*this);
487 SwTwips nFrameTooSmall
= nMinHeight
- Frm().Height();
489 if (nFrameTooSmall
> 0)
490 nEat
-= nFrameTooSmall
;
492 /* No negative eating, not eating more than allowed. */
495 else if (nEat
> nMaxEat
)
498 // OD 10.04.2003 #108719# - Notify fly frame, if header frame
499 // grows. Consider, that 'normal' grow of layout frame already notifys
501 sal_Bool bNotifyFlys
= sal_False
;
508 aPrt
.Top(aPrt
.Top() - nEat
);
509 aPrt
.Height(aPrt
.Height() - nEat
);
516 // OD 14.04.2003 #108719# - trigger fly frame notify.
519 bNotifyFlys
= sal_True
;
523 if (nDist
- nEat
> 0)
526 SwLayoutFrm::GrowFrm( nDist
- nEat
, bTst
, bInfo
);
531 bNotifyFlys
= sal_False
;
535 // OD 10.04.2003 #108719# - notify fly frames, if necessary and triggered.
536 if ( ( nResult
> 0 ) && bNotifyFlys
)
542 if ( nResult
&& !bTst
)
548 SwTwips
SwHeadFootFrm::ShrinkFrm( SwTwips nDist
, BOOL bTst
, BOOL bInfo
)
556 else if (! GetEatSpacing())
558 nResult
= SwLayoutFrm::ShrinkFrm(nDist
, bTst
, bInfo
);
564 SwTwips nMinHeight
= lcl_GetFrmMinHeight(*this);
565 SwTwips nOldHeight
= Frm().Height();
566 SwTwips nRest
= 0; // Amount to shrink by spitting out spacing
568 if ( nOldHeight
>= nMinHeight
)
570 /* If the frame's height is bigger than its minimum height, shrink
571 the frame towards its minimum height. If this is not sufficient
572 to provide the shrinking requested provide the rest by spitting
575 SwTwips nBiggerThanMin
= nOldHeight
- nMinHeight
;
577 if (nBiggerThanMin
< nDist
)
579 nRest
= nDist
- nBiggerThanMin
;
581 /* info: declaration of nRest -> else nRest = 0 */
584 /* The frame cannot shrink. Provide shrinking by spitting out
588 // OD 10.04.2003 #108719# - Notify fly frame, if header/footer frame
589 // shrinks. Consider, that 'normal' shrink of layout frame already notifys
591 sal_Bool bNotifyFlys
= sal_False
;
595 SwBorderAttrAccess
* pAccess
=
596 new SwBorderAttrAccess( SwFrm::GetCache(), this );
597 ASSERT(pAccess
, "no border attributes");
599 SwBorderAttrs
* pAttrs
= pAccess
->Get();
601 /* minimal height of print area */
602 SwTwips nMinPrtHeight
= nMinHeight
604 - pAttrs
->CalcBottom();
606 if (nMinPrtHeight
< 0)
611 /* assume all shrinking can be provided */
612 SwTwips nShrink
= nRest
;
614 /* calculate maximum shrinking */
615 SwTwips nMaxShrink
= aPrt
.Height() - nMinPrtHeight
;
617 /* shrink no more than maximum shrinking */
618 if (nShrink
> nMaxShrink
)
620 //nRest -= nShrink - nMaxShrink;
621 nShrink
= nMaxShrink
;
626 if (! IsHeaderFrm() )
628 aPrt
.Top(aPrt
.Top() + nShrink
);
629 aPrt
.Height(aPrt
.Height() - nShrink
);
635 // OD 14.04.2003 #108719# - trigger fly frame notify.
638 bNotifyFlys
= sal_True
;
642 /* The shrinking not providable by spitting out spacing has to be done
644 if (nDist
- nRest
> 0)
646 SwTwips nShrinkAmount
= SwLayoutFrm::ShrinkFrm( nDist
- nRest
, bTst
, bInfo
);
647 nResult
+= nShrinkAmount
;
648 if ( nShrinkAmount
> 0 )
650 bNotifyFlys
= sal_False
;
654 // OD 10.04.2003 #108719# - notify fly frames, if necessary.
655 if ( ( nResult
> 0 ) && bNotifyFlys
)
664 BOOL
SwHeadFootFrm::GetEatSpacing() const
666 const SwFrmFmt
* pFmt
= GetFmt();
667 ASSERT(pFmt
, "SwHeadFootFrm: no format?");
669 if (pFmt
->GetHeaderAndFooterEatSpacing().GetValue())
676 /*************************************************************************
678 |* SwPageFrm::PrepareHeader()
680 |* Beschreibung Erzeugt oder Entfernt Header
681 |* Ersterstellung MA 04. Feb. 93
682 |* Letzte Aenderung MA 12. May. 96
684 |*************************************************************************/
687 void DelFlys( SwLayoutFrm
*pFrm
, SwPageFrm
*pPage
)
689 for ( int i
= 0; pPage
->GetSortedObjs() &&
690 pPage
->GetSortedObjs()->Count() &&
691 i
< (int)pPage
->GetSortedObjs()->Count(); ++i
)
693 SwAnchoredObject
* pObj
= (*pPage
->GetSortedObjs())[i
];
694 if ( pObj
->ISA(SwFlyFrm
) )
696 SwFlyFrm
* pFlyFrm
= static_cast<SwFlyFrm
*>(pObj
);
697 if ( pFrm
->IsAnLower( pFlyFrm
) )
708 void SwPageFrm::PrepareHeader()
710 SwLayoutFrm
*pLay
= (SwLayoutFrm
*)Lower();
714 const SwFmtHeader
&rH
= ((SwFrmFmt
*)pRegisteredIn
)->GetHeader();
716 const BOOL bOn
= !((SwFrmFmt
*)pRegisteredIn
)->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE
);
718 if ( bOn
&& rH
.IsActive() )
719 { //Header einsetzen, vorher entfernen falls vorhanden.
720 ASSERT( rH
.GetHeaderFmt(), "FrmFmt fuer Header nicht gefunden." );
722 if ( pLay
->GetFmt() == (SwFrmFmt
*)rH
.GetHeaderFmt() )
723 return; //Der Footer ist bereits der richtige
725 if ( pLay
->IsHeaderFrm() )
726 { SwLayoutFrm
*pDel
= pLay
;
727 pLay
= (SwLayoutFrm
*)pLay
->GetNext();
728 ::DelFlys( pDel
, this );
732 ASSERT( pLay
, "Wohin mit dem Header?" );
733 SwHeaderFrm
*pH
= new SwHeaderFrm( (SwFrmFmt
*)rH
.GetHeaderFmt() );
734 pH
->Paste( this, pLay
);
736 ::RegistFlys( this, pH
);
738 else if ( pLay
&& pLay
->IsHeaderFrm() )
739 { //Header entfernen falls vorhanden.
740 ::DelFlys( pLay
, this );
745 /*************************************************************************
747 |* SwPageFrm::PrepareFooter()
749 |* Beschreibung Erzeugt oder Entfernt Footer
750 |* Ersterstellung MA 04. Feb. 93
751 |* Letzte Aenderung MA 12. May. 96
753 |*************************************************************************/
756 void SwPageFrm::PrepareFooter()
758 SwLayoutFrm
*pLay
= (SwLayoutFrm
*)Lower();
762 const SwFmtFooter
&rF
= ((SwFrmFmt
*)pRegisteredIn
)->GetFooter();
763 while ( pLay
->GetNext() )
764 pLay
= (SwLayoutFrm
*)pLay
->GetNext();
766 const BOOL bOn
= !((SwFrmFmt
*)pRegisteredIn
)->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE
);
768 if ( bOn
&& rF
.IsActive() )
769 { //Footer einsetzen, vorher entfernen falls vorhanden.
770 ASSERT( rF
.GetFooterFmt(), "FrmFmt fuer Footer nicht gefunden." );
772 if ( pLay
->GetFmt() == (SwFrmFmt
*)rF
.GetFooterFmt() )
773 return; //Der Footer ist bereits der richtige.
775 if ( pLay
->IsFooterFrm() )
776 { ::DelFlys( pLay
, this );
780 SwFooterFrm
*pF
= new SwFooterFrm( (SwFrmFmt
*)rF
.GetFooterFmt() );
783 ::RegistFlys( this, pF
);
785 else if ( pLay
&& pLay
->IsFooterFrm() )
786 { //Footer entfernen falls vorhanden.
787 ::DelFlys( pLay
, this );
789 if ( pLay
->GetPrev() && 0 != (pSh
= GetShell()) &&
790 pSh
->VisArea().HasArea() )
791 pSh
->InvalidateWindows( pSh
->VisArea() );