merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / layout / colfrm.cxx
blob8515889c10dc939ed8a2b61c083c1779e7d1c553
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 $
10 * $Revision: 1.20 $
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>
35 #include "cntfrm.hxx"
36 #include "doc.hxx"
38 #include "hintids.hxx"
39 #include <svx/ulspitem.hxx>
40 #include <svx/lrspitem.hxx>
41 #include <fmtclds.hxx>
42 #include <fmtfordr.hxx>
43 #include <frmfmt.hxx>
44 #include <node.hxx>
45 #include "frmtool.hxx"
46 #include "colfrm.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
52 // ftnfrm.cxx:
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 ):
65 SwFtnBossFrm( pFmt )
67 nType = FRMC_COLUMN;
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();
76 SwDoc *pDoc;
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();
111 pColumn->Cut();
112 delete pColumn; //Format wird ggf. im DTor mit vernichtet.
113 pColumn = pTmp;
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() )
125 SwFrm *pTmp = pCol;
126 USHORT i;
127 for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i )
128 /* do nothing */;
129 return i == nCount ? (SwLayoutFrm*)pCol : 0;
131 return 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) );
152 USHORT nAdd = 0;
153 SwFrm *pCol = pCont->Lower();
154 if ( pCol && pCol->IsColumnFrm() )
155 for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd )
156 /* do nothing */;
157 while ( pNeighbour )
159 if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) &&
160 pNeighbourCol != pCont )
161 break;
162 pNeighbourCol = 0;
163 pNeighbour = (SwLayoutFrm*)aIter.Next();
166 BOOL bRet;
167 SwTwips nMax = pCont->IsPageBodyFrm() ?
168 pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX;
169 if ( pNeighbourCol )
171 bRet = FALSE;
172 SwFrm *pTmp = pCont->Lower();
173 while ( pTmp )
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();
186 else
188 bRet = TRUE;
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 );
198 if ( !bMod )
199 pDoc->ResetModified();
200 return bRet;
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,
212 const BOOL bChgFtn )
214 if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn )
215 return;
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 )
221 return;
223 // <--
225 USHORT nNewNum, nOldNum = 1;
226 if( Lower() && Lower()->IsColumnFrm() )
228 SwFrm* pCol = Lower();
229 while( 0 != (pCol=pCol->GetNext()) )
230 ++nOldNum;
232 nNewNum = rNew.GetNumCols();
233 if( !nNewNum )
234 ++nNewNum;
235 BOOL bAtEnd;
236 if( IsSctFrm() )
237 bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd();
238 else
239 bAtEnd = FALSE;
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.
246 SwFrm *pSave = 0;
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 );
262 if ( IsBodyFrm() )
263 SetFrmFmt( pDoc->GetDfltFrmFmt() );
264 else
265 GetFmt()->SetFmtAttr( SwFmtFillOrder() );
266 if ( pSave )
267 ::RestoreCntnt( pSave, this, 0, true );
268 return;
270 if ( nOldNum == 1 )
272 if ( IsBodyFrm() )
273 SetFrmFmt( pDoc->GetColumnContFmt() );
274 else
275 GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) );
276 if( !Lower() || !Lower()->IsColumnFrm() )
277 --nOldNum;
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;
297 else
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;
304 break;
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.
314 if ( pSave )
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() );
338 return;
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.
347 if ( !pAttr )
349 pAttr = &GetFmt()->GetCol();
350 if ( !bAdjustAttributes )
352 long nAvail = (Prt().*fnRect->fnGetWidth)();
353 for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower();
354 pCol;
355 pCol = (SwLayoutFrm*)pCol->GetNext() )
356 nAvail -= (pCol->Frm().*fnRect->fnGetWidth)();
357 if ( !nAvail )
358 return;
362 //Sodele, jetzt koennen die Spalten bequem eingestellt werden.
363 //Die Breiten werden mitgezaehlt, damit wir dem letzten den Rest geben
364 //koennen.
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;
376 long nGutter = 0;
377 // <--
379 for ( USHORT i = 0; i < pAttr->GetNumCols(); ++i )
381 if( !bOrtho )
383 const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ?
384 nAvail :
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.
397 if( IsBodyFrm() )
398 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
400 nAvail -= nWidth;
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 );
419 if ( bLine )
421 if ( i == 0 )
423 aLR.SetRight( Max( nRight, nMin ) );
425 else if ( i == pAttr->GetNumCols() - 1 )
427 aLR.SetLeft ( Max( nLeft, nMin ) );
429 else
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();
452 if( bOrtho )
454 long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols();
455 pCol = Lower();
456 for( USHORT i = 0; i < pAttr->GetNumCols(); pCol = pCol->GetNext(), ++i )
458 SwTwips nWidth;
459 if ( i == pAttr->GetNumCols() - 1 )
460 nWidth = nAvail;
461 else
463 SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() );
464 nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight();
466 if( nWidth < 0 )
467 nWidth = 0;
469 const Size aColSz = bVert ?
470 Size( Prt().Width(), nWidth ) :
471 Size( nWidth, Prt().Height() );
473 pCol->ChgSize( aColSz );
475 if( IsBodyFrm() )
476 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
478 nAvail -= nWidth;