LCOV - code coverage report
Current view: top level - sw/source/core/layout - colfrm.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 167 201 83.1 %
Date: 2014-04-11 Functions: 7 8 87.5 %
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             : 
      32             : // ftnfrm.cxx:
      33             : void sw_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes );
      34             : 
      35         608 : SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt, SwFrm* pSib ):
      36         608 :     SwFtnBossFrm( pFmt, pSib )
      37             : {
      38         608 :     mnType = FRMC_COLUMN;
      39         608 :     SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt(), pSib );
      40         608 :     pColBody->InsertBehind( this, 0 ); // ColumnFrms now with BodyFrm
      41         608 :     SetMaxFtnHeight( LONG_MAX );
      42         608 : }
      43             : 
      44        1824 : SwColumnFrm::~SwColumnFrm()
      45             : {
      46         608 :     SwFrmFmt *pFmt = GetFmt();
      47             :     SwDoc *pDoc;
      48         608 :     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         110 :         pDoc->GetDfltFrmFmt()->Add( this );
      53         110 :         pDoc->DelFrmFmt( pFmt );
      54             :     }
      55        1216 : }
      56             : 
      57           0 : 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           0 :     SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower();
      63           0 :     sw_RemoveFtns( pColumn, sal_True, sal_True );
      64           0 :     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           0 :     for ( sal_uInt16 i = 0; i < nCnt; ++i )
      71             :     {
      72           0 :         SwColumnFrm *pTmp = (SwColumnFrm*)pColumn->GetPrev();
      73           0 :         pColumn->Cut();
      74           0 :         delete pColumn; //format is going to be destroyed in the DTor if needed.
      75           0 :         pColumn = pTmp;
      76             :     }
      77           0 : }
      78             : 
      79         441 : static SwLayoutFrm * lcl_FindColumns( SwLayoutFrm *pLay, sal_uInt16 nCount )
      80             : {
      81         441 :     SwFrm *pCol = pLay->Lower();
      82         441 :     if ( pLay->IsPageFrm() )
      83          12 :         pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower();
      84             : 
      85         441 :     if ( pCol && pCol->IsColumnFrm() )
      86             :     {
      87         200 :         SwFrm *pTmp = pCol;
      88             :         sal_uInt16 i;
      89         200 :         for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i )
      90             :             /* do nothing */;
      91         200 :         return i == nCount ? (SwLayoutFrm*)pCol : 0;
      92             :     }
      93         241 :     return 0;
      94             : }
      95             : 
      96         248 : static sal_Bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount )
      97             : {
      98         248 :     SwDoc *pDoc = pCont->GetFmt()->GetDoc();
      99         248 :     const sal_Bool bMod = pDoc->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         248 :     SwLayoutFrm *pAttrOwner = pCont;
     106         248 :     if ( pCont->IsBodyFrm() )
     107          12 :         pAttrOwner = pCont->FindPageFrm();
     108         248 :     SwLayoutFrm *pNeighbourCol = 0;
     109         248 :     SwIterator<SwLayoutFrm,SwFmt> aIter( *pAttrOwner->GetFmt() );
     110         248 :     SwLayoutFrm *pNeighbour = aIter.First();
     111             : 
     112         248 :     sal_uInt16 nAdd = 0;
     113         248 :     SwFrm *pCol = pCont->Lower();
     114         248 :     if ( pCol && pCol->IsColumnFrm() )
     115           0 :         for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd )
     116             :             /* do nothing */;
     117         737 :     while ( pNeighbour )
     118             :     {
     119         441 :         if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) &&
     120             :              pNeighbourCol != pCont )
     121         200 :             break;
     122         241 :         pNeighbourCol = 0;
     123         241 :         pNeighbour = aIter.Next();
     124             :     }
     125             : 
     126             :     sal_Bool bRet;
     127         248 :     SwTwips nMax = pCont->IsPageBodyFrm() ?
     128         248 :                    pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX;
     129         248 :     if ( pNeighbourCol )
     130             :     {
     131         200 :         bRet = sal_False;
     132         200 :         SwFrm *pTmp = pCont->Lower();
     133         400 :         while ( pTmp )
     134             :         {
     135           0 :             pTmp = pTmp->GetNext();
     136           0 :             pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext();
     137             :         }
     138         698 :         for ( sal_uInt16 i = 0; i < nCount; ++i )
     139             :         {
     140         498 :             SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt(), pCont );
     141         498 :             pTmpCol->SetMaxFtnHeight( nMax );
     142         498 :             pTmpCol->InsertBefore( pCont, NULL );
     143         498 :             pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext();
     144             :         }
     145             :     }
     146             :     else
     147             :     {
     148          48 :         bRet = sal_True;
     149         158 :         for ( sal_uInt16 i = 0; i < nCount; ++i )
     150             :         {
     151         110 :             SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyOUStr, pDoc->GetDfltFrmFmt());
     152         110 :             SwColumnFrm *pTmp = new SwColumnFrm( pFmt, pCont );
     153         110 :             pTmp->SetMaxFtnHeight( nMax );
     154         110 :             pTmp->Paste( pCont );
     155             :         }
     156             :     }
     157             : 
     158         248 :     if ( !bMod )
     159         172 :         pDoc->ResetModified();
     160         248 :     return bRet;
     161             : }
     162             : 
     163             : /** add or remove columns from a layoutframe.
     164             :  *
     165             :  * Normally, a layoutframe with a column attribut 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         279 : void SwLayoutFrm::ChgColumns( const SwFmtCol &rOld, const SwFmtCol &rNew,
     174             :     const sal_Bool bChgFtn )
     175             : {
     176         279 :     if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn )
     177          23 :         return;
     178             :     // #i97379#
     179             :     // If current lower is a no text frame, then columns are not allowed
     180         256 :     if ( Lower() && Lower()->IsNoTxtFrm() &&
     181           0 :          rNew.GetNumCols() > 1 )
     182             :     {
     183           0 :         return;
     184             :     }
     185             : 
     186         256 :     sal_uInt16 nNewNum, nOldNum = 1;
     187         256 :     if( Lower() && Lower()->IsColumnFrm() )
     188             :     {
     189           8 :         SwFrm* pCol = Lower();
     190          16 :         while( 0 != (pCol=pCol->GetNext()) )
     191           0 :             ++nOldNum;
     192             :     }
     193         256 :     nNewNum = rNew.GetNumCols();
     194         256 :     if( !nNewNum )
     195          12 :         ++nNewNum;
     196             :     sal_Bool bAtEnd;
     197         256 :     if( IsSctFrm() )
     198         244 :         bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd();
     199             :     else
     200          12 :         bAtEnd = sal_False;
     201             : 
     202             :     //Setting the column width is only needed for new formats.
     203         256 :     sal_Bool bAdjustAttributes = nOldNum != rOld.GetNumCols();
     204             : 
     205             :     //The content is saved and restored if the column count is different.
     206         256 :     SwFrm *pSave = 0;
     207         256 :     if( nOldNum != nNewNum || bChgFtn )
     208             :     {
     209         256 :         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         256 :         if( IsPageBodyFrm() )
     214          12 :             pDoc->GetCurrentLayout()->RemoveFtns( (SwPageFrm*)GetUpper(), sal_True, sal_False );
     215         256 :         pSave = ::SaveCntnt( this );
     216             : 
     217             :         //If columns exist, they get deleted if a column count of 0 or 1 is requested.
     218         256 :         if ( nNewNum == 1 && !bAtEnd )
     219             :         {
     220           0 :             ::lcl_RemoveColumns( this, nOldNum );
     221           0 :             if ( IsBodyFrm() )
     222           0 :                 SetFrmFmt( pDoc->GetDfltFrmFmt() );
     223             :             else
     224           0 :                 GetFmt()->SetFmtAttr( SwFmtFillOrder() );
     225           0 :             if ( pSave )
     226           0 :                 ::RestoreCntnt( pSave, this, 0, true );
     227           0 :             return;
     228             :         }
     229         256 :         if ( nOldNum == 1 )
     230             :         {
     231         256 :             if ( IsBodyFrm() )
     232          12 :                 SetFrmFmt( pDoc->GetColumnContFmt() );
     233             :             else
     234         244 :                 GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) );
     235         256 :             if( !Lower() || !Lower()->IsColumnFrm() )
     236         248 :                 --nOldNum;
     237             :         }
     238         256 :         if ( nOldNum > nNewNum )
     239             :         {
     240           0 :             ::lcl_RemoveColumns( this, nOldNum - nNewNum );
     241           0 :             bAdjustAttributes = sal_True;
     242             :         }
     243         256 :         else if( nOldNum < nNewNum )
     244             :         {
     245         248 :             sal_uInt16 nAdd = nNewNum - nOldNum;
     246         248 :             bAdjustAttributes = lcl_AddColumns( this, nAdd );
     247             :         }
     248             :     }
     249             : 
     250         256 :     if ( !bAdjustAttributes )
     251             :     {
     252         600 :         if ( rOld.GetLineWidth()    != rNew.GetLineWidth() ||
     253         387 :              rOld.GetWishWidth()    != rNew.GetWishWidth() ||
     254         187 :              rOld.IsOrtho()         != rNew.IsOrtho() )
     255          47 :             bAdjustAttributes = sal_True;
     256             :         else
     257             :         {
     258         153 :             sal_uInt16 nCount = std::min( rNew.GetColumns().size(), rOld.GetColumns().size() );
     259         153 :             for ( sal_uInt16 i = 0; i < nCount; ++i )
     260           0 :                 if ( !(rOld.GetColumns()[i] == rNew.GetColumns()[i]) )
     261             :                 {
     262           0 :                     bAdjustAttributes = sal_True;
     263           0 :                     break;
     264             :                 }
     265             :         }
     266             :     }
     267             : 
     268             :     //The columns can now be easily adjusted.
     269         256 :     AdjustColumns( &rNew, bAdjustAttributes );
     270             : 
     271             :     //Don't restore the content before. An earlier restore would trigger useless
     272             :     //actions during setup.
     273         256 :     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          11 :         ::RestoreCntnt( pSave, (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower(), 0, true );
     280             :     }
     281             : }
     282             : 
     283         921 : void SwLayoutFrm::AdjustColumns( const SwFmtCol *pAttr, sal_Bool bAdjustAttributes )
     284             : {
     285         921 :     if( !Lower()->GetNext() )
     286             :     {
     287          12 :         Lower()->ChgSize( Prt().SSize() );
     288          73 :         return;
     289             :     }
     290             : 
     291         909 :     const sal_Bool bVert = IsVertical();
     292             :     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
     293         909 :     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         909 :     if ( !pAttr )
     298             :     {
     299          55 :         pAttr = &GetFmt()->GetCol();
     300          55 :         if ( !bAdjustAttributes )
     301             :         {
     302          55 :             long nAvail = (Prt().*fnRect->fnGetWidth)();
     303         187 :             for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower();
     304             :                   pCol;
     305         132 :                   pCol = (SwLayoutFrm*)pCol->GetNext() )
     306         132 :                 nAvail -= (pCol->Frm().*fnRect->fnGetWidth)();
     307          55 :             if ( !nAvail )
     308          49 :                 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         860 :     SwTwips nAvail = (Prt().*fnRect->fnGetWidth)();
     315         860 :     const sal_Bool bLine = pAttr->GetLineAdj() != COLADJ_NONE;
     316         860 :     const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0;
     317             : 
     318         860 :     const sal_Bool bR2L = IsRightToLeft();
     319         860 :     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         860 :     const sal_Bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0;
     325         860 :     long nGutter = 0;
     326             : 
     327        3054 :     for ( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; ++i ) //i118878, value returned by GetNumCols() can't be trusted
     328             :     {
     329        2194 :         if( !bOrtho )
     330             :         {
     331         430 :             const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ?
     332             :                                    nAvail :
     333         430 :                                    pAttr->CalcColWidth( i, sal_uInt16( (Prt().*fnRect->fnGetWidth)() ) );
     334             : 
     335             :             const Size aColSz = bVert ?
     336           0 :                                 Size( Prt().Width(), nWidth ) :
     337         430 :                                 Size( nWidth, Prt().Height() );
     338             : 
     339         430 :             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         430 :             if( IsBodyFrm() )
     346           2 :                 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
     347             : 
     348         430 :             nAvail -= nWidth;
     349             :         }
     350             : 
     351        2194 :         if ( bOrtho || bAdjustAttributes )
     352             :         {
     353        1888 :             const SwColumn *pC = &pAttr->GetColumns()[i];
     354        1888 :             const SwAttrSet* pSet = pCol->GetAttrSet();
     355        1888 :             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        1888 :             const sal_uInt16 nLeft = pC->GetLeft();
     362        1888 :             const sal_uInt16 nRight = pC->GetRight();
     363             : 
     364        1888 :             aLR.SetLeft ( nLeft );
     365        1888 :             aLR.SetRight( nRight );
     366             : 
     367        1888 :             if ( bLine )
     368             :             {
     369          38 :                 if ( i == 0 )
     370             :                 {
     371          19 :                     aLR.SetRight( std::max( nRight, nMin ) );
     372             :                 }
     373          19 :                 else if ( i == pAttr->GetNumCols() - 1 )
     374             :                 {
     375          19 :                     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        1888 :             if ( bAdjustAttributes )
     385             :             {
     386         202 :                 SvxULSpaceItem aUL( pSet->GetULSpace() );
     387         202 :                 aUL.SetUpper( pC->GetUpper());
     388         202 :                 aUL.SetLower( pC->GetLower());
     389             : 
     390         202 :                 ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aLR );
     391         202 :                 ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aUL );
     392             :             }
     393             : 
     394        1888 :             nGutter += aLR.GetLeft() + aLR.GetRight();
     395             :         }
     396             : 
     397        2194 :         pCol = bR2L ? pCol->GetPrev() : pCol->GetNext();
     398             :     }
     399             : 
     400         860 :     if( bOrtho )
     401             :     {
     402         648 :         long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols();
     403         648 :         pCol = Lower();
     404        2412 :         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        1764 :             if ( i == pAttr->GetNumCols() - 1 )
     408         648 :                 nWidth = nAvail;
     409             :             else
     410             :             {
     411        1116 :                 SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() );
     412        1116 :                 nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight();
     413             :             }
     414        1764 :             if( nWidth < 0 )
     415           0 :                 nWidth = 0;
     416             : 
     417             :             const Size aColSz = bVert ?
     418           0 :                                 Size( Prt().Width(), nWidth ) :
     419        1764 :                                 Size( nWidth, Prt().Height() );
     420             : 
     421        1764 :             pCol->ChgSize( aColSz );
     422             : 
     423        1764 :             if( IsBodyFrm() )
     424          22 :                 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
     425             : 
     426        1764 :             nAvail -= nWidth;
     427             :         }
     428             :     }
     429             : }
     430             : 
     431             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10