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: colfrm.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 <hintids.hxx>
38 #include "hintids.hxx"
39 #include <svx/ulspitem.hxx>
40 #include <svx/lrspitem.hxx>
41 #include <fmtclds.hxx>
42 #include <fmtfordr.hxx>
45 #include "frmtool.hxx"
47 #include "pagefrm.hxx"
48 #include "bodyfrm.hxx" // ColumnFrms jetzt mit BodyFrm
49 #include "rootfrm.hxx" // wg. RemoveFtns
50 #include "sectfrm.hxx" // wg. FtnAtEnd-Flag
53 void lcl_RemoveFtns( SwFtnBossFrm
* pBoss
, BOOL bPageOnly
, BOOL bEndNotes
);
56 /*************************************************************************
58 |* SwColumnFrm::SwColumnFrm()
60 |* Ersterstellung MA ??
61 |* Letzte Aenderung AMA 30. Oct 98
63 |*************************************************************************/
64 SwColumnFrm::SwColumnFrm( SwFrmFmt
*pFmt
):
68 SwBodyFrm
* pColBody
= new SwBodyFrm( pFmt
->GetDoc()->GetDfltFrmFmt() );
69 pColBody
->InsertBehind( this, 0 ); // ColumnFrms jetzt mit BodyFrm
70 SetMaxFtnHeight( LONG_MAX
);
73 SwColumnFrm::~SwColumnFrm()
75 SwFrmFmt
*pFmt
= GetFmt();
77 if ( !(pDoc
= pFmt
->GetDoc())->IsInDtor() && pFmt
->IsLastDepend() )
79 //Ich bin der einzige, weg mit dem Format.
80 //Vorher ummelden, damit die Basisklasse noch klarkommt.
81 pDoc
->GetDfltFrmFmt()->Add( this );
82 pDoc
->DelFrmFmt( pFmt
);
86 /*************************************************************************
88 |* SwLayoutFrm::ChgColumns()
90 |* Ersterstellung MA 11. Feb. 93
91 |* Letzte Aenderung MA 12. Oct. 98
93 |*************************************************************************/
95 void MA_FASTCALL
lcl_RemoveColumns( SwLayoutFrm
*pCont
, USHORT nCnt
)
97 ASSERT( pCont
&& pCont
->Lower() && pCont
->Lower()->IsColumnFrm(),
98 "Keine Spalten zu entfernen." );
100 SwColumnFrm
*pColumn
= (SwColumnFrm
*)pCont
->Lower();
101 ::lcl_RemoveFtns( pColumn
, TRUE
, TRUE
);
102 while ( pColumn
->GetNext() )
104 ASSERT( pColumn
->GetNext()->IsColumnFrm(),
105 "Nachbar von ColFrm kein ColFrm." );
106 pColumn
= (SwColumnFrm
*)pColumn
->GetNext();
108 for ( USHORT i
= 0; i
< nCnt
; ++i
)
110 SwColumnFrm
*pTmp
= (SwColumnFrm
*)pColumn
->GetPrev();
112 delete pColumn
; //Format wird ggf. im DTor mit vernichtet.
117 SwLayoutFrm
* MA_FASTCALL
lcl_FindColumns( SwLayoutFrm
*pLay
, USHORT nCount
)
119 SwFrm
*pCol
= pLay
->Lower();
120 if ( pLay
->IsPageFrm() )
121 pCol
= ((SwPageFrm
*)pLay
)->FindBodyCont()->Lower();
123 if ( pCol
&& pCol
->IsColumnFrm() )
127 for ( i
= 0; pTmp
; pTmp
= pTmp
->GetNext(), ++i
)
129 return i
== nCount
? (SwLayoutFrm
*)pCol
: 0;
135 static BOOL
lcl_AddColumns( SwLayoutFrm
*pCont
, USHORT nCount
)
137 SwDoc
*pDoc
= pCont
->GetFmt()->GetDoc();
138 const BOOL bMod
= pDoc
->IsModified();
140 //Format sollen soweit moeglich geshared werden. Wenn es also schon einen
141 //Nachbarn mit den selben Spalteneinstellungen gibt, so koennen die
142 //Spalten an die selben Formate gehaengt werden.
143 //Der Nachbar kann ueber das Format gesucht werden, wer der Owner des Attributes
144 //ist, ist allerdings vom Frametyp abhaengig.
145 SwLayoutFrm
*pAttrOwner
= pCont
;
146 if ( pCont
->IsBodyFrm() )
147 pAttrOwner
= pCont
->FindPageFrm();
148 SwLayoutFrm
*pNeighbourCol
= 0;
149 SwClientIter
aIter( *pAttrOwner
->GetFmt() );
150 SwLayoutFrm
*pNeighbour
= (SwLayoutFrm
*)aIter
.First( TYPE(SwLayoutFrm
) );
153 SwFrm
*pCol
= pCont
->Lower();
154 if ( pCol
&& pCol
->IsColumnFrm() )
155 for ( nAdd
= 1; pCol
; pCol
= pCol
->GetNext(), ++nAdd
)
159 if ( 0 != (pNeighbourCol
= lcl_FindColumns( pNeighbour
, nCount
+nAdd
)) &&
160 pNeighbourCol
!= pCont
)
163 pNeighbour
= (SwLayoutFrm
*)aIter
.Next();
167 SwTwips nMax
= pCont
->IsPageBodyFrm() ?
168 pCont
->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX
;
172 SwFrm
*pTmp
= pCont
->Lower();
175 pTmp
= pTmp
->GetNext();
176 pNeighbourCol
= (SwLayoutFrm
*)pNeighbourCol
->GetNext();
178 for ( USHORT i
= 0; i
< nCount
; ++i
)
180 SwColumnFrm
*pTmpCol
= new SwColumnFrm( pNeighbourCol
->GetFmt() );
181 pTmpCol
->SetMaxFtnHeight( nMax
);
182 pTmpCol
->InsertBefore( pCont
, NULL
);
183 pNeighbourCol
= (SwLayoutFrm
*)pNeighbourCol
->GetNext();
189 for ( USHORT i
= 0; i
< nCount
; ++i
)
191 SwFrmFmt
*pFmt
= pDoc
->MakeFrmFmt( aEmptyStr
, pDoc
->GetDfltFrmFmt());
192 SwColumnFrm
*pTmp
= new SwColumnFrm( pFmt
);
193 pTmp
->SetMaxFtnHeight( nMax
);
194 pTmp
->Paste( pCont
);
199 pDoc
->ResetModified();
203 /*-----------------21.09.99 15:42-------------------
204 * ChgColumns() adds or removes columns from a layoutframe.
205 * Normally, a layoutframe with a column attribut of 1 or 0 columns contains
206 * no columnframe. However, a sectionframe with "footnotes at the end" needs
207 * a columnframe. If the bChgFtn-flag is set, the columnframe will be inserted
208 * or remove, if necessary.
209 * --------------------------------------------------*/
211 void SwLayoutFrm::ChgColumns( const SwFmtCol
&rOld
, const SwFmtCol
&rNew
,
214 if ( rOld
.GetNumCols() <= 1 && rNew
.GetNumCols() <= 1 && !bChgFtn
)
216 // --> OD 2009-08-12 #i97379#
217 // If current lower is a no text frame, then columns are not allowed
218 if ( Lower() && Lower()->IsNoTxtFrm() &&
219 rNew
.GetNumCols() > 1 )
225 USHORT nNewNum
, nOldNum
= 1;
226 if( Lower() && Lower()->IsColumnFrm() )
228 SwFrm
* pCol
= Lower();
229 while( 0 != (pCol
=pCol
->GetNext()) )
232 nNewNum
= rNew
.GetNumCols();
237 bAtEnd
= ((SwSectionFrm
*)this)->IsAnyNoteAtEnd();
241 //Einstellung der Spaltenbreiten ist nur bei neuen Formaten notwendig.
242 BOOL bAdjustAttributes
= nOldNum
!= rOld
.GetNumCols();
244 //Wenn die Spaltenanzahl unterschiedlich ist, wird der Inhalt
245 //gesichert und restored.
247 if( nOldNum
!= nNewNum
|| bChgFtn
)
249 SwDoc
*pDoc
= GetFmt()->GetDoc();
250 ASSERT( pDoc
, "FrmFmt gibt kein Dokument her." );
251 // SaveCntnt wuerde auch den Inhalt der Fussnotencontainer aufsaugen
252 // und im normalen Textfluss unterbringen.
253 if( IsPageBodyFrm() )
254 pDoc
->GetRootFrm()->RemoveFtns( (SwPageFrm
*)GetUpper(), TRUE
, FALSE
);
255 pSave
= ::SaveCntnt( this );
257 //Wenn Spalten existieren, jetzt aber eine Spaltenanzahl von
258 //0 oder eins gewuenscht ist, so werden die Spalten einfach vernichtet.
259 if ( nNewNum
== 1 && !bAtEnd
)
261 ::lcl_RemoveColumns( this, nOldNum
);
263 SetFrmFmt( pDoc
->GetDfltFrmFmt() );
265 GetFmt()->SetFmtAttr( SwFmtFillOrder() );
267 ::RestoreCntnt( pSave
, this, 0, true );
273 SetFrmFmt( pDoc
->GetColumnContFmt() );
275 GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT
) );
276 if( !Lower() || !Lower()->IsColumnFrm() )
279 if ( nOldNum
> nNewNum
)
281 ::lcl_RemoveColumns( this, nOldNum
- nNewNum
);
282 bAdjustAttributes
= TRUE
;
284 else if( nOldNum
< nNewNum
)
286 USHORT nAdd
= nNewNum
- nOldNum
;
287 bAdjustAttributes
= lcl_AddColumns( this, nAdd
);
291 if ( !bAdjustAttributes
)
293 if ( rOld
.GetLineWidth() != rNew
.GetLineWidth() ||
294 rOld
.GetWishWidth() != rNew
.GetWishWidth() ||
295 rOld
.IsOrtho() != rNew
.IsOrtho() )
296 bAdjustAttributes
= TRUE
;
299 USHORT nCount
= Min( rNew
.GetColumns().Count(), rOld
.GetColumns().Count() );
300 for ( USHORT i
= 0; i
< nCount
; ++i
)
301 if ( !(*rOld
.GetColumns()[i
] == *rNew
.GetColumns()[i
]) )
303 bAdjustAttributes
= TRUE
;
309 //Sodele, jetzt koennen die Spalten bequem eingestellt werden.
310 AdjustColumns( &rNew
, bAdjustAttributes
);
312 //Erst jetzt den Inhalt restaurieren. Ein frueheres Restaurieren wuerde
313 //unnuetzte Aktionen beim Einstellen zur Folge haben.
316 ASSERT( Lower() && Lower()->IsLayoutFrm() &&
317 ((SwLayoutFrm
*)Lower())->Lower() &&
318 ((SwLayoutFrm
*)Lower())->Lower()->IsLayoutFrm(),
319 "Gesucht: Spaltenbody (Tod oder Lebend)." ); // ColumnFrms jetzt mit BodyFrm
320 ::RestoreCntnt( pSave
, (SwLayoutFrm
*)((SwLayoutFrm
*)Lower())->Lower(), 0, true );
324 /*************************************************************************
326 |* SwLayoutFrm::AdjustColumns()
328 |* Ersterstellung MA 19. Jan. 99
329 |* Letzte Aenderung MA 19. Jan. 99
331 |*************************************************************************/
333 void SwLayoutFrm::AdjustColumns( const SwFmtCol
*pAttr
, BOOL bAdjustAttributes
)
335 if( !Lower()->GetNext() )
337 Lower()->ChgSize( Prt().SSize() );
341 const BOOL bVert
= IsVertical();
342 SwRectFn fnRect
= bVert
? fnRectVert
: fnRectHori
;
344 //Ist ein Pointer da, oder sollen wir die Attribute einstellen,
345 //so stellen wir auf jeden Fall die Spaltenbreiten ein. Andernfalls
346 //checken wir, ob eine Einstellung notwendig ist.
349 pAttr
= &GetFmt()->GetCol();
350 if ( !bAdjustAttributes
)
352 long nAvail
= (Prt().*fnRect
->fnGetWidth
)();
353 for ( SwLayoutFrm
*pCol
= (SwLayoutFrm
*)Lower();
355 pCol
= (SwLayoutFrm
*)pCol
->GetNext() )
356 nAvail
-= (pCol
->Frm().*fnRect
->fnGetWidth
)();
362 //Sodele, jetzt koennen die Spalten bequem eingestellt werden.
363 //Die Breiten werden mitgezaehlt, damit wir dem letzten den Rest geben
365 SwTwips nAvail
= (Prt().*fnRect
->fnGetWidth
)();
366 const BOOL bLine
= pAttr
->GetLineAdj() != COLADJ_NONE
;
367 const USHORT nMin
= bLine
? USHORT( 20 + ( pAttr
->GetLineWidth() / 2) ) : 0;
369 const BOOL bR2L
= IsRightToLeft();
370 SwFrm
*pCol
= bR2L
? GetLastLower() : Lower();
372 // --> FME 2004-07-16 #i27399#
373 // bOrtho means we have to adjust the column frames manually. Otherwise
374 // we may use the values returned by CalcColWidth:
375 const BOOL bOrtho
= pAttr
->IsOrtho() && pAttr
->GetNumCols() > 0;
379 for ( USHORT i
= 0; i
< pAttr
->GetNumCols(); ++i
)
383 const SwTwips nWidth
= i
== (pAttr
->GetNumCols() - 1) ?
385 pAttr
->CalcColWidth( i
, USHORT( (Prt().*fnRect
->fnGetWidth
)() ) );
387 const Size aColSz
= bVert
?
388 Size( Prt().Width(), nWidth
) :
389 Size( nWidth
, Prt().Height() );
391 pCol
->ChgSize( aColSz
);
393 // Hierdurch werden die ColumnBodyFrms von Seitenspalten angepasst und
394 // ihr bFixHeight-Flag wird gesetzt, damit sie nicht schrumpfen/wachsen.
395 // Bei Rahmenspalten hingegen soll das Flag _nicht_ gesetzt werden,
396 // da BodyFrms in Rahmenspalten durchaus wachsen/schrumpfen duerfen.
398 ((SwLayoutFrm
*)pCol
)->Lower()->ChgSize( aColSz
);
403 if ( bOrtho
|| bAdjustAttributes
)
405 const SwColumn
*pC
= pAttr
->GetColumns()[i
];
406 const SwAttrSet
* pSet
= pCol
->GetAttrSet();
407 SvxLRSpaceItem
aLR( pSet
->GetLRSpace() );
409 //Damit die Trennlinien Platz finden, muessen sie hier
410 //Beruecksichtigung finden. Ueberall wo zwei Spalten aufeinanderstossen
411 //wird jeweils rechts bzw. links ein Sicherheitsabstand von 20 plus
412 //der halben Penbreite einkalkuliert.
413 const USHORT nLeft
= pC
->GetLeft();
414 const USHORT nRight
= pC
->GetRight();
416 aLR
.SetLeft ( nLeft
);
417 aLR
.SetRight( nRight
);
423 aLR
.SetRight( Max( nRight
, nMin
) );
425 else if ( i
== pAttr
->GetNumCols() - 1 )
427 aLR
.SetLeft ( Max( nLeft
, nMin
) );
431 aLR
.SetLeft ( Max( nLeft
, nMin
) );
432 aLR
.SetRight( Max( nRight
, nMin
) );
436 if ( bAdjustAttributes
)
438 SvxULSpaceItem
aUL( pSet
->GetULSpace() );
439 aUL
.SetUpper( pC
->GetUpper());
440 aUL
.SetLower( pC
->GetLower());
442 ((SwLayoutFrm
*)pCol
)->GetFmt()->SetFmtAttr( aLR
);
443 ((SwLayoutFrm
*)pCol
)->GetFmt()->SetFmtAttr( aUL
);
446 nGutter
+= aLR
.GetLeft() + aLR
.GetRight();
449 pCol
= bR2L
? pCol
->GetPrev() : pCol
->GetNext();
454 long nInnerWidth
= ( nAvail
- nGutter
) / pAttr
->GetNumCols();
456 for( USHORT i
= 0; i
< pAttr
->GetNumCols(); pCol
= pCol
->GetNext(), ++i
)
459 if ( i
== pAttr
->GetNumCols() - 1 )
463 SvxLRSpaceItem
aLR( pCol
->GetAttrSet()->GetLRSpace() );
464 nWidth
= nInnerWidth
+ aLR
.GetLeft() + aLR
.GetRight();
469 const Size aColSz
= bVert
?
470 Size( Prt().Width(), nWidth
) :
471 Size( nWidth
, Prt().Height() );
473 pCol
->ChgSize( aColSz
);
476 ((SwLayoutFrm
*)pCol
)->Lower()->ChgSize( aColSz
);