diff options
Diffstat (limited to 'sw/source/core/layout/colfrm.cxx')
-rw-r--r-- | sw/source/core/layout/colfrm.cxx | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/sw/source/core/layout/colfrm.cxx b/sw/source/core/layout/colfrm.cxx new file mode 100644 index 000000000000..f64752a18708 --- /dev/null +++ b/sw/source/core/layout/colfrm.cxx @@ -0,0 +1,483 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include "cntfrm.hxx" +#include "doc.hxx" + +#include "hintids.hxx" +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <fmtclds.hxx> +#include <fmtfordr.hxx> +#include <frmfmt.hxx> +#include <node.hxx> +#include "frmtool.hxx" +#include "colfrm.hxx" +#include "pagefrm.hxx" +#include "bodyfrm.hxx" // ColumnFrms jetzt mit BodyFrm +#include "rootfrm.hxx" // wg. RemoveFtns +#include "sectfrm.hxx" // wg. FtnAtEnd-Flag + +// ftnfrm.cxx: +void lcl_RemoveFtns( SwFtnBossFrm* pBoss, BOOL bPageOnly, BOOL bEndNotes ); + + +/************************************************************************* +|* +|* SwColumnFrm::SwColumnFrm() +|* +|* Ersterstellung MA ?? +|* Letzte Aenderung AMA 30. Oct 98 +|* +|*************************************************************************/ +SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt ): + SwFtnBossFrm( pFmt ) +{ + nType = FRMC_COLUMN; + SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt() ); + pColBody->InsertBehind( this, 0 ); // ColumnFrms jetzt mit BodyFrm + SetMaxFtnHeight( LONG_MAX ); +} + +SwColumnFrm::~SwColumnFrm() +{ + SwFrmFmt *pFmt = GetFmt(); + SwDoc *pDoc; + if ( !(pDoc = pFmt->GetDoc())->IsInDtor() && pFmt->IsLastDepend() ) + { + //Ich bin der einzige, weg mit dem Format. + //Vorher ummelden, damit die Basisklasse noch klarkommt. + pDoc->GetDfltFrmFmt()->Add( this ); + pDoc->DelFrmFmt( pFmt ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::ChgColumns() +|* +|* Ersterstellung MA 11. Feb. 93 +|* Letzte Aenderung MA 12. Oct. 98 +|* +|*************************************************************************/ + +void MA_FASTCALL lcl_RemoveColumns( SwLayoutFrm *pCont, USHORT nCnt ) +{ + ASSERT( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(), + "Keine Spalten zu entfernen." ); + + SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower(); + ::lcl_RemoveFtns( pColumn, TRUE, TRUE ); + while ( pColumn->GetNext() ) + { + ASSERT( pColumn->GetNext()->IsColumnFrm(), + "Nachbar von ColFrm kein ColFrm." ); + pColumn = (SwColumnFrm*)pColumn->GetNext(); + } + for ( USHORT i = 0; i < nCnt; ++i ) + { + SwColumnFrm *pTmp = (SwColumnFrm*)pColumn->GetPrev(); + pColumn->Cut(); + delete pColumn; //Format wird ggf. im DTor mit vernichtet. + pColumn = pTmp; + } +} + +SwLayoutFrm * MA_FASTCALL lcl_FindColumns( SwLayoutFrm *pLay, USHORT nCount ) +{ + SwFrm *pCol = pLay->Lower(); + if ( pLay->IsPageFrm() ) + pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower(); + + if ( pCol && pCol->IsColumnFrm() ) + { + SwFrm *pTmp = pCol; + USHORT i; + for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i ) + /* do nothing */; + return i == nCount ? (SwLayoutFrm*)pCol : 0; + } + return 0; +} + + +static BOOL lcl_AddColumns( SwLayoutFrm *pCont, USHORT nCount ) +{ + SwDoc *pDoc = pCont->GetFmt()->GetDoc(); + const BOOL bMod = pDoc->IsModified(); + + //Format sollen soweit moeglich geshared werden. Wenn es also schon einen + //Nachbarn mit den selben Spalteneinstellungen gibt, so koennen die + //Spalten an die selben Formate gehaengt werden. + //Der Nachbar kann ueber das Format gesucht werden, wer der Owner des Attributes + //ist, ist allerdings vom Frametyp abhaengig. + SwLayoutFrm *pAttrOwner = pCont; + if ( pCont->IsBodyFrm() ) + pAttrOwner = pCont->FindPageFrm(); + SwLayoutFrm *pNeighbourCol = 0; + SwClientIter aIter( *pAttrOwner->GetFmt() ); + SwLayoutFrm *pNeighbour = (SwLayoutFrm*)aIter.First( TYPE(SwLayoutFrm) ); + + USHORT nAdd = 0; + SwFrm *pCol = pCont->Lower(); + if ( pCol && pCol->IsColumnFrm() ) + for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd ) + /* do nothing */; + while ( pNeighbour ) + { + if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) && + pNeighbourCol != pCont ) + break; + pNeighbourCol = 0; + pNeighbour = (SwLayoutFrm*)aIter.Next(); + } + + BOOL bRet; + SwTwips nMax = pCont->IsPageBodyFrm() ? + pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX; + if ( pNeighbourCol ) + { + bRet = FALSE; + SwFrm *pTmp = pCont->Lower(); + while ( pTmp ) + { + pTmp = pTmp->GetNext(); + pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); + } + for ( USHORT i = 0; i < nCount; ++i ) + { + SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt() ); + pTmpCol->SetMaxFtnHeight( nMax ); + pTmpCol->InsertBefore( pCont, NULL ); + pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); + } + } + else + { + bRet = TRUE; + for ( USHORT i = 0; i < nCount; ++i ) + { + SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyStr, pDoc->GetDfltFrmFmt()); + SwColumnFrm *pTmp = new SwColumnFrm( pFmt ); + pTmp->SetMaxFtnHeight( nMax ); + pTmp->Paste( pCont ); + } + } + + if ( !bMod ) + pDoc->ResetModified(); + return bRet; +} + +/*-----------------21.09.99 15:42------------------- + * ChgColumns() adds or removes columns from a layoutframe. + * Normally, a layoutframe with a column attribut of 1 or 0 columns contains + * no columnframe. However, a sectionframe with "footnotes at the end" needs + * a columnframe. If the bChgFtn-flag is set, the columnframe will be inserted + * or remove, if necessary. + * --------------------------------------------------*/ + +void SwLayoutFrm::ChgColumns( const SwFmtCol &rOld, const SwFmtCol &rNew, + const BOOL bChgFtn ) +{ + if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn ) + return; + // --> OD 2009-08-12 #i97379# + // If current lower is a no text frame, then columns are not allowed + if ( Lower() && Lower()->IsNoTxtFrm() && + rNew.GetNumCols() > 1 ) + { + return; + } + // <-- + + USHORT nNewNum, nOldNum = 1; + if( Lower() && Lower()->IsColumnFrm() ) + { + SwFrm* pCol = Lower(); + while( 0 != (pCol=pCol->GetNext()) ) + ++nOldNum; + } + nNewNum = rNew.GetNumCols(); + if( !nNewNum ) + ++nNewNum; + BOOL bAtEnd; + if( IsSctFrm() ) + bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd(); + else + bAtEnd = FALSE; + + //Einstellung der Spaltenbreiten ist nur bei neuen Formaten notwendig. + BOOL bAdjustAttributes = nOldNum != rOld.GetNumCols(); + + //Wenn die Spaltenanzahl unterschiedlich ist, wird der Inhalt + //gesichert und restored. + SwFrm *pSave = 0; + if( nOldNum != nNewNum || bChgFtn ) + { + SwDoc *pDoc = GetFmt()->GetDoc(); + ASSERT( pDoc, "FrmFmt gibt kein Dokument her." ); + // SaveCntnt wuerde auch den Inhalt der Fussnotencontainer aufsaugen + // und im normalen Textfluss unterbringen. + if( IsPageBodyFrm() ) + pDoc->GetRootFrm()->RemoveFtns( (SwPageFrm*)GetUpper(), TRUE, FALSE ); + pSave = ::SaveCntnt( this ); + + //Wenn Spalten existieren, jetzt aber eine Spaltenanzahl von + //0 oder eins gewuenscht ist, so werden die Spalten einfach vernichtet. + if ( nNewNum == 1 && !bAtEnd ) + { + ::lcl_RemoveColumns( this, nOldNum ); + if ( IsBodyFrm() ) + SetFrmFmt( pDoc->GetDfltFrmFmt() ); + else + GetFmt()->SetFmtAttr( SwFmtFillOrder() ); + if ( pSave ) + ::RestoreCntnt( pSave, this, 0, true ); + return; + } + if ( nOldNum == 1 ) + { + if ( IsBodyFrm() ) + SetFrmFmt( pDoc->GetColumnContFmt() ); + else + GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) ); + if( !Lower() || !Lower()->IsColumnFrm() ) + --nOldNum; + } + if ( nOldNum > nNewNum ) + { + ::lcl_RemoveColumns( this, nOldNum - nNewNum ); + bAdjustAttributes = TRUE; + } + else if( nOldNum < nNewNum ) + { + USHORT nAdd = nNewNum - nOldNum; + bAdjustAttributes = lcl_AddColumns( this, nAdd ); + } + } + + if ( !bAdjustAttributes ) + { + if ( rOld.GetLineWidth() != rNew.GetLineWidth() || + rOld.GetWishWidth() != rNew.GetWishWidth() || + rOld.IsOrtho() != rNew.IsOrtho() ) + bAdjustAttributes = TRUE; + else + { + USHORT nCount = Min( rNew.GetColumns().Count(), rOld.GetColumns().Count() ); + for ( USHORT i = 0; i < nCount; ++i ) + if ( !(*rOld.GetColumns()[i] == *rNew.GetColumns()[i]) ) + { + bAdjustAttributes = TRUE; + break; + } + } + } + + //Sodele, jetzt koennen die Spalten bequem eingestellt werden. + AdjustColumns( &rNew, bAdjustAttributes ); + + //Erst jetzt den Inhalt restaurieren. Ein frueheres Restaurieren wuerde + //unnuetzte Aktionen beim Einstellen zur Folge haben. + if ( pSave ) + { + ASSERT( Lower() && Lower()->IsLayoutFrm() && + ((SwLayoutFrm*)Lower())->Lower() && + ((SwLayoutFrm*)Lower())->Lower()->IsLayoutFrm(), + "Gesucht: Spaltenbody (Tod oder Lebend)." ); // ColumnFrms jetzt mit BodyFrm + ::RestoreCntnt( pSave, (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower(), 0, true ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::AdjustColumns() +|* +|* Ersterstellung MA 19. Jan. 99 +|* Letzte Aenderung MA 19. Jan. 99 +|* +|*************************************************************************/ + +void SwLayoutFrm::AdjustColumns( const SwFmtCol *pAttr, BOOL bAdjustAttributes ) +{ + if( !Lower()->GetNext() ) + { + Lower()->ChgSize( Prt().SSize() ); + return; + } + + const BOOL bVert = IsVertical(); + SwRectFn fnRect = bVert ? fnRectVert : fnRectHori; + + //Ist ein Pointer da, oder sollen wir die Attribute einstellen, + //so stellen wir auf jeden Fall die Spaltenbreiten ein. Andernfalls + //checken wir, ob eine Einstellung notwendig ist. + if ( !pAttr ) + { + pAttr = &GetFmt()->GetCol(); + if ( !bAdjustAttributes ) + { + long nAvail = (Prt().*fnRect->fnGetWidth)(); + for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower(); + pCol; + pCol = (SwLayoutFrm*)pCol->GetNext() ) + nAvail -= (pCol->Frm().*fnRect->fnGetWidth)(); + if ( !nAvail ) + return; + } + } + + //Sodele, jetzt koennen die Spalten bequem eingestellt werden. + //Die Breiten werden mitgezaehlt, damit wir dem letzten den Rest geben + //koennen. + SwTwips nAvail = (Prt().*fnRect->fnGetWidth)(); + const BOOL bLine = pAttr->GetLineAdj() != COLADJ_NONE; + const USHORT nMin = bLine ? USHORT( 20 + ( pAttr->GetLineWidth() / 2) ) : 0; + + const BOOL bR2L = IsRightToLeft(); + SwFrm *pCol = bR2L ? GetLastLower() : Lower(); + + // --> FME 2004-07-16 #i27399# + // bOrtho means we have to adjust the column frames manually. Otherwise + // we may use the values returned by CalcColWidth: + const BOOL bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0; + long nGutter = 0; + // <-- + + for ( USHORT i = 0; i < pAttr->GetNumCols(); ++i ) + { + if( !bOrtho ) + { + const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ? + nAvail : + pAttr->CalcColWidth( i, USHORT( (Prt().*fnRect->fnGetWidth)() ) ); + + const Size aColSz = bVert ? + Size( Prt().Width(), nWidth ) : + Size( nWidth, Prt().Height() ); + + pCol->ChgSize( aColSz ); + + // Hierdurch werden die ColumnBodyFrms von Seitenspalten angepasst und + // ihr bFixHeight-Flag wird gesetzt, damit sie nicht schrumpfen/wachsen. + // Bei Rahmenspalten hingegen soll das Flag _nicht_ gesetzt werden, + // da BodyFrms in Rahmenspalten durchaus wachsen/schrumpfen duerfen. + if( IsBodyFrm() ) + ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz ); + + nAvail -= nWidth; + } + + if ( bOrtho || bAdjustAttributes ) + { + const SwColumn *pC = pAttr->GetColumns()[i]; + const SwAttrSet* pSet = pCol->GetAttrSet(); + SvxLRSpaceItem aLR( pSet->GetLRSpace() ); + + //Damit die Trennlinien Platz finden, muessen sie hier + //Beruecksichtigung finden. Ueberall wo zwei Spalten aufeinanderstossen + //wird jeweils rechts bzw. links ein Sicherheitsabstand von 20 plus + //der halben Penbreite einkalkuliert. + const USHORT nLeft = pC->GetLeft(); + const USHORT nRight = pC->GetRight(); + + aLR.SetLeft ( nLeft ); + aLR.SetRight( nRight ); + + if ( bLine ) + { + if ( i == 0 ) + { + aLR.SetRight( Max( nRight, nMin ) ); + } + else if ( i == pAttr->GetNumCols() - 1 ) + { + aLR.SetLeft ( Max( nLeft, nMin ) ); + } + else + { + aLR.SetLeft ( Max( nLeft, nMin ) ); + aLR.SetRight( Max( nRight, nMin ) ); + } + } + + if ( bAdjustAttributes ) + { + SvxULSpaceItem aUL( pSet->GetULSpace() ); + aUL.SetUpper( pC->GetUpper()); + aUL.SetLower( pC->GetLower()); + + ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aLR ); + ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aUL ); + } + + nGutter += aLR.GetLeft() + aLR.GetRight(); + } + + pCol = bR2L ? pCol->GetPrev() : pCol->GetNext(); + } + + if( bOrtho ) + { + long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols(); + pCol = Lower(); + for( USHORT i = 0; i < pAttr->GetNumCols(); pCol = pCol->GetNext(), ++i ) + { + SwTwips nWidth; + if ( i == pAttr->GetNumCols() - 1 ) + nWidth = nAvail; + else + { + SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() ); + nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight(); + } + if( nWidth < 0 ) + nWidth = 0; + + const Size aColSz = bVert ? + Size( Prt().Width(), nWidth ) : + Size( nWidth, Prt().Height() ); + + pCol->ChgSize( aColSz ); + + if( IsBodyFrm() ) + ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz ); + + nAvail -= nWidth; + } + } +} + + + + + |