| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 |
| #include "switerator.hxx" |
| |
| // ftnfrm.cxx: |
| void lcl_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes ); |
| |
| |
| /************************************************************************* |
| |* |
| |* SwColumnFrm::SwColumnFrm() |
| |* |
| |* Ersterstellung MA ?? |
| |* Letzte Aenderung AMA 30. Oct 98 |
| |* |
| |*************************************************************************/ |
| SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt, SwFrm* pSib ): |
| SwFtnBossFrm( pFmt, pSib ) |
| { |
| nType = FRMC_COLUMN; |
| SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt(), pSib ); |
| 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, sal_uInt16 nCnt ) |
| { |
| ASSERT( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(), |
| "Keine Spalten zu entfernen." ); |
| |
| SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower(); |
| ::lcl_RemoveFtns( pColumn, sal_True, sal_True ); |
| while ( pColumn->GetNext() ) |
| { |
| ASSERT( pColumn->GetNext()->IsColumnFrm(), |
| "Nachbar von ColFrm kein ColFrm." ); |
| pColumn = (SwColumnFrm*)pColumn->GetNext(); |
| } |
| for ( sal_uInt16 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, sal_uInt16 nCount ) |
| { |
| SwFrm *pCol = pLay->Lower(); |
| if ( pLay->IsPageFrm() ) |
| pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower(); |
| |
| if ( pCol && pCol->IsColumnFrm() ) |
| { |
| SwFrm *pTmp = pCol; |
| sal_uInt16 i; |
| for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i ) |
| /* do nothing */; |
| return i == nCount ? (SwLayoutFrm*)pCol : 0; |
| } |
| return 0; |
| } |
| |
| |
| static sal_Bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount ) |
| { |
| SwDoc *pDoc = pCont->GetFmt()->GetDoc(); |
| const sal_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; |
| SwIterator<SwLayoutFrm,SwFmt> aIter( *pAttrOwner->GetFmt() ); |
| SwLayoutFrm *pNeighbour = aIter.First(); |
| |
| sal_uInt16 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 = aIter.Next(); |
| } |
| |
| sal_Bool bRet; |
| SwTwips nMax = pCont->IsPageBodyFrm() ? |
| pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX; |
| if ( pNeighbourCol ) |
| { |
| bRet = sal_False; |
| SwFrm *pTmp = pCont->Lower(); |
| while ( pTmp ) |
| { |
| pTmp = pTmp->GetNext(); |
| pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); |
| } |
| for ( sal_uInt16 i = 0; i < nCount; ++i ) |
| { |
| SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt(), pCont ); |
| pTmpCol->SetMaxFtnHeight( nMax ); |
| pTmpCol->InsertBefore( pCont, NULL ); |
| pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); |
| } |
| } |
| else |
| { |
| bRet = sal_True; |
| for ( sal_uInt16 i = 0; i < nCount; ++i ) |
| { |
| SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyStr, pDoc->GetDfltFrmFmt()); |
| SwColumnFrm *pTmp = new SwColumnFrm( pFmt, pCont ); |
| 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 sal_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; |
| } |
| // <-- |
| |
| sal_uInt16 nNewNum, nOldNum = 1; |
| if( Lower() && Lower()->IsColumnFrm() ) |
| { |
| SwFrm* pCol = Lower(); |
| while( 0 != (pCol=pCol->GetNext()) ) |
| ++nOldNum; |
| } |
| nNewNum = rNew.GetNumCols(); |
| if( !nNewNum ) |
| ++nNewNum; |
| sal_Bool bAtEnd; |
| if( IsSctFrm() ) |
| bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd(); |
| else |
| bAtEnd = sal_False; |
| |
| //Einstellung der Spaltenbreiten ist nur bei neuen Formaten notwendig. |
| sal_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->GetCurrentLayout()->RemoveFtns( (SwPageFrm*)GetUpper(), sal_True, sal_False ); //swmod 080218 |
| 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 = sal_True; |
| } |
| else if( nOldNum < nNewNum ) |
| { |
| sal_uInt16 nAdd = nNewNum - nOldNum; |
| bAdjustAttributes = lcl_AddColumns( this, nAdd ); |
| } |
| } |
| |
| if ( !bAdjustAttributes ) |
| { |
| if ( rOld.GetLineWidth() != rNew.GetLineWidth() || |
| rOld.GetWishWidth() != rNew.GetWishWidth() || |
| rOld.IsOrtho() != rNew.IsOrtho() ) |
| bAdjustAttributes = sal_True; |
| else |
| { |
| sal_uInt16 nCount = Min( rNew.GetColumns().Count(), rOld.GetColumns().Count() ); |
| for ( sal_uInt16 i = 0; i < nCount; ++i ) |
| if ( !(*rOld.GetColumns()[i] == *rNew.GetColumns()[i]) ) |
| { |
| bAdjustAttributes = sal_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, sal_Bool bAdjustAttributes ) |
| { |
| if( !Lower()->GetNext() ) |
| { |
| Lower()->ChgSize( Prt().SSize() ); |
| return; |
| } |
| |
| const sal_Bool bVert = IsVertical(); |
| //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin |
| SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : 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 sal_Bool bLine = pAttr->GetLineAdj() != COLADJ_NONE; |
| const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0; |
| |
| const sal_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 sal_Bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0; |
| long nGutter = 0; |
| // <-- |
| |
| for ( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; ++i ) //i118878, value returned by GetNumCols() can't be trusted |
| { |
| if( !bOrtho ) |
| { |
| const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ? |
| nAvail : |
| pAttr->CalcColWidth( i, sal_uInt16( (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 sal_uInt16 nLeft = pC->GetLeft(); |
| const sal_uInt16 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( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; pCol = pCol->GetNext(), ++i ) //i118878, value returned by GetNumCols() can't be trusted |
| { |
| 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; |
| } |
| } |
| } |
| |
| |
| |
| |
| |