LCOV - code coverage report
Current view: top level - sw/source/core/layout - colfrm.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 184 202 91.1 %
Date: 2014-11-03 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <editeng/ulspitem.hxx>
      21             : #include <fmtclds.hxx>
      22             : #include <fmtfordr.hxx>
      23             : #include <frmfmt.hxx>
      24             : #include "frmtool.hxx"
      25             : #include "colfrm.hxx"
      26             : #include "pagefrm.hxx"
      27             : #include "bodyfrm.hxx"
      28             : #include "rootfrm.hxx"
      29             : #include "sectfrm.hxx"
      30             : #include "switerator.hxx"
      31             : #include "ftnfrm.hxx"
      32             : #include <IDocumentState.hxx>
      33             : #include <IDocumentLayoutAccess.hxx>
      34             : 
      35        1478 : SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt, SwFrm* pSib ):
      36        1478 :     SwFtnBossFrm( pFmt, pSib )
      37             : {
      38        1478 :     mnType = FRMC_COLUMN;
      39        1478 :     SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt(), pSib );
      40        1478 :     pColBody->InsertBehind( this, 0 ); // ColumnFrms now with BodyFrm
      41        1478 :     SetMaxFtnHeight( LONG_MAX );
      42        1478 : }
      43             : 
      44        4434 : SwColumnFrm::~SwColumnFrm()
      45             : {
      46        1478 :     SwFrmFmt *pFmt = GetFmt();
      47             :     SwDoc *pDoc;
      48        1478 :     if ( !(pDoc = pFmt->GetDoc())->IsInDtor() && pFmt->IsLastDepend() )
      49             :     {
      50             :         //I'm the only one, delete the format.
      51             :         //Get default format before, so the base class can cope with it.
      52         374 :         pDoc->GetDfltFrmFmt()->Add( this );
      53         374 :         pDoc->DelFrmFmt( pFmt );
      54             :     }
      55        2956 : }
      56             : 
      57           2 : static void lcl_RemoveColumns( SwLayoutFrm *pCont, sal_uInt16 nCnt )
      58             : {
      59             :     OSL_ENSURE( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(),
      60             :             "no columns to remove." );
      61             : 
      62           2 :     SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower();
      63           2 :     sw_RemoveFtns( pColumn, true, true );
      64           4 :     while ( pColumn->GetNext() )
      65             :     {
      66             :         OSL_ENSURE( pColumn->GetNext()->IsColumnFrm(),
      67             :                 "neighbor of ColumnFrame is no ColumnFrame." );
      68           0 :         pColumn = (SwColumnFrm*)pColumn->GetNext();
      69             :     }
      70           4 :     for ( sal_uInt16 i = 0; i < nCnt; ++i )
      71             :     {
      72           2 :         SwColumnFrm *pTmp = (SwColumnFrm*)pColumn->GetPrev();
      73           2 :         pColumn->Cut();
      74           2 :         delete pColumn; //format is going to be destroyed in the DTor if needed.
      75           2 :         pColumn = pTmp;
      76             :     }
      77           2 : }
      78             : 
      79         908 : static SwLayoutFrm * lcl_FindColumns( SwLayoutFrm *pLay, sal_uInt16 nCount )
      80             : {
      81         908 :     SwFrm *pCol = pLay->Lower();
      82         908 :     if ( pLay->IsPageFrm() )
      83          28 :         pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower();
      84             : 
      85         908 :     if ( pCol && pCol->IsColumnFrm() )
      86             :     {
      87         372 :         SwFrm *pTmp = pCol;
      88             :         sal_uInt16 i;
      89         372 :         for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i )
      90             :             /* do nothing */;
      91         372 :         return i == nCount ? (SwLayoutFrm*)pCol : 0;
      92             :     }
      93         536 :     return 0;
      94             : }
      95             : 
      96         536 : static bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount )
      97             : {
      98         536 :     SwDoc *pDoc = pCont->GetFmt()->GetDoc();
      99         536 :     const bool bMod = pDoc->getIDocumentState().IsModified();
     100             : 
     101             :     //Formats should be shared whenever possible. If a neighbour already has
     102             :     //the same column settings we can add them to the same format.
     103             :     //The neighbour can be searched using the format, however the owner of the
     104             :     //attribute depends on the frame type.
     105         536 :     SwLayoutFrm *pAttrOwner = pCont;
     106         536 :     if ( pCont->IsBodyFrm() )
     107          28 :         pAttrOwner = pCont->FindPageFrm();
     108         536 :     SwLayoutFrm *pNeighbourCol = 0;
     109         536 :     SwIterator<SwLayoutFrm,SwFmt> aIter( *pAttrOwner->GetFmt() );
     110         536 :     SwLayoutFrm *pNeighbour = aIter.First();
     111             : 
     112         536 :     sal_uInt16 nAdd = 0;
     113         536 :     SwFrm *pCol = pCont->Lower();
     114         536 :     if ( pCol && pCol->IsColumnFrm() )
     115           0 :         for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd )
     116             :             /* do nothing */;
     117        1608 :     while ( pNeighbour )
     118             :     {
     119         908 :         if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) &&
     120             :              pNeighbourCol != pCont )
     121         372 :             break;
     122         536 :         pNeighbourCol = 0;
     123         536 :         pNeighbour = aIter.Next();
     124             :     }
     125             : 
     126             :     bool bRet;
     127         536 :     SwTwips nMax = pCont->IsPageBodyFrm() ?
     128         536 :                    pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX;
     129         536 :     if ( pNeighbourCol )
     130             :     {
     131         372 :         bRet = false;
     132         372 :         SwFrm *pTmp = pCont->Lower();
     133         744 :         while ( pTmp )
     134             :         {
     135           0 :             pTmp = pTmp->GetNext();
     136           0 :             pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext();
     137             :         }
     138        1476 :         for ( sal_uInt16 i = 0; i < nCount; ++i )
     139             :         {
     140        1104 :             SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt(), pCont );
     141        1104 :             pTmpCol->SetMaxFtnHeight( nMax );
     142        1104 :             pTmpCol->InsertBefore( pCont, NULL );
     143        1104 :             pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext();
     144             :         }
     145             :     }
     146             :     else
     147             :     {
     148         164 :         bRet = true;
     149         538 :         for ( sal_uInt16 i = 0; i < nCount; ++i )
     150             :         {
     151         374 :             SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyOUStr, pDoc->GetDfltFrmFmt());
     152         374 :             SwColumnFrm *pTmp = new SwColumnFrm( pFmt, pCont );
     153         374 :             pTmp->SetMaxFtnHeight( nMax );
     154         374 :             pTmp->Paste( pCont );
     155             :         }
     156             :     }
     157             : 
     158         536 :     if ( !bMod )
     159         326 :         pDoc->getIDocumentState().ResetModified();
     160         536 :     return bRet;
     161             : }
     162             : 
     163             : /** add or remove columns from a layoutframe.
     164             :  *
     165             :  * Normally, a layoutframe with a column attribute of 1 or 0 columns contains
     166             :  * no columnframe. However, a sectionframe with "footnotes at the end" needs
     167             :  * a columnframe.
     168             :  *
     169             :  * @param rOld
     170             :  * @param rNew
     171             :  * @param bChgFtn if true, the columnframe will be inserted or removed, if necessary.
     172             :  */
     173         578 : void SwLayoutFrm::ChgColumns( const SwFmtCol &rOld, const SwFmtCol &rNew,
     174             :     const bool bChgFtn )
     175             : {
     176         578 :     if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn )
     177          24 :         return;
     178             :     // #i97379#
     179             :     // If current lower is a no text frame, then columns are not allowed
     180         554 :     if ( Lower() && Lower()->IsNoTxtFrm() &&
     181           0 :          rNew.GetNumCols() > 1 )
     182             :     {
     183           0 :         return;
     184             :     }
     185             : 
     186         554 :     sal_uInt16 nNewNum, nOldNum = 1;
     187         554 :     if( Lower() && Lower()->IsColumnFrm() )
     188             :     {
     189          18 :         SwFrm* pCol = Lower();
     190          36 :         while( 0 != (pCol=pCol->GetNext()) )
     191           0 :             ++nOldNum;
     192             :     }
     193         554 :     nNewNum = rNew.GetNumCols();
     194         554 :     if( !nNewNum )
     195          28 :         ++nNewNum;
     196             :     bool bAtEnd;
     197         554 :     if( IsSctFrm() )
     198         526 :         bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd();
     199             :     else
     200          28 :         bAtEnd = false;
     201             : 
     202             :     //Setting the column width is only needed for new formats.
     203         554 :     bool bAdjustAttributes = nOldNum != rOld.GetNumCols();
     204             : 
     205             :     //The content is saved and restored if the column count is different.
     206         554 :     SwFrm *pSave = 0;
     207         554 :     if( nOldNum != nNewNum || bChgFtn )
     208             :     {
     209         554 :         SwDoc *pDoc = GetFmt()->GetDoc();
     210             :         OSL_ENSURE( pDoc, "FrmFmt doesn't return a document." );
     211             :         // SaveCntnt would also suck up the content of the footnote container
     212             :         // and store it within the normal text flow.
     213         554 :         if( IsPageBodyFrm() )
     214          28 :             pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->RemoveFtns( (SwPageFrm*)GetUpper(), true, false );
     215         554 :         pSave = ::SaveCntnt( this );
     216             : 
     217             :         //If columns exist, they get deleted if a column count of 0 or 1 is requested.
     218         554 :         if ( nNewNum == 1 && !bAtEnd )
     219             :         {
     220           2 :             ::lcl_RemoveColumns( this, nOldNum );
     221           2 :             if ( IsBodyFrm() )
     222           0 :                 SetFrmFmt( pDoc->GetDfltFrmFmt() );
     223             :             else
     224           2 :                 GetFmt()->SetFmtAttr( SwFmtFillOrder() );
     225           2 :             if ( pSave )
     226           2 :                 ::RestoreCntnt( pSave, this, 0, true );
     227           2 :             return;
     228             :         }
     229         552 :         if ( nOldNum == 1 )
     230             :         {
     231         552 :             if ( IsBodyFrm() )
     232          28 :                 SetFrmFmt( pDoc->GetColumnContFmt() );
     233             :             else
     234         524 :                 GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) );
     235         552 :             if( !Lower() || !Lower()->IsColumnFrm() )
     236         536 :                 --nOldNum;
     237             :         }
     238         552 :         if ( nOldNum > nNewNum )
     239             :         {
     240           0 :             ::lcl_RemoveColumns( this, nOldNum - nNewNum );
     241           0 :             bAdjustAttributes = true;
     242             :         }
     243         552 :         else if( nOldNum < nNewNum )
     244             :         {
     245         536 :             sal_uInt16 nAdd = nNewNum - nOldNum;
     246         536 :             bAdjustAttributes = lcl_AddColumns( this, nAdd );
     247             :         }
     248             :     }
     249             : 
     250         552 :     if ( !bAdjustAttributes )
     251             :     {
     252        1116 :         if ( rOld.GetLineWidth()    != rNew.GetLineWidth() ||
     253         712 :              rOld.GetWishWidth()    != rNew.GetWishWidth() ||
     254         340 :              rOld.IsOrtho()         != rNew.IsOrtho() )
     255         146 :             bAdjustAttributes = true;
     256             :         else
     257             :         {
     258         226 :             sal_uInt16 nCount = std::min( rNew.GetColumns().size(), rOld.GetColumns().size() );
     259         226 :             for ( sal_uInt16 i = 0; i < nCount; ++i )
     260           0 :                 if ( !(rOld.GetColumns()[i] == rNew.GetColumns()[i]) )
     261             :                 {
     262           0 :                     bAdjustAttributes = true;
     263           0 :                     break;
     264             :                 }
     265             :         }
     266             :     }
     267             : 
     268             :     //The columns can now be easily adjusted.
     269         552 :     AdjustColumns( &rNew, bAdjustAttributes );
     270             : 
     271             :     //Don't restore the content before. An earlier restore would trigger useless
     272             :     //actions during setup.
     273         552 :     if ( pSave )
     274             :     {
     275             :         OSL_ENSURE( Lower() && Lower()->IsLayoutFrm() &&
     276             :                 ((SwLayoutFrm*)Lower())->Lower() &&
     277             :                 ((SwLayoutFrm*)Lower())->Lower()->IsLayoutFrm(),
     278             :                 "no column body." );   // ColumnFrms contain BodyFrms
     279          24 :         ::RestoreCntnt( pSave, (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower(), 0, true );
     280             :     }
     281             : }
     282             : 
     283        2010 : void SwLayoutFrm::AdjustColumns( const SwFmtCol *pAttr, bool bAdjustAttributes )
     284             : {
     285        2010 :     if( !Lower()->GetNext() )
     286             :     {
     287          26 :         Lower()->ChgSize( Prt().SSize() );
     288         196 :         return;
     289             :     }
     290             : 
     291        1984 :     const bool bVert = IsVertical();
     292             : 
     293        1984 :     SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
     294             : 
     295             :     //If we have a pointer or we have to configure an attribute, we set the
     296             :     //column widths in any case. Otherwise we check if a configuration is needed.
     297        1984 :     if ( !pAttr )
     298             :     {
     299         166 :         pAttr = &GetFmt()->GetCol();
     300         166 :         if ( !bAdjustAttributes )
     301             :         {
     302         166 :             long nAvail = (Prt().*fnRect->fnGetWidth)();
     303         562 :             for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower();
     304             :                   pCol;
     305         396 :                   pCol = (SwLayoutFrm*)pCol->GetNext() )
     306         396 :                 nAvail -= (pCol->Frm().*fnRect->fnGetWidth)();
     307         166 :             if ( !nAvail )
     308         144 :                 return;
     309             :         }
     310             :     }
     311             : 
     312             :     //The columns can now be easily adjusted.
     313             :     //The widths get counted so we can give the reminder to the last one.
     314        1840 :     SwTwips nAvail = (Prt().*fnRect->fnGetWidth)();
     315        1840 :     const bool bLine = pAttr->GetLineAdj() != COLADJ_NONE;
     316        1840 :     const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0;
     317             : 
     318        1840 :     const bool bR2L = IsRightToLeft();
     319        1840 :     SwFrm *pCol = bR2L ? GetLastLower() : Lower();
     320             : 
     321             :     // #i27399#
     322             :     // bOrtho means we have to adjust the column frames manually. Otherwise
     323             :     // we may use the values returned by CalcColWidth:
     324        1840 :     const bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0;
     325        1840 :     long nGutter = 0;
     326             : 
     327        7206 :     for ( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; ++i ) //i118878, value returned by GetNumCols() can't be trusted
     328             :     {
     329        5366 :         if( !bOrtho )
     330             :         {
     331        2148 :             const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ?
     332             :                                    nAvail :
     333        2148 :                                    pAttr->CalcColWidth( i, sal_uInt16( (Prt().*fnRect->fnGetWidth)() ) );
     334             : 
     335             :             const Size aColSz = bVert ?
     336           0 :                                 Size( Prt().Width(), nWidth ) :
     337        2148 :                                 Size( nWidth, Prt().Height() );
     338             : 
     339        2148 :             pCol->ChgSize( aColSz );
     340             : 
     341             :             // With this, the ColumnBodyFrms from page columns gets adjusted and
     342             :             // their bFixHeight flag is set so they won't shrink/grow.
     343             :             // Don't use the flag with frame columns because BodyFrms in frame
     344             :             // columns can grow/shrink.
     345        2148 :             if( IsBodyFrm() )
     346          28 :                 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
     347             : 
     348        2148 :             nAvail -= nWidth;
     349             :         }
     350             : 
     351        5366 :         if ( bOrtho || bAdjustAttributes )
     352             :         {
     353        3804 :             const SwColumn *pC = &pAttr->GetColumns()[i];
     354        3804 :             const SwAttrSet* pSet = pCol->GetAttrSet();
     355        3804 :             SvxLRSpaceItem aLR( pSet->GetLRSpace() );
     356             : 
     357             :             //In order to have enough space for the separation lines, we have to
     358             :             //take them into account here. Every time two columns meet we
     359             :             //calculate a clearance of 20 + half the pen width on the left or
     360             :             //right side, respectively.
     361        3804 :             const sal_uInt16 nLeft = pC->GetLeft();
     362        3804 :             const sal_uInt16 nRight = pC->GetRight();
     363             : 
     364        3804 :             aLR.SetLeft ( nLeft );
     365        3804 :             aLR.SetRight( nRight );
     366             : 
     367        3804 :             if ( bLine )
     368             :             {
     369          76 :                 if ( i == 0 )
     370             :                 {
     371          38 :                     aLR.SetRight( std::max( nRight, nMin ) );
     372             :                 }
     373          38 :                 else if ( i == pAttr->GetNumCols() - 1 )
     374             :                 {
     375          38 :                     aLR.SetLeft ( std::max( nLeft, nMin ) );
     376             :                 }
     377             :                 else
     378             :                 {
     379           0 :                     aLR.SetLeft ( std::max( nLeft,  nMin ) );
     380           0 :                     aLR.SetRight( std::max( nRight, nMin ) );
     381             :                 }
     382             :             }
     383             : 
     384        3804 :             if ( bAdjustAttributes )
     385             :             {
     386         804 :                 SvxULSpaceItem aUL( pSet->GetULSpace() );
     387         804 :                 aUL.SetUpper( pC->GetUpper());
     388         804 :                 aUL.SetLower( pC->GetLower());
     389             : 
     390         804 :                 ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aLR );
     391         804 :                 ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aUL );
     392             :             }
     393             : 
     394        3804 :             nGutter += aLR.GetLeft() + aLR.GetRight();
     395             :         }
     396             : 
     397        5366 :         pCol = bR2L ? pCol->GetPrev() : pCol->GetNext();
     398             :     }
     399             : 
     400        1840 :     if( bOrtho )
     401             :     {
     402        1102 :         long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols();
     403        1102 :         pCol = Lower();
     404        4320 :         for( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; pCol = pCol->GetNext(), ++i ) //i118878, value returned by GetNumCols() can't be trusted
     405             :         {
     406             :             SwTwips nWidth;
     407        3218 :             if ( i == pAttr->GetNumCols() - 1 )
     408        1102 :                 nWidth = nAvail;
     409             :             else
     410             :             {
     411        2116 :                 SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() );
     412        2116 :                 nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight();
     413             :             }
     414        3218 :             if( nWidth < 0 )
     415           0 :                 nWidth = 0;
     416             : 
     417             :             const Size aColSz = bVert ?
     418           0 :                                 Size( Prt().Width(), nWidth ) :
     419        3218 :                                 Size( nWidth, Prt().Height() );
     420             : 
     421        3218 :             pCol->ChgSize( aColSz );
     422             : 
     423        3218 :             if( IsBodyFrm() )
     424          28 :                 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
     425             : 
     426        3218 :             nAvail -= nWidth;
     427             :         }
     428             :     }
     429         270 : }
     430             : 
     431             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10