LCOV - code coverage report
Current view: top level - sw/source/core/layout - colfrm.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 166 205 81.0 %
Date: 2015-06-13 12:38:46 Functions: 10 11 90.9 %
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 <calbck.hxx>
      31             : #include "ftnfrm.hxx"
      32             : #include <IDocumentState.hxx>
      33             : #include <IDocumentLayoutAccess.hxx>
      34             : 
      35         754 : SwColumnFrm::SwColumnFrm( SwFrameFormat *pFormat, SwFrm* pSib ):
      36         754 :     SwFootnoteBossFrm( pFormat, pSib )
      37             : {
      38         754 :     mnFrmType = FRM_COLUMN;
      39         754 :     SwBodyFrm* pColBody = new SwBodyFrm( pFormat->GetDoc()->GetDfltFrameFormat(), pSib );
      40         754 :     pColBody->InsertBehind( this, 0 ); // ColumnFrms now with BodyFrm
      41         754 :     SetMaxFootnoteHeight( LONG_MAX );
      42         754 : }
      43             : 
      44         754 : void SwColumnFrm::DestroyImpl()
      45             : {
      46         754 :     SwFrameFormat *pFormat = GetFormat();
      47             :     SwDoc *pDoc;
      48         754 :     if ( !(pDoc = pFormat->GetDoc())->IsInDtor() && pFormat->HasOnlyOneListener() )
      49             :     {
      50             :         //I'm the only one, delete the format.
      51             :         //Get default format before, so the base class can cope with it.
      52         190 :         pDoc->GetDfltFrameFormat()->Add( this );
      53         190 :         pDoc->DelFrameFormat( pFormat );
      54             :     }
      55             : 
      56         754 :     SwFootnoteBossFrm::DestroyImpl();
      57         754 : }
      58             : 
      59        1508 : SwColumnFrm::~SwColumnFrm()
      60             : {
      61        1508 : }
      62             : 
      63           0 : static void lcl_RemoveColumns( SwLayoutFrm *pCont, sal_uInt16 nCnt )
      64             : {
      65             :     OSL_ENSURE( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(),
      66             :             "no columns to remove." );
      67             : 
      68           0 :     SwColumnFrm *pColumn = static_cast<SwColumnFrm*>(pCont->Lower());
      69           0 :     sw_RemoveFootnotes( pColumn, true, true );
      70           0 :     while ( pColumn->GetNext() )
      71             :     {
      72             :         OSL_ENSURE( pColumn->GetNext()->IsColumnFrm(),
      73             :                 "neighbor of ColumnFrame is no ColumnFrame." );
      74           0 :         pColumn = static_cast<SwColumnFrm*>(pColumn->GetNext());
      75             :     }
      76           0 :     for ( sal_uInt16 i = 0; i < nCnt; ++i )
      77             :     {
      78           0 :         SwColumnFrm *pTmp = static_cast<SwColumnFrm*>(pColumn->GetPrev());
      79           0 :         pColumn->Cut();
      80           0 :         SwFrm::DestroyFrm(pColumn); //format is going to be destroyed in the DTor if needed.
      81           0 :         pColumn = pTmp;
      82             :     }
      83           0 : }
      84             : 
      85         451 : static SwLayoutFrm * lcl_FindColumns( SwLayoutFrm *pLay, sal_uInt16 nCount )
      86             : {
      87         451 :     SwFrm *pCol = pLay->Lower();
      88         451 :     if ( pLay->IsPageFrm() )
      89          14 :         pCol = static_cast<SwPageFrm*>(pLay)->FindBodyCont()->Lower();
      90             : 
      91         451 :     if ( pCol && pCol->IsColumnFrm() )
      92             :     {
      93         185 :         SwFrm *pTmp = pCol;
      94             :         sal_uInt16 i;
      95         185 :         for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i )
      96             :             /* do nothing */;
      97         185 :         return i == nCount ? static_cast<SwLayoutFrm*>(pCol) : 0;
      98             :     }
      99         266 :     return 0;
     100             : }
     101             : 
     102         266 : static bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount )
     103             : {
     104         266 :     SwDoc *pDoc = pCont->GetFormat()->GetDoc();
     105         266 :     const bool bMod = pDoc->getIDocumentState().IsModified();
     106             : 
     107             :     //Formats should be shared whenever possible. If a neighbour already has
     108             :     //the same column settings we can add them to the same format.
     109             :     //The neighbour can be searched using the format, however the owner of the
     110             :     //attribute depends on the frame type.
     111         266 :     SwLayoutFrm *pAttrOwner = pCont;
     112         266 :     if ( pCont->IsBodyFrm() )
     113          14 :         pAttrOwner = pCont->FindPageFrm();
     114         266 :     SwLayoutFrm *pNeighbourCol = 0;
     115         266 :     SwIterator<SwLayoutFrm,SwFormat> aIter( *pAttrOwner->GetFormat() );
     116         266 :     SwLayoutFrm *pNeighbour = aIter.First();
     117             : 
     118         266 :     sal_uInt16 nAdd = 0;
     119         266 :     SwFrm *pCol = pCont->Lower();
     120         266 :     if ( pCol && pCol->IsColumnFrm() )
     121           0 :         for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd )
     122             :             /* do nothing */;
     123         798 :     while ( pNeighbour )
     124             :     {
     125         451 :         if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) &&
     126             :              pNeighbourCol != pCont )
     127         185 :             break;
     128         266 :         pNeighbourCol = 0;
     129         266 :         pNeighbour = aIter.Next();
     130             :     }
     131             : 
     132             :     bool bRet;
     133         266 :     SwTwips nMax = pCont->IsPageBodyFrm() ?
     134         266 :                    pCont->FindPageFrm()->GetMaxFootnoteHeight() : LONG_MAX;
     135         266 :     if ( pNeighbourCol )
     136             :     {
     137         185 :         bRet = false;
     138         185 :         SwFrm *pTmp = pCont->Lower();
     139         370 :         while ( pTmp )
     140             :         {
     141           0 :             pTmp = pTmp->GetNext();
     142           0 :             pNeighbourCol = static_cast<SwLayoutFrm*>(pNeighbourCol->GetNext());
     143             :         }
     144         749 :         for ( sal_uInt16 i = 0; i < nCount; ++i )
     145             :         {
     146         564 :             SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFormat(), pCont );
     147         564 :             pTmpCol->SetMaxFootnoteHeight( nMax );
     148         564 :             pTmpCol->InsertBefore( pCont, NULL );
     149         564 :             pNeighbourCol = static_cast<SwLayoutFrm*>(pNeighbourCol->GetNext());
     150             :         }
     151             :     }
     152             :     else
     153             :     {
     154          81 :         bRet = true;
     155         271 :         for ( sal_uInt16 i = 0; i < nCount; ++i )
     156             :         {
     157         190 :             SwFrameFormat *pFormat = pDoc->MakeFrameFormat( aEmptyOUStr, pDoc->GetDfltFrameFormat());
     158         190 :             SwColumnFrm *pTmp = new SwColumnFrm( pFormat, pCont );
     159         190 :             pTmp->SetMaxFootnoteHeight( nMax );
     160         190 :             pTmp->Paste( pCont );
     161             :         }
     162             :     }
     163             : 
     164         266 :     if ( !bMod )
     165         163 :         pDoc->getIDocumentState().ResetModified();
     166         266 :     return bRet;
     167             : }
     168             : 
     169             : /** add or remove columns from a layoutframe.
     170             :  *
     171             :  * Normally, a layoutframe with a column attribute of 1 or 0 columns contains
     172             :  * no columnframe. However, a sectionframe with "footnotes at the end" needs
     173             :  * a columnframe.
     174             :  *
     175             :  * @param rOld
     176             :  * @param rNew
     177             :  * @param bChgFootnote if true, the columnframe will be inserted or removed, if necessary.
     178             :  */
     179         272 : void SwLayoutFrm::ChgColumns( const SwFormatCol &rOld, const SwFormatCol &rNew,
     180             :     const bool bChgFootnote )
     181             : {
     182         272 :     if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFootnote )
     183           6 :         return;
     184             :     // #i97379#
     185             :     // If current lower is a no text frame, then columns are not allowed
     186         266 :     if ( Lower() && Lower()->IsNoTextFrm() &&
     187           0 :          rNew.GetNumCols() > 1 )
     188             :     {
     189           0 :         return;
     190             :     }
     191             : 
     192         266 :     sal_uInt16 nNewNum, nOldNum = 1;
     193         266 :     if( Lower() && Lower()->IsColumnFrm() )
     194             :     {
     195           0 :         SwFrm* pCol = Lower();
     196           0 :         while( 0 != (pCol=pCol->GetNext()) )
     197           0 :             ++nOldNum;
     198             :     }
     199         266 :     nNewNum = rNew.GetNumCols();
     200         266 :     if( !nNewNum )
     201           0 :         ++nNewNum;
     202             :     bool bAtEnd;
     203         266 :     if( IsSctFrm() )
     204         252 :         bAtEnd = static_cast<SwSectionFrm*>(this)->IsAnyNoteAtEnd();
     205             :     else
     206          14 :         bAtEnd = false;
     207             : 
     208             :     //Setting the column width is only needed for new formats.
     209         266 :     bool bAdjustAttributes = nOldNum != rOld.GetNumCols();
     210             : 
     211             :     //The content is saved and restored if the column count is different.
     212         266 :     SwFrm *pSave = 0;
     213         266 :     if( nOldNum != nNewNum || bChgFootnote )
     214             :     {
     215         266 :         SwDoc *pDoc = GetFormat()->GetDoc();
     216             :         OSL_ENSURE( pDoc, "FrameFormat doesn't return a document." );
     217             :         // SaveContent would also suck up the content of the footnote container
     218             :         // and store it within the normal text flow.
     219         266 :         if( IsPageBodyFrm() )
     220          14 :             pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->RemoveFootnotes( static_cast<SwPageFrm*>(GetUpper()), true, false );
     221         266 :         pSave = ::SaveContent( this );
     222             : 
     223             :         //If columns exist, they get deleted if a column count of 0 or 1 is requested.
     224         266 :         if ( nNewNum == 1 && !bAtEnd )
     225             :         {
     226           0 :             ::lcl_RemoveColumns( this, nOldNum );
     227           0 :             if ( IsBodyFrm() )
     228           0 :                 SetFrameFormat( pDoc->GetDfltFrameFormat() );
     229             :             else
     230           0 :                 GetFormat()->SetFormatAttr( SwFormatFillOrder() );
     231           0 :             if ( pSave )
     232           0 :                 ::RestoreContent( pSave, this, 0, true );
     233           0 :             return;
     234             :         }
     235         266 :         if ( nOldNum == 1 )
     236             :         {
     237         266 :             if ( IsBodyFrm() )
     238          14 :                 SetFrameFormat( pDoc->GetColumnContFormat() );
     239             :             else
     240         252 :                 GetFormat()->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT ) );
     241         266 :             if( !Lower() || !Lower()->IsColumnFrm() )
     242         266 :                 --nOldNum;
     243             :         }
     244         266 :         if ( nOldNum > nNewNum )
     245             :         {
     246           0 :             ::lcl_RemoveColumns( this, nOldNum - nNewNum );
     247           0 :             bAdjustAttributes = true;
     248             :         }
     249         266 :         else if( nOldNum < nNewNum )
     250             :         {
     251         266 :             sal_uInt16 nAdd = nNewNum - nOldNum;
     252         266 :             bAdjustAttributes = lcl_AddColumns( this, nAdd );
     253             :         }
     254             :     }
     255             : 
     256         266 :     if ( !bAdjustAttributes )
     257             :     {
     258         555 :         if ( rOld.GetLineWidth()    != rNew.GetLineWidth() ||
     259         354 :              rOld.GetWishWidth()    != rNew.GetWishWidth() ||
     260         169 :              rOld.IsOrtho()         != rNew.IsOrtho() )
     261          73 :             bAdjustAttributes = true;
     262             :         else
     263             :         {
     264         112 :             const size_t nCount = std::min( rNew.GetColumns().size(), rOld.GetColumns().size() );
     265         112 :             for ( size_t i = 0; i < nCount; ++i )
     266           0 :                 if ( !(rOld.GetColumns()[i] == rNew.GetColumns()[i]) )
     267             :                 {
     268           0 :                     bAdjustAttributes = true;
     269           0 :                     break;
     270             :                 }
     271             :         }
     272             :     }
     273             : 
     274             :     //The columns can now be easily adjusted.
     275         266 :     AdjustColumns( &rNew, bAdjustAttributes );
     276             : 
     277             :     //Don't restore the content before. An earlier restore would trigger useless
     278             :     //actions during setup.
     279         266 :     if ( pSave )
     280             :     {
     281             :         OSL_ENSURE( Lower() && Lower()->IsLayoutFrm() &&
     282             :                 static_cast<SwLayoutFrm*>(Lower())->Lower() &&
     283             :                 static_cast<SwLayoutFrm*>(Lower())->Lower()->IsLayoutFrm(),
     284             :                 "no column body." );   // ColumnFrms contain BodyFrms
     285           0 :         ::RestoreContent( pSave, static_cast<SwLayoutFrm*>(static_cast<SwLayoutFrm*>(Lower())->Lower()), 0, true );
     286             :     }
     287             : }
     288             : 
     289        1036 : void SwLayoutFrm::AdjustColumns( const SwFormatCol *pAttr, bool bAdjustAttributes )
     290             : {
     291        1036 :     if( !Lower()->GetNext() )
     292             :     {
     293           0 :         Lower()->ChgSize( Prt().SSize() );
     294          79 :         return;
     295             :     }
     296             : 
     297        1036 :     const bool bVert = IsVertical();
     298             : 
     299        1036 :     SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
     300             : 
     301             :     //If we have a pointer or we have to configure an attribute, we set the
     302             :     //column widths in any case. Otherwise we check if a configuration is needed.
     303        1036 :     if ( !pAttr )
     304             :     {
     305          90 :         pAttr = &GetFormat()->GetCol();
     306          90 :         if ( !bAdjustAttributes )
     307             :         {
     308          90 :             long nAvail = (Prt().*fnRect->fnGetWidth)();
     309         305 :             for ( SwLayoutFrm *pCol = static_cast<SwLayoutFrm*>(Lower());
     310             :                   pCol;
     311         215 :                   pCol = static_cast<SwLayoutFrm*>(pCol->GetNext()) )
     312         215 :                 nAvail -= (pCol->Frm().*fnRect->fnGetWidth)();
     313          90 :             if ( !nAvail )
     314          79 :                 return;
     315             :         }
     316             :     }
     317             : 
     318             :     //The columns can now be easily adjusted.
     319             :     //The widths get counted so we can give the reminder to the last one.
     320         957 :     SwTwips nAvail = (Prt().*fnRect->fnGetWidth)();
     321         957 :     const bool bLine = pAttr->GetLineAdj() != COLADJ_NONE;
     322         957 :     const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0;
     323             : 
     324         957 :     const bool bR2L = IsRightToLeft();
     325         957 :     SwFrm *pCol = bR2L ? GetLastLower() : Lower();
     326             : 
     327             :     // #i27399#
     328             :     // bOrtho means we have to adjust the column frames manually. Otherwise
     329             :     // we may use the values returned by CalcColWidth:
     330         957 :     const bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0;
     331         957 :     long nGutter = 0;
     332             : 
     333        3793 :     for ( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; ++i ) //i118878, value returned by GetNumCols() can't be trusted
     334             :     {
     335        2836 :         if( !bOrtho )
     336             :         {
     337        1074 :             const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ?
     338             :                                    nAvail :
     339        1074 :                                    pAttr->CalcColWidth( i, sal_uInt16( (Prt().*fnRect->fnGetWidth)() ) );
     340             : 
     341             :             const Size aColSz = bVert ?
     342           0 :                                 Size( Prt().Width(), nWidth ) :
     343        1074 :                                 Size( nWidth, Prt().Height() );
     344             : 
     345        1074 :             pCol->ChgSize( aColSz );
     346             : 
     347             :             // With this, the ColumnBodyFrms from page columns gets adjusted and
     348             :             // their bFixHeight flag is set so they won't shrink/grow.
     349             :             // Don't use the flag with frame columns because BodyFrms in frame
     350             :             // columns can grow/shrink.
     351        1074 :             if( IsBodyFrm() )
     352          14 :                 static_cast<SwLayoutFrm*>(pCol)->Lower()->ChgSize( aColSz );
     353             : 
     354        1074 :             nAvail -= nWidth;
     355             :         }
     356             : 
     357        2836 :         if ( bOrtho || bAdjustAttributes )
     358             :         {
     359        2055 :             const SwColumn *pC = &pAttr->GetColumns()[i];
     360        2055 :             const SwAttrSet* pSet = pCol->GetAttrSet();
     361        2055 :             SvxLRSpaceItem aLR( pSet->GetLRSpace() );
     362             : 
     363             :             //In order to have enough space for the separation lines, we have to
     364             :             //take them into account here. Every time two columns meet we
     365             :             //calculate a clearance of 20 + half the pen width on the left or
     366             :             //right side, respectively.
     367        2055 :             const sal_uInt16 nLeft = pC->GetLeft();
     368        2055 :             const sal_uInt16 nRight = pC->GetRight();
     369             : 
     370        2055 :             aLR.SetLeft ( nLeft );
     371        2055 :             aLR.SetRight( nRight );
     372             : 
     373        2055 :             if ( bLine )
     374             :             {
     375          38 :                 if ( i == 0 )
     376             :                 {
     377          19 :                     aLR.SetRight( std::max( nRight, nMin ) );
     378             :                 }
     379          19 :                 else if ( i == pAttr->GetNumCols() - 1 )
     380             :                 {
     381          19 :                     aLR.SetLeft ( std::max( nLeft, nMin ) );
     382             :                 }
     383             :                 else
     384             :                 {
     385           0 :                     aLR.SetLeft ( std::max( nLeft,  nMin ) );
     386           0 :                     aLR.SetRight( std::max( nRight, nMin ) );
     387             :                 }
     388             :             }
     389             : 
     390        2055 :             if ( bAdjustAttributes )
     391             :             {
     392         409 :                 SvxULSpaceItem aUL( pSet->GetULSpace() );
     393         409 :                 aUL.SetUpper( pC->GetUpper());
     394         409 :                 aUL.SetLower( pC->GetLower());
     395             : 
     396         409 :                 static_cast<SwLayoutFrm*>(pCol)->GetFormat()->SetFormatAttr( aLR );
     397         409 :                 static_cast<SwLayoutFrm*>(pCol)->GetFormat()->SetFormatAttr( aUL );
     398             :             }
     399             : 
     400        2055 :             nGutter += aLR.GetLeft() + aLR.GetRight();
     401             :         }
     402             : 
     403        2836 :         pCol = bR2L ? pCol->GetPrev() : pCol->GetNext();
     404             :     }
     405             : 
     406         957 :     if( bOrtho )
     407             :     {
     408         588 :         long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols();
     409         588 :         pCol = Lower();
     410        2350 :         for( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; pCol = pCol->GetNext(), ++i ) //i118878, value returned by GetNumCols() can't be trusted
     411             :         {
     412             :             SwTwips nWidth;
     413        1762 :             if ( i == pAttr->GetNumCols() - 1 )
     414         588 :                 nWidth = nAvail;
     415             :             else
     416             :             {
     417        1174 :                 SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() );
     418        1174 :                 nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight();
     419             :             }
     420        1762 :             if( nWidth < 0 )
     421           0 :                 nWidth = 0;
     422             : 
     423             :             const Size aColSz = bVert ?
     424           0 :                                 Size( Prt().Width(), nWidth ) :
     425        1762 :                                 Size( nWidth, Prt().Height() );
     426             : 
     427        1762 :             pCol->ChgSize( aColSz );
     428             : 
     429        1762 :             if( IsBodyFrm() )
     430          14 :                 static_cast<SwLayoutFrm*>(pCol)->Lower()->ChgSize( aColSz );
     431             : 
     432        1762 :             nAvail -= nWidth;
     433             :         }
     434             :     }
     435         177 : }
     436             : 
     437             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11