LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/data - attarray.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 614 1202 51.1 %
Date: 2012-12-27 Functions: 34 53 64.2 %
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 "scitems.hxx"
      21             : #include <svx/algitem.hxx>
      22             : #include <editeng/boxitem.hxx>
      23             : #include <editeng/bolnitem.hxx>
      24             : #include <editeng/frmdiritem.hxx>
      25             : #include <editeng/shaditem.hxx>
      26             : #include <editeng/editobj.hxx>
      27             : #include <editeng/justifyitem.hxx>
      28             : #include <svl/poolcach.hxx>
      29             : #include <editeng/fontitem.hxx>
      30             : #include <unotools/fontcvt.hxx>
      31             : 
      32             : #include "attarray.hxx"
      33             : #include "global.hxx"
      34             : #include "document.hxx"
      35             : #include "docpool.hxx"
      36             : #include "patattr.hxx"
      37             : #include "stlsheet.hxx"
      38             : #include "stlpool.hxx"
      39             : #include "markarr.hxx"
      40             : #include "rechead.hxx"
      41             : #include "globstr.hrc"
      42             : #include "segmenttree.hxx"
      43             : #include "cell.hxx"
      44             : #include <rtl/strbuf.hxx>
      45             : 
      46             : // STATIC DATA -----------------------------------------------------------
      47             : 
      48             : //------------------------------------------------------------------------
      49             : using ::editeng::SvxBorderLine;
      50             : 
      51      276480 : ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
      52             :     nCol( nNewCol ),
      53             :     nTab( nNewTab ),
      54      276480 :     pDocument( pDoc )
      55             : {
      56      276480 :     nCount = nLimit = 1;
      57      276480 :     pData = new ScAttrEntry[1];
      58      276480 :     if (pData)
      59             :     {
      60      276480 :         pData[0].nRow = MAXROW;
      61      276480 :         pData[0].pPattern = pDocument->GetDefPattern(); // no put
      62             :     }
      63      276480 : }
      64             : 
      65             : //------------------------------------------------------------------------
      66             : 
      67      204800 : ScAttrArray::~ScAttrArray()
      68             : {
      69             : #if OSL_DEBUG_LEVEL > 1
      70             :     TestData();
      71             : #endif
      72             : 
      73      204800 :     if (pData)
      74             :     {
      75      204800 :         ScDocumentPool* pDocPool = pDocument->GetPool();
      76      518043 :         for (SCSIZE i=0; i<nCount; i++)
      77      313243 :             pDocPool->Remove(*pData[i].pPattern);
      78             : 
      79      204800 :         delete[] pData;
      80             :     }
      81      204800 : }
      82             : 
      83             : //------------------------------------------------------------------------
      84             : #if OSL_DEBUG_LEVEL > 1
      85             : void ScAttrArray::TestData() const
      86             : {
      87             : 
      88             :     sal_uInt16 nErr = 0;
      89             :     if (pData)
      90             :     {
      91             :         SCSIZE nPos;
      92             :         for (nPos=0; nPos<nCount; nPos++)
      93             :         {
      94             :             if (nPos > 0)
      95             :                 if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
      96             :                     ++nErr;
      97             :             if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
      98             :                 ++nErr;
      99             :         }
     100             :         if ( nPos && pData[nPos-1].nRow != MAXROW )
     101             :             ++nErr;
     102             :     }
     103             :     if (nErr)
     104             :     {
     105             :         rtl::OStringBuffer aMsg;
     106             :         aMsg.append(static_cast<sal_Int32>(nErr));
     107             :         aMsg.append(RTL_CONSTASCII_STRINGPARAM(
     108             :             " errors in attribute array, column "));
     109             :         aMsg.append(static_cast<sal_Int32>(nCol));
     110             :         OSL_FAIL(aMsg.getStr());
     111             :     }
     112             : }
     113             : #endif
     114             : 
     115             : //------------------------------------------------------------------------
     116             : 
     117        3075 : void ScAttrArray::Reset( const ScPatternAttr* pPattern, bool bAlloc )
     118             : {
     119        3075 :     if (pData)
     120             :     {
     121        3075 :         ScDocumentPool*      pDocPool = pDocument->GetPool();
     122             :         const ScPatternAttr* pOldPattern;
     123        3075 :         ScAddress            aAdrStart( nCol, 0, nTab );
     124        3075 :         ScAddress            aAdrEnd  ( nCol, 0, nTab );
     125             : 
     126        6150 :         for (SCSIZE i=0; i<nCount; i++)
     127             :         {
     128             :             // ensure that attributing changes text width of cell
     129        3075 :             pOldPattern = pData[i].pPattern;
     130             :             bool bNumFormatChanged;
     131        3075 :             if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
     132        3075 :                     pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
     133             :             {
     134           0 :                 aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
     135           0 :                 aAdrEnd  .SetRow( pData[i].nRow );
     136           0 :                 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
     137             :             }
     138        3075 :             pDocPool->Remove(*pOldPattern);
     139             :         }
     140        3075 :         delete[] pData;
     141             : 
     142        3075 :         if (pDocument->IsStreamValid(nTab))
     143           0 :             pDocument->SetStreamValid(nTab, false);
     144             : 
     145        3075 :         if (bAlloc)
     146             :         {
     147        3075 :             nCount = nLimit = 1;
     148        3075 :             pData = new ScAttrEntry[1];
     149        3075 :             if (pData)
     150             :             {
     151        3075 :                 ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
     152        3075 :                 pData[0].nRow = MAXROW;
     153        3075 :                 pData[0].pPattern = pNewPattern;
     154             :             }
     155             :         }
     156             :         else
     157             :         {
     158           0 :             nCount = nLimit = 0;
     159           0 :             pData = NULL;        // should be immediately occupied again
     160             :         }
     161             :     }
     162        3075 : }
     163             : 
     164             : 
     165       17638 : bool ScAttrArray::Concat(SCSIZE nPos)
     166             : {
     167       17638 :     bool bRet = false;
     168       17638 :     if (pData && (nPos < nCount))
     169             :     {
     170       17638 :         if (nPos > 0)
     171             :         {
     172          59 :             if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
     173             :             {
     174           0 :                 pData[nPos - 1].nRow = pData[nPos].nRow;
     175           0 :                 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
     176           0 :                 memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
     177           0 :                 pData[nCount - 1].pPattern = NULL;
     178           0 :                 pData[nCount - 1].nRow = 0;
     179           0 :                 nCount--;
     180           0 :                 nPos--;
     181           0 :                 bRet = true;
     182             :             }
     183             :         }
     184       17638 :         if (nPos + 1 < nCount)
     185             :         {
     186         230 :             if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
     187             :             {
     188          22 :                 pData[nPos].nRow = pData[nPos + 1].nRow;
     189          22 :                 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
     190          22 :                 memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
     191          22 :                 pData[nCount - 1].pPattern = NULL;
     192          22 :                 pData[nCount - 1].nRow = 0;
     193          22 :                 nCount--;
     194          22 :                 bRet = true;
     195             :             }
     196             :         }
     197             :     }
     198       17638 :     return bRet;
     199             : }
     200             : 
     201             : //------------------------------------------------------------------------
     202             : 
     203      214422 : bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
     204             : {
     205      214422 :     long    nHi         = static_cast<long>(nCount) - 1;
     206      214422 :     long    i           = 0;
     207      214422 :     bool    bFound      = (nCount == 1);
     208      214422 :     if (pData)
     209             :     {
     210      214422 :         long nLo = 0;
     211      214422 :         long nStartRow = 0;
     212      214422 :         long nEndRow = 0;
     213      542797 :         while ( !bFound && nLo <= nHi )
     214             :         {
     215      113953 :             i = (nLo + nHi) / 2;
     216      113953 :             if (i > 0)
     217      110582 :                 nStartRow = (long) pData[i - 1].nRow;
     218             :             else
     219        3371 :                 nStartRow = -1;
     220      113953 :             nEndRow = (long) pData[i].nRow;
     221      113953 :             if (nEndRow < (long) nRow)
     222       46591 :                 nLo = ++i;
     223             :             else
     224       67362 :                 if (nStartRow >= (long) nRow)
     225       37862 :                     nHi = --i;
     226             :                 else
     227       29500 :                     bFound = true;
     228             :         }
     229             :     }
     230             :     else
     231           0 :         bFound = false;
     232             : 
     233      214422 :     if (bFound)
     234      213949 :         nIndex=(SCSIZE)i;
     235             :     else
     236         473 :         nIndex=0;
     237      214422 :     return bFound;
     238             : }
     239             : 
     240             : 
     241       18820 : const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
     242             : {
     243             :     SCSIZE i;
     244       18820 :     if (Search( nRow, i ))
     245       18820 :         return pData[i].pPattern;
     246             :     else
     247           0 :         return NULL;
     248             : }
     249             : 
     250             : 
     251          49 : const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
     252             :         SCROW& rEndRow, SCROW nRow ) const
     253             : {
     254             :     SCSIZE nIndex;
     255          49 :     if ( Search( nRow, nIndex ) )
     256             :     {
     257          49 :         if ( nIndex > 0 )
     258          12 :             rStartRow = pData[nIndex-1].nRow + 1;
     259             :         else
     260          37 :             rStartRow = 0;
     261          49 :         rEndRow = pData[nIndex].nRow;
     262          49 :         return pData[nIndex].pPattern;
     263             :     }
     264           0 :     return NULL;
     265             : }
     266             : 
     267          49 : void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
     268             : {
     269          49 :     if(!VALIDROW(nStartRow) || !VALIDROW(nEndRow))
     270           0 :         return;
     271             : 
     272          49 :     if(nEndRow < nStartRow)
     273           0 :         return;
     274             : 
     275          49 :     SCROW nTempStartRow = nStartRow;
     276          49 :     SCROW nTempEndRow = nEndRow;
     277             : 
     278          49 :     do
     279             :     {
     280          49 :         const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
     281             : 
     282          49 :         boost::scoped_ptr<ScPatternAttr> pNewPattern;
     283          49 :         if(pPattern)
     284             :         {
     285          49 :             pNewPattern.reset( new ScPatternAttr(*pPattern) );
     286             :             SCROW nPatternStartRow;
     287             :             SCROW nPatternEndRow;
     288          49 :             GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
     289             : 
     290          49 :             nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
     291          49 :             const SfxPoolItem* pItem = NULL;
     292          49 :             pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
     293          49 :             std::vector< sal_uInt32 > aCondFormatData;
     294          49 :             if(pItem)
     295           1 :                 aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
     296          49 :             aCondFormatData.push_back(nIndex);
     297             : 
     298          49 :             ScCondFormatItem aItem;
     299          49 :             aItem.SetCondFormatData( aCondFormatData );
     300          49 :             pNewPattern->GetItemSet().Put( aItem );
     301             :         }
     302             :         else
     303             :         {
     304           0 :             pNewPattern.reset( new ScPatternAttr( pDocument->GetPool() ) );
     305           0 :             ScCondFormatItem aItem;
     306           0 :             aItem.AddCondFormatData(nIndex);
     307           0 :             pNewPattern->GetItemSet().Put( aItem );
     308           0 :             nTempEndRow = nEndRow;
     309             :         }
     310             : 
     311          49 :         SetPatternArea( nTempStartRow, nTempEndRow, pNewPattern.get(), true );
     312          49 :         nTempStartRow = nTempEndRow + 1;
     313             :     }
     314             :     while(nTempEndRow < nEndRow);
     315             : 
     316             : }
     317             : 
     318           0 : void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
     319             : {
     320           0 :     if(!VALIDROW(nStartRow) || !VALIDROW(nEndRow))
     321           0 :         return;
     322             : 
     323           0 :     if(nEndRow < nStartRow)
     324           0 :         return;
     325             : 
     326           0 :     SCROW nTempStartRow = nStartRow;
     327           0 :     SCROW nTempEndRow = nEndRow;
     328             : 
     329           0 :     do
     330             :     {
     331           0 :         const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
     332             : 
     333           0 :         if(pPattern)
     334             :         {
     335           0 :             ScPatternAttr aPattern( *pPattern );
     336             :             SCROW nPatternStartRow;
     337             :             SCROW nPatternEndRow;
     338           0 :             GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
     339             : 
     340           0 :             nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
     341           0 :             const SfxPoolItem* pItem = NULL;
     342           0 :             pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
     343           0 :             if(pItem)
     344             :             {
     345           0 :                 std::vector< sal_uInt32 > aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
     346           0 :                 std::vector<sal_uInt32>::iterator itr = std::find(aCondFormatData.begin(), aCondFormatData.end(), nIndex);
     347           0 :                 if(itr != aCondFormatData.end())
     348             :                 {
     349           0 :                     ScCondFormatItem aItem;
     350           0 :                     aCondFormatData.erase(itr);
     351           0 :                     aItem.SetCondFormatData( aCondFormatData );
     352           0 :                     aPattern.GetItemSet().Put( aItem );
     353           0 :                     SetPatternArea( nTempStartRow, nTempEndRow, &aPattern, true );
     354           0 :                 }
     355             : 
     356           0 :             }
     357             :         }
     358             :         else
     359             :         {
     360           0 :             return;
     361             :         }
     362             : 
     363           0 :         nTempStartRow = nTempEndRow + 1;
     364             :     }
     365             :     while(nTempEndRow < nEndRow);
     366             : 
     367             : }
     368             : 
     369             : //------------------------------------------------------------------------
     370             : 
     371        1239 : void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bPutToPool )
     372             : {
     373        1239 :     SetPatternArea( nRow, nRow, pPattern, bPutToPool );
     374        1239 : }
     375             : 
     376           0 : void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
     377             :                                        const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
     378             : {
     379           0 :     for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
     380             :     {
     381             :         ScBaseCell* pCell;
     382           0 :         pDocument->GetCell(nCol, nRow, nTab, pCell);
     383           0 :         if (pCell && pCell->GetCellType() == CELLTYPE_EDIT)
     384             :         {
     385           0 :             EditTextObject* pOldData = NULL;
     386           0 :             ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell);
     387           0 :             if (pDataArray)
     388           0 :                 pOldData = pEditCell->GetData()->Clone();
     389           0 :             pEditCell->RemoveCharAttribs(*pPattern);
     390           0 :             if (pDataArray)
     391             :             {
     392           0 :                 EditTextObject* pNewData = pEditCell->GetData()->Clone();
     393           0 :                 pDataArray->AddItem(nTab, nCol, nRow, pOldData, pNewData);
     394             :             }
     395             :         }
     396             :     }
     397           0 : }
     398             : 
     399       14341 : void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
     400             :                                  bool bPutToPool, ScEditDataArray* pDataArray )
     401             : {
     402       14341 :     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     403             :     {
     404       14341 :         if (bPutToPool)
     405        7194 :             pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
     406             : 
     407       14341 :         if ((nStartRow == 0) && (nEndRow == MAXROW))
     408        3075 :             Reset(pPattern);
     409             :         else
     410             :         {
     411       11266 :             SCSIZE nNeeded = nCount + 2;
     412       11266 :             if ( nLimit < nNeeded )
     413             :             {
     414        1671 :                 nLimit += SC_ATTRARRAY_DELTA;
     415        1671 :                 if ( nLimit < nNeeded )
     416           0 :                     nLimit = nNeeded;
     417        1671 :                 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
     418        1671 :                 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
     419        1671 :                 delete[] pData;
     420        1671 :                 pData = pNewData;
     421             :             }
     422             : 
     423       11266 :             ScAddress       aAdrStart( nCol, 0, nTab );
     424       11266 :             ScAddress       aAdrEnd  ( nCol, 0, nTab );
     425             : 
     426       11266 :             SCSIZE ni = 0;      // number of entries in beginning
     427       11266 :             SCSIZE nx = 0;      // track position
     428       11266 :             SCROW ns = 0;      // start row of track position
     429       11266 :             if ( nStartRow > 0 )
     430             :             {
     431             :                 // skip beginning
     432             :                 SCSIZE nIndex;
     433       10516 :                 Search( nStartRow, nIndex );
     434       10516 :                 ni = nIndex;
     435             : 
     436       10516 :                 if ( ni > 0 )
     437             :                 {
     438        6189 :                     nx = ni;
     439        6189 :                     ns = pData[ni-1].nRow+1;
     440             :                 }
     441             :             }
     442             : 
     443             :             // ensure that attributing changes text width of cell
     444             :             // otherwise, conditional formats need to be reset or deleted
     445       33977 :             while ( ns <= nEndRow )
     446             :             {
     447       11445 :                 const SfxItemSet& rNewSet = pPattern->GetItemSet();
     448       11445 :                 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
     449             : 
     450             :                 bool bNumFormatChanged;
     451       11445 :                 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
     452       11445 :                         rNewSet, rOldSet ) )
     453             :                 {
     454         401 :                     aAdrStart.SetRow( Max(nStartRow,ns) );
     455         401 :                     aAdrEnd  .SetRow( Min(nEndRow,pData[nx].nRow) );
     456         401 :                     pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
     457             :                 }
     458       11445 :                 ns = pData[nx].nRow + 1;
     459       11445 :                 nx++;
     460             :             }
     461             : 
     462             :             // continue modifying data array
     463             : 
     464             :             SCSIZE nInsert;     // insert position (MAXROWCOUNT := no insert)
     465       11266 :             bool bCombined = false;
     466       11266 :             bool bSplit = false;
     467       11266 :             if ( nStartRow > 0 )
     468             :             {
     469       10516 :                 nInsert = MAXROWCOUNT;
     470       10516 :                 if ( pData[ni].pPattern != pPattern )
     471             :                 {
     472        6359 :                     if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
     473             :                     {   // may be a split or a simple insert or just a shrink,
     474             :                         // row adjustment is done further down
     475         291 :                         if ( pData[ni].nRow > nEndRow )
     476         216 :                             bSplit = true;
     477         291 :                         ni++;
     478         291 :                         nInsert = ni;
     479             :                     }
     480        6068 :                     else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
     481        6068 :                         nInsert = ni;
     482             :                 }
     483       10516 :                 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
     484             :                 {   // combine
     485         335 :                     pData[ni-1].nRow = nEndRow;
     486         335 :                     nInsert = MAXROWCOUNT;
     487         335 :                     bCombined = true;
     488             :                 }
     489             :             }
     490             :             else
     491         750 :                 nInsert = 0;
     492             : 
     493       11266 :             SCSIZE nj = ni;     // stop position of range to replace
     494       28563 :             while ( nj < nCount && pData[nj].nRow <= nEndRow )
     495        6031 :                 nj++;
     496       11266 :             if ( !bSplit )
     497             :             {
     498       11050 :                 if ( nj < nCount && pData[nj].pPattern == pPattern )
     499             :                 {   // combine
     500        4318 :                     if ( ni > 0 )
     501             :                     {
     502          26 :                         if ( pData[ni-1].pPattern == pPattern )
     503             :                         {   // adjacent entries
     504          26 :                             pData[ni-1].nRow = pData[nj].nRow;
     505          26 :                             nj++;
     506             :                         }
     507           0 :                         else if ( ni == nInsert )
     508           0 :                             pData[ni-1].nRow = nStartRow - 1;   // shrink
     509             :                     }
     510        4318 :                     nInsert = MAXROWCOUNT;
     511        4318 :                     bCombined = true;
     512             :                 }
     513        6732 :                 else if ( ni > 0 && ni == nInsert )
     514        5808 :                     pData[ni-1].nRow = nStartRow - 1;   // shrink
     515             :             }
     516       11266 :             ScDocumentPool* pDocPool = pDocument->GetPool();
     517       11266 :             if ( bSplit )
     518             :             {   // duplicate splitted entry in pool
     519         216 :                 pDocPool->Put( *pData[ni-1].pPattern );
     520             :             }
     521       11266 :             if ( ni < nj )
     522             :             {   // remove middle entries
     523       11909 :                 for ( SCSIZE nk=ni; nk<nj; nk++)
     524             :                 {   // remove entries from pool
     525        6057 :                     pDocPool->Remove( *pData[nk].pPattern );
     526             :                 }
     527        5852 :                 if ( !bCombined )
     528             :                 {   // replace one entry
     529        5748 :                     pData[ni].nRow = nEndRow;
     530        5748 :                     pData[ni].pPattern = pPattern;
     531        5748 :                     ni++;
     532        5748 :                     nInsert = MAXROWCOUNT;
     533             :                 }
     534        5852 :                 if ( ni < nj )
     535             :                 {   // remove entries
     536         104 :                     memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
     537         104 :                     nCount -= nj - ni;
     538             :                 }
     539             :             }
     540             : 
     541       11266 :             if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
     542             :             {   // insert or append new entry
     543         891 :                 if ( nInsert <= nCount )
     544             :                 {
     545         891 :                     if ( !bSplit )
     546         675 :                         memmove( pData + nInsert + 1, pData + nInsert,
     547        1350 :                             (nCount - nInsert) * sizeof(ScAttrEntry) );
     548             :                     else
     549             :                     {
     550         216 :                         memmove( pData + nInsert + 2, pData + nInsert,
     551         432 :                             (nCount - nInsert) * sizeof(ScAttrEntry) );
     552         216 :                         pData[nInsert+1] = pData[nInsert-1];
     553         216 :                         nCount++;
     554             :                     }
     555             :                 }
     556         891 :                 if ( nInsert )
     557         720 :                     pData[nInsert-1].nRow = nStartRow - 1;
     558         891 :                 pData[nInsert].nRow = nEndRow;
     559         891 :                 pData[nInsert].pPattern = pPattern;
     560             : 
     561             :                 // Remove character attributes from these cells if the pattern
     562             :                 // is applied during normal session.
     563         891 :                 if (pDataArray)
     564           0 :                     RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
     565             : 
     566         891 :                 nCount++;
     567             :             }
     568             : 
     569       11266 :             if (pDocument->IsStreamValid(nTab))
     570           0 :                 pDocument->SetStreamValid(nTab, false);
     571             :         }
     572             :     }
     573             : 
     574             : #if OSL_DEBUG_LEVEL > 1
     575             :     TestData();
     576             : #endif
     577       14341 : }
     578             : 
     579             : 
     580        1135 : void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
     581             : {
     582        1135 :     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     583             :     {
     584             :         SCSIZE nPos;
     585        1135 :         SCROW nStart=0;
     586        1135 :         if (!Search( nStartRow, nPos ))
     587             :         {
     588             :             OSL_FAIL("Search Failure");
     589        1135 :             return;
     590             :         }
     591             : 
     592        1135 :         ScAddress aAdrStart( nCol, 0, nTab );
     593        1135 :         ScAddress aAdrEnd  ( nCol, 0, nTab );
     594             : 
     595        1231 :         do
     596             :         {
     597        1231 :             const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
     598        1231 :             ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
     599        1231 :             pNewPattern->SetStyleSheet(pStyle);
     600        1231 :             SCROW nY1 = nStart;
     601        1231 :             SCROW nY2 = pData[nPos].nRow;
     602        1231 :             nStart = pData[nPos].nRow + 1;
     603             : 
     604        1231 :             if ( *pNewPattern == *pOldPattern )
     605             :             {
     606             :                 // keep the original pattern (might be default)
     607             :                 // pNewPattern is deleted below
     608         707 :                 nPos++;
     609             :             }
     610         524 :             else if ( nY1 < nStartRow || nY2 > nEndRow )
     611             :             {
     612         439 :                 if (nY1 < nStartRow) nY1=nStartRow;
     613         439 :                 if (nY2 > nEndRow) nY2=nEndRow;
     614         439 :                 SetPatternArea( nY1, nY2, pNewPattern, true );
     615         439 :                 Search( nStart, nPos );
     616             :             }
     617             :             else
     618             :             {
     619             :                 // ensure attributing changes text width of cell; otherwise
     620             :                 // there aren't (yet) template format changes
     621          85 :                 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
     622          85 :                 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
     623             : 
     624             :                 bool bNumFormatChanged;
     625          85 :                 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
     626          85 :                         rNewSet, rOldSet ) )
     627             :                 {
     628           0 :                     aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
     629           0 :                     aAdrEnd  .SetRow( pData[nPos].nRow );
     630           0 :                     pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
     631             :                 }
     632             : 
     633          85 :                 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
     634          85 :                 pData[nPos].pPattern = (const ScPatternAttr*)
     635          85 :                                             &pDocument->GetPool()->Put(*pNewPattern);
     636          85 :                 if (Concat(nPos))
     637           0 :                     Search(nStart, nPos);
     638             :                 else
     639          85 :                     nPos++;
     640             :             }
     641        1231 :             delete pNewPattern;
     642             :         }
     643             :         while ((nStart <= nEndRow) && (nPos < nCount));
     644             : 
     645        1135 :         if (pDocument->IsStreamValid(nTab))
     646           0 :             pDocument->SetStreamValid(nTab, false);
     647             :     }
     648             : 
     649             : #if OSL_DEBUG_LEVEL > 1
     650             :     TestData();
     651             : #endif
     652             : }
     653             : 
     654             : 
     655             :     // const cast, otherwise it will be too inefficient/complicated
     656             : #define SET_LINECOLOR(dest,c)                    \
     657             :     if ((dest))                                  \
     658             :     {                                            \
     659             :         ((SvxBorderLine*)(dest))->SetColor((c)); \
     660             :     }
     661             : 
     662             : #define SET_LINE(dest,src)                             \
     663             :     if ((dest))                                        \
     664             :     {                                                  \
     665             :         SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
     666             :         pCast->SetBorderLineStyle( (src)->GetBorderLineStyle() ); \
     667             :         pCast->SetWidth( (src)->GetWidth( ) );         \
     668             :     }
     669             : 
     670           0 : void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
     671             :                                       const SvxBorderLine* pLine, bool bColorOnly )
     672             : {
     673           0 :     if ( bColorOnly && !pLine )
     674           0 :         return;
     675             : 
     676           0 :     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     677             :     {
     678             :         SCSIZE nPos;
     679           0 :         SCROW nStart=0;
     680           0 :         if (!Search( nStartRow, nPos ))
     681             :         {
     682             :             OSL_FAIL("Search failure");
     683             :             return;
     684             :         }
     685             : 
     686           0 :         do
     687             :         {
     688           0 :             const ScPatternAttr*    pOldPattern = pData[nPos].pPattern;
     689           0 :             const SfxItemSet&       rOldSet = pOldPattern->GetItemSet();
     690           0 :             const SfxPoolItem*      pBoxItem = 0;
     691           0 :             SfxItemState            eState = rOldSet.GetItemState( ATTR_BORDER, true, &pBoxItem );
     692           0 :             const SfxPoolItem*      pTLBRItem = 0;
     693           0 :             SfxItemState            eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
     694           0 :             const SfxPoolItem*      pBLTRItem = 0;
     695           0 :             SfxItemState            eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
     696             : 
     697           0 :             if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
     698             :             {
     699           0 :                 ScPatternAttr*  pNewPattern = new ScPatternAttr(*pOldPattern);
     700           0 :                 SfxItemSet&     rNewSet = pNewPattern->GetItemSet();
     701           0 :                 SCROW           nY1 = nStart;
     702           0 :                 SCROW           nY2 = pData[nPos].nRow;
     703             : 
     704           0 :                 SvxBoxItem*     pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
     705           0 :                 SvxLineItem*    pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
     706           0 :                 SvxLineItem*    pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
     707             : 
     708             :                 // fetch line and update attributes with parameters
     709             : 
     710           0 :                 if ( !pLine )
     711             :                 {
     712           0 :                     if( pNewBoxItem )
     713             :                     {
     714           0 :                         if ( pNewBoxItem->GetTop() )    pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
     715           0 :                         if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
     716           0 :                         if ( pNewBoxItem->GetLeft() )   pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
     717           0 :                         if ( pNewBoxItem->GetRight() )  pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
     718             :                     }
     719           0 :                     if( pNewTLBRItem && pNewTLBRItem->GetLine() )
     720           0 :                         pNewTLBRItem->SetLine( 0 );
     721           0 :                     if( pNewBLTRItem && pNewBLTRItem->GetLine() )
     722           0 :                         pNewBLTRItem->SetLine( 0 );
     723             :                 }
     724             :                 else
     725             :                 {
     726           0 :                     if ( bColorOnly )
     727             :                     {
     728           0 :                         Color aColor( pLine->GetColor() );
     729           0 :                         if( pNewBoxItem )
     730             :                         {
     731           0 :                             SET_LINECOLOR( pNewBoxItem->GetTop(),    aColor );
     732           0 :                             SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
     733           0 :                             SET_LINECOLOR( pNewBoxItem->GetLeft(),   aColor );
     734           0 :                             SET_LINECOLOR( pNewBoxItem->GetRight(),   aColor );
     735             :                         }
     736           0 :                         if( pNewTLBRItem )
     737           0 :                             SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
     738           0 :                         if( pNewBLTRItem )
     739           0 :                             SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
     740             :                     }
     741             :                     else
     742             :                     {
     743           0 :                         if( pNewBoxItem )
     744             :                         {
     745           0 :                             SET_LINE( pNewBoxItem->GetTop(),    pLine );
     746           0 :                             SET_LINE( pNewBoxItem->GetBottom(), pLine );
     747           0 :                             SET_LINE( pNewBoxItem->GetLeft(),   pLine );
     748           0 :                             SET_LINE( pNewBoxItem->GetRight(),   pLine );
     749             :                         }
     750           0 :                         if( pNewTLBRItem )
     751           0 :                             SET_LINE( pNewTLBRItem->GetLine(), pLine );
     752           0 :                         if( pNewBLTRItem )
     753           0 :                             SET_LINE( pNewBLTRItem->GetLine(), pLine );
     754             :                     }
     755             :                 }
     756           0 :                 if( pNewBoxItem )   rNewSet.Put( *pNewBoxItem );
     757           0 :                 if( pNewTLBRItem )  rNewSet.Put( *pNewTLBRItem );
     758           0 :                 if( pNewBLTRItem )  rNewSet.Put( *pNewBLTRItem );
     759             : 
     760           0 :                 nStart = pData[nPos].nRow + 1;
     761             : 
     762           0 :                 if ( nY1 < nStartRow || nY2 > nEndRow )
     763             :                 {
     764           0 :                     if (nY1 < nStartRow) nY1=nStartRow;
     765           0 :                     if (nY2 > nEndRow) nY2=nEndRow;
     766           0 :                     SetPatternArea( nY1, nY2, pNewPattern, true );
     767           0 :                     Search( nStart, nPos );
     768             :                 }
     769             :                 else
     770             :                 {
     771             :                     // remove from pool ?
     772           0 :                     pDocument->GetPool()->Remove(*pData[nPos].pPattern);
     773           0 :                     pData[nPos].pPattern = (const ScPatternAttr*)
     774           0 :                                 &pDocument->GetPool()->Put(*pNewPattern);
     775             : 
     776           0 :                     if (Concat(nPos))
     777           0 :                         Search(nStart, nPos);
     778             :                     else
     779           0 :                         nPos++;
     780             :                 }
     781           0 :                 delete pNewBoxItem;
     782           0 :                 delete pNewTLBRItem;
     783           0 :                 delete pNewBLTRItem;
     784           0 :                 delete pNewPattern;
     785             :             }
     786             :             else
     787             :             {
     788           0 :                 nStart = pData[nPos].nRow + 1;
     789           0 :                 nPos++;
     790             :             }
     791             :         }
     792             :         while ((nStart <= nEndRow) && (nPos < nCount));
     793             :     }
     794             : }
     795             : 
     796             : #undef SET_LINECOLOR
     797             : #undef SET_LINE
     798             : 
     799             : 
     800       18237 : void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
     801             : {
     802             : #if OSL_DEBUG_LEVEL > 1
     803             :     TestData();
     804             : #endif
     805             : 
     806       18237 :     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     807             :     {
     808             :         SCSIZE nPos;
     809       18237 :         SCROW nStart=0;
     810       18237 :         if (!Search( nStartRow, nPos ))
     811             :         {
     812             :             OSL_FAIL("Search Failure");
     813       18237 :             return;
     814             :         }
     815             : 
     816       18237 :         ScAddress aAdrStart( nCol, 0, nTab );
     817       18237 :         ScAddress aAdrEnd  ( nCol, 0, nTab );
     818             : 
     819       18251 :         do
     820             :         {
     821       18251 :             const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
     822       18251 :             const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, true );
     823       18251 :             ScDocumentPool::CheckRef( *pOldPattern );
     824       18251 :             ScDocumentPool::CheckRef( *pNewPattern );
     825       18251 :             if (pNewPattern != pOldPattern)
     826             :             {
     827       18227 :                 SCROW nY1 = nStart;
     828       18227 :                 SCROW nY2 = pData[nPos].nRow;
     829       18227 :                 nStart = pData[nPos].nRow + 1;
     830             : 
     831       18227 :                 if ( nY1 < nStartRow || nY2 > nEndRow )
     832             :                 {
     833         674 :                     if (nY1 < nStartRow) nY1=nStartRow;
     834         674 :                     if (nY2 > nEndRow) nY2=nEndRow;
     835         674 :                     SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
     836         674 :                     Search( nStart, nPos );
     837             :                 }
     838             :                 else
     839             :                 {
     840             :                     // ensure attributing changes text-width of cell
     841             : 
     842       17553 :                     const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
     843       17553 :                     const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
     844             : 
     845             :                     bool bNumFormatChanged;
     846       17553 :                     if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
     847       17553 :                             rNewSet, rOldSet ) )
     848             :                     {
     849           2 :                         aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
     850           2 :                         aAdrEnd  .SetRow( pData[nPos].nRow );
     851           2 :                         pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
     852             :                     }
     853             : 
     854       17553 :                     pDocument->GetPool()->Remove(*pData[nPos].pPattern);
     855       17553 :                     pData[nPos].pPattern = pNewPattern;
     856       17553 :                     if (Concat(nPos))
     857          22 :                         Search(nStart, nPos);
     858             :                     else
     859       17531 :                         ++nPos;
     860             :                 }
     861             :             }
     862             :             else
     863             :             {
     864          24 :                 nStart = pData[nPos].nRow + 1;
     865          24 :                 ++nPos;
     866             :             }
     867             :         }
     868             :         while (nStart <= nEndRow);
     869             : 
     870       18237 :         if (pDocument->IsStreamValid(nTab))
     871           0 :             pDocument->SetStreamValid(nTab, false);
     872             :     }
     873             : 
     874             : #if OSL_DEBUG_LEVEL > 1
     875             :     TestData();
     876             : #endif
     877             : }
     878             : 
     879       20535 : bool ScAttrArray::SetAttrEntries(ScAttrEntry* pNewData, SCSIZE nSize)
     880             : {
     881       20535 :     if (pData)
     882             :     {
     883       20535 :         ScDocumentPool* pDocPool = pDocument->GetPool();
     884       41070 :         for (SCSIZE i=0; i<nCount; i++)
     885       20535 :             pDocPool->Remove(*pData[i].pPattern);
     886             : 
     887       20535 :         delete[] pData;
     888             :     }
     889             : 
     890       20535 :     pData = pNewData;
     891       20535 :     nCount = nLimit = nSize;
     892       20535 :     return true;
     893             : }
     894             : 
     895           0 : static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
     896             : {
     897             :     const SfxPoolItem* pNewItem;
     898             :     const SfxPoolItem* pOldItem;
     899           0 :     for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
     900             :     {
     901             :         //  pMergeSet has no parent
     902           0 :         SfxItemState eOldState = rMergeSet.GetItemState( nId, false, &pOldItem );
     903             : 
     904           0 :         if ( eOldState == SFX_ITEM_DEFAULT )
     905             :         {
     906           0 :             SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
     907           0 :             if ( eNewState == SFX_ITEM_SET )
     908             :             {
     909           0 :                 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
     910           0 :                     rMergeSet.InvalidateItem( nId );
     911             :             }
     912             :         }
     913           0 :         else if ( eOldState == SFX_ITEM_SET )               // Item gesetzt
     914             :         {
     915           0 :             SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
     916           0 :             if ( eNewState == SFX_ITEM_SET )
     917             :             {
     918           0 :                 if ( pNewItem != pOldItem )                 // beide gepuhlt
     919           0 :                     rMergeSet.InvalidateItem( nId );
     920             :             }
     921             :             else            // Default
     922             :             {
     923           0 :                 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
     924           0 :                     rMergeSet.InvalidateItem( nId );
     925             :             }
     926             :         }
     927             :         // Dontcare remains Dontcare
     928             :     }
     929           0 : }
     930             : 
     931             : 
     932       21807 : void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
     933             :                                     ScMergePatternState& rState, bool bDeep ) const
     934             : {
     935       21807 :     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     936             :     {
     937             :         SCSIZE nPos;
     938       21807 :         SCROW nStart=0;
     939       21807 :         if (!Search( nStartRow, nPos ))
     940             :         {
     941             :             OSL_FAIL("Search failure");
     942       21807 :             return;
     943             :         }
     944             : 
     945       21807 :         do
     946             :         {
     947             :             // similar patterns must not be repeated
     948             : 
     949       21807 :             const ScPatternAttr* pPattern = pData[nPos].pPattern;
     950       21807 :             if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
     951             :             {
     952         185 :                 const SfxItemSet& rThisSet = pPattern->GetItemSet();
     953         185 :                 if (rState.pItemSet)
     954             :                 {
     955           0 :                     if (bDeep)
     956           0 :                         lcl_MergeDeep( *rState.pItemSet, rThisSet );
     957             :                     else
     958           0 :                         rState.pItemSet->MergeValues( rThisSet, false );
     959             :                 }
     960             :                 else
     961             :                 {
     962             :                     // first pattern - copied from parent
     963         185 :                     rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
     964         185 :                     rState.pItemSet->Set( rThisSet, bDeep );
     965             :                 }
     966             : 
     967         185 :                 rState.pOld2 = rState.pOld1;
     968         185 :                 rState.pOld1 = pPattern;
     969             :             }
     970             : 
     971       21807 :             nStart = pData[nPos].nRow + 1;
     972       21807 :             ++nPos;
     973             :         }
     974             :         while (nStart <= nEndRow);
     975             :     }
     976             : }
     977             : 
     978             : 
     979             : 
     980             : // assemble border
     981             : 
     982           0 : static bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
     983             :                             sal_uInt8& rModified, const SvxBorderLine*& rpNew )
     984             : {
     985           0 :     if (rModified == SC_LINE_DONTCARE)
     986           0 :         return false;               // don't go again
     987             : 
     988           0 :     if (rModified == SC_LINE_EMPTY)
     989             :     {
     990           0 :         rModified = SC_LINE_SET;
     991           0 :         rpNew = pNewLine;
     992           0 :         return true;                // initial value
     993             :     }
     994             : 
     995           0 :     if (pOldLine == pNewLine)
     996             :     {
     997           0 :         rpNew = pOldLine;
     998           0 :         return false;
     999             :     }
    1000             : 
    1001           0 :     if (pOldLine && pNewLine)
    1002           0 :         if (*pOldLine == *pNewLine)
    1003             :         {
    1004           0 :             rpNew = pOldLine;
    1005           0 :             return false;
    1006             :         }
    1007             : 
    1008           0 :     rModified = SC_LINE_DONTCARE;
    1009           0 :     rpNew = NULL;
    1010           0 :     return true;              // another line -> don't care
    1011             : }
    1012             : 
    1013             : 
    1014           0 : static void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
    1015             :                                 ScLineFlags& rFlags, const ScPatternAttr* pPattern,
    1016             :                                 bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
    1017             : {
    1018             :     // right/bottom border set when connected together
    1019           0 :     const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
    1020           0 :     if ( rMerge.GetColMerge() == nDistRight + 1 )
    1021           0 :         nDistRight = 0;
    1022           0 :     if ( rMerge.GetRowMerge() == nDistBottom + 1 )
    1023           0 :         nDistBottom = 0;
    1024             : 
    1025           0 :     const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
    1026           0 :     const SvxBorderLine* pLeftAttr   = pCellFrame->GetLeft();
    1027           0 :     const SvxBorderLine* pRightAttr  = pCellFrame->GetRight();
    1028           0 :     const SvxBorderLine* pTopAttr    = pCellFrame->GetTop();
    1029           0 :     const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
    1030             :     const SvxBorderLine* pNew;
    1031             : 
    1032           0 :     if (bTop)
    1033             :     {
    1034           0 :         if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
    1035           0 :             pLineOuter->SetLine( pNew, BOX_LINE_TOP );
    1036             :     }
    1037             :     else
    1038             :     {
    1039           0 :         if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
    1040           0 :             pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
    1041             :     }
    1042             : 
    1043           0 :     if (nDistBottom == 0)
    1044             :     {
    1045           0 :         if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
    1046           0 :             pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
    1047             :     }
    1048             :     else
    1049             :     {
    1050           0 :         if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
    1051           0 :             pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
    1052             :     }
    1053             : 
    1054           0 :     if (bLeft)
    1055             :     {
    1056           0 :         if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
    1057           0 :             pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
    1058             :     }
    1059             :     else
    1060             :     {
    1061           0 :         if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
    1062           0 :             pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
    1063             :     }
    1064             : 
    1065           0 :     if (nDistRight == 0)
    1066             :     {
    1067           0 :         if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
    1068           0 :             pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
    1069             :     }
    1070             :     else
    1071             :     {
    1072           0 :         if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
    1073           0 :             pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
    1074             :     }
    1075           0 : }
    1076             : 
    1077             : 
    1078           0 : void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
    1079             :                     ScLineFlags& rFlags,
    1080             :                     SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
    1081             : {
    1082             :     const ScPatternAttr* pPattern;
    1083             : 
    1084           0 :     if (nStartRow == nEndRow)
    1085             :     {
    1086           0 :         pPattern = GetPattern( nStartRow );
    1087           0 :         lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 );
    1088             :     }
    1089             :     else
    1090             :     {
    1091           0 :         pPattern = GetPattern( nStartRow );
    1092             :         lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
    1093           0 :                             nEndRow-nStartRow );
    1094             : 
    1095             :         SCSIZE nStartIndex;
    1096             :         SCSIZE nEndIndex;
    1097           0 :         Search( nStartRow+1, nStartIndex );
    1098           0 :         Search( nEndRow-1, nEndIndex );
    1099           0 :         for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
    1100             :         {
    1101           0 :             pPattern = (ScPatternAttr*) pData[i].pPattern;
    1102             :             lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false,
    1103           0 :                             nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
    1104             :             // nDistBottom here always > 0
    1105             :         }
    1106             : 
    1107           0 :         pPattern = GetPattern( nEndRow );
    1108           0 :         lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 );
    1109             :     }
    1110           0 : }
    1111             : 
    1112             : //
    1113             : // apply border
    1114             : //
    1115             : 
    1116             : // ApplyFrame - on an entry into the array
    1117             : 
    1118         677 : bool ScAttrArray::ApplyFrame( const SvxBoxItem*     pBoxItem,
    1119             :                               const SvxBoxInfoItem* pBoxInfoItem,
    1120             :                               SCROW nStartRow, SCROW nEndRow,
    1121             :                               bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
    1122             : {
    1123             :     OSL_ENSURE( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" );
    1124             : 
    1125         677 :     const ScPatternAttr* pPattern = GetPattern( nStartRow );
    1126             :     const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
    1127         677 :                                   &pPattern->GetItemSet().Get( ATTR_BORDER );
    1128             : 
    1129             :     // right/bottom border set when connected together
    1130         677 :     const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
    1131         677 :     if ( rMerge.GetColMerge() == nDistRight + 1 )
    1132           0 :         nDistRight = 0;
    1133         677 :     if ( rMerge.GetRowMerge() == nDistBottom + 1 )
    1134           0 :         nDistBottom = 0;
    1135             : 
    1136         677 :     SvxBoxItem aNewFrame( *pOldFrame );
    1137             : 
    1138         677 :     if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
    1139             :         aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
    1140         445 :             BOX_LINE_LEFT );
    1141         677 :     if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
    1142             :         aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
    1143         446 :             BOX_LINE_RIGHT );
    1144         677 :     if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
    1145             :         aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
    1146         395 :             BOX_LINE_TOP );
    1147         677 :     if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
    1148             :         aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
    1149         395 :             BOX_LINE_BOTTOM );
    1150             : 
    1151         677 :     if (aNewFrame == *pOldFrame)
    1152             :     {
    1153             :         // nothing to do
    1154         137 :         return false;
    1155             :     }
    1156             :     else
    1157             :     {
    1158         540 :         SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
    1159         540 :         ApplyCacheArea( nStartRow, nEndRow, &aCache );
    1160             : 
    1161         540 :         return true;
    1162         677 :     }
    1163             : }
    1164             : 
    1165             : 
    1166         390 : void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
    1167             :                             SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
    1168             : {
    1169         390 :     if (nStartRow == nEndRow)
    1170         232 :         ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0 );
    1171             :     else
    1172             :     {
    1173             :         ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
    1174         158 :                         true, nEndRow-nStartRow );
    1175             : 
    1176         158 :         if ( nEndRow > nStartRow+1 )     // inner part available?
    1177             :         {
    1178             :             SCSIZE nStartIndex;
    1179             :             SCSIZE nEndIndex;
    1180          90 :             Search( nStartRow+1, nStartIndex );
    1181          90 :             Search( nEndRow-1, nEndIndex );
    1182          90 :             SCROW nTmpStart = nStartRow+1;
    1183             :             SCROW nTmpEnd;
    1184         309 :             for (SCSIZE i=nStartIndex; i<=nEndIndex;)
    1185             :             {
    1186         129 :                 nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
    1187             :                 bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
    1188         129 :                                             bLeft, nDistRight, false, nEndRow-nTmpEnd );
    1189         129 :                 nTmpStart = nTmpEnd+1;
    1190         129 :                 if (bChanged)
    1191             :                 {
    1192          64 :                     Search(nTmpStart, i);
    1193          64 :                     Search(nEndRow-1, nEndIndex);
    1194             :                 }
    1195             :                 else
    1196          65 :                     i++;
    1197             :             }
    1198             :         }
    1199             : 
    1200         158 :         ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0 );
    1201             :     }
    1202         390 : }
    1203             : 
    1204             : // Test if field contains specific attribute
    1205             : 
    1206       53069 : bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
    1207             : {
    1208             :     SCSIZE nStartIndex;
    1209             :     SCSIZE nEndIndex;
    1210       53069 :     Search( nRow1, nStartIndex );
    1211       53069 :     Search( nRow2, nEndIndex );
    1212       53069 :     bool bFound = false;
    1213             : 
    1214      106341 :     for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
    1215             :     {
    1216       53272 :         const ScPatternAttr* pPattern = pData[i].pPattern;
    1217       53272 :         if ( nMask & HASATTR_MERGED )
    1218             :         {
    1219             :             const ScMergeAttr* pMerge =
    1220          12 :                     (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
    1221          12 :             if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
    1222           2 :                 bFound = true;
    1223             :         }
    1224       53272 :         if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
    1225             :         {
    1226             :             const ScMergeFlagAttr* pMergeFlag =
    1227        2380 :                     (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
    1228        2380 :             if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
    1229           1 :                 bFound = true;
    1230        2380 :             if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
    1231           0 :                 bFound = true;
    1232        2380 :             if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
    1233           0 :                 bFound = true;
    1234             :         }
    1235       53272 :         if ( nMask & HASATTR_LINES )
    1236             :         {
    1237             :             const SvxBoxItem* pBox =
    1238       35959 :                     (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
    1239       35959 :             if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
    1240           1 :                 bFound = true;
    1241             :         }
    1242       53272 :         if ( nMask & HASATTR_SHADOW )
    1243             :         {
    1244             :             const SvxShadowItem* pShadow =
    1245       35857 :                     (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
    1246       35857 :             if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
    1247           0 :                 bFound = true;
    1248             :         }
    1249       53272 :         if ( nMask & HASATTR_CONDITIONAL )
    1250             :         {
    1251             :             bool bContainsCondFormat =
    1252       36881 :                     !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
    1253       36881 :             if ( bContainsCondFormat )
    1254           0 :                 bFound = true;
    1255             :         }
    1256       53272 :         if ( nMask & HASATTR_PROTECTED )
    1257             :         {
    1258             :             const ScProtectionAttr* pProtect =
    1259           0 :                     (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
    1260           0 :             bool bFoundTemp = false;
    1261           0 :             if ( pProtect->GetProtection() || pProtect->GetHideCell() )
    1262           0 :                 bFoundTemp = true;
    1263             : 
    1264             :             bool bContainsCondFormat =
    1265           0 :                     !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
    1266           0 :             if ( bContainsCondFormat )
    1267             :             {
    1268           0 :                 SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? pData[i-1].nRow + 1: 0 );
    1269           0 :                 SCROW nRowEndCond = std::min<SCROW>( nRow2, pData[i].nRow );
    1270           0 :                 bool bFoundCond = false;
    1271           0 :                 for(SCROW nRowCond = nRowStartCond; nRowCond <= nRowEndCond && !bFoundCond; ++nRowCond)
    1272             :                 {
    1273           0 :                     const SfxItemSet* pSet = pDocument->GetCondResult( nCol, nRowCond, nTab );
    1274             : 
    1275             :                     const SfxPoolItem* pItem;
    1276           0 :                     if( pSet && pSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SFX_ITEM_SET )
    1277             :                     {
    1278           0 :                         const ScProtectionAttr* pCondProtect = static_cast<const ScProtectionAttr*>(pItem);
    1279           0 :                         if( pCondProtect->GetProtection() || pProtect->GetHideCell() )
    1280           0 :                             bFoundCond = true;
    1281             :                     }
    1282             :                     else
    1283             :                     {
    1284             :                         // well it is not true that we found one
    1285             :                         // but existing one + cell where conditional
    1286             :                         // formatting does not remove it
    1287             :                         // => we have a protected cell
    1288           0 :                         bFoundCond = true;
    1289             :                     }
    1290             :                 }
    1291           0 :                 bFoundTemp = bFoundCond;
    1292             :             }
    1293             : 
    1294           0 :             if(bFoundTemp)
    1295           0 :                 bFound = true;
    1296             :         }
    1297       53272 :         if ( nMask & HASATTR_ROTATE )
    1298             :         {
    1299             :             const SfxInt32Item* pRotate =
    1300           0 :                     (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
    1301             :             // 90 or 270 degrees is former SvxOrientationItem - only look for other values
    1302             :             // (see ScPatternAttr::GetCellOrientation)
    1303           0 :             sal_Int32 nAngle = pRotate->GetValue();
    1304           0 :             if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
    1305           0 :                 bFound = true;
    1306             :         }
    1307       53272 :         if ( nMask & HASATTR_NEEDHEIGHT )
    1308             :         {
    1309           6 :             if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
    1310           0 :                 bFound = true;
    1311           6 :             else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
    1312           0 :                 bFound = true;
    1313           6 :             else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
    1314           6 :                         GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
    1315           0 :                 bFound = true;
    1316             : 
    1317           6 :             else if (!static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData().empty())
    1318           0 :                 bFound = true;
    1319           6 :             else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
    1320           0 :                 bFound = true;
    1321             :         }
    1322       53272 :         if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
    1323             :         {
    1324             :             const SvxShadowItem* pShadow =
    1325         574 :                     (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
    1326         574 :             SvxShadowLocation eLoc = pShadow->GetLocation();
    1327         574 :             if ( nMask & HASATTR_SHADOW_RIGHT )
    1328          50 :                 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
    1329           0 :                     bFound = true;
    1330         574 :             if ( nMask & HASATTR_SHADOW_DOWN )
    1331         524 :                 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
    1332           0 :                     bFound = true;
    1333             :         }
    1334       53272 :         if ( nMask & HASATTR_RTL )
    1335             :         {
    1336             :             const SvxFrameDirectionItem& rDirection =
    1337           0 :                     (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
    1338           0 :             if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
    1339           0 :                 bFound = true;
    1340             :         }
    1341       53272 :         if ( nMask & HASATTR_RIGHTORCENTER )
    1342             :         {
    1343             :             //  called only if the sheet is LTR, so physical=logical alignment can be assumed
    1344             :             SvxCellHorJustify eHorJust = (SvxCellHorJustify)
    1345       13328 :                     ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
    1346       13328 :             if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
    1347           0 :                 bFound = true;
    1348             :         }
    1349             :     }
    1350             : 
    1351       53069 :     return bFound;
    1352             : }
    1353             : 
    1354             : // Area around any given summaries expand and adapt any MergeFlag (bRefresh)
    1355        1415 : bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
    1356             :                                 SCCOL& rPaintCol, SCROW& rPaintRow,
    1357             :                                 bool bRefresh )
    1358             : {
    1359             :     const ScPatternAttr* pPattern;
    1360             :     const ScMergeAttr* pItem;
    1361             :     SCSIZE nStartIndex;
    1362             :     SCSIZE nEndIndex;
    1363        1415 :     Search( nStartRow, nStartIndex );
    1364        1415 :     Search( nEndRow, nEndIndex );
    1365        1415 :     bool bFound = false;
    1366             : 
    1367        2958 :     for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
    1368             :     {
    1369        1543 :         pPattern = pData[i].pPattern;
    1370        1543 :         pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
    1371        1543 :         SCsCOL  nCountX = pItem->GetColMerge();
    1372        1543 :         SCsROW  nCountY = pItem->GetRowMerge();
    1373        1543 :         if (nCountX>1 || nCountY>1)
    1374             :         {
    1375          11 :             SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
    1376          11 :             SCCOL nMergeEndCol = nThisCol + nCountX - 1;
    1377          11 :             SCROW nMergeEndRow = nThisRow + nCountY - 1;
    1378          11 :             if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
    1379           9 :                 rPaintCol = nMergeEndCol;
    1380          11 :             if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
    1381          10 :                 rPaintRow = nMergeEndRow;
    1382          11 :             bFound = true;
    1383             : 
    1384          11 :             if (bRefresh)
    1385             :             {
    1386           1 :                 if ( nMergeEndCol > nThisCol )
    1387           1 :                     pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
    1388           2 :                                 nTab, SC_MF_HOR );
    1389           1 :                 if ( nMergeEndRow > nThisRow )
    1390             :                     pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
    1391           1 :                                 nTab, SC_MF_VER );
    1392           1 :                 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
    1393             :                     pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
    1394           1 :                                 nTab, SC_MF_HOR | SC_MF_VER );
    1395             : 
    1396           1 :                 Search( nThisRow, i );    // Data changed
    1397           1 :                 Search( nStartRow, nStartIndex );
    1398           1 :                 Search( nEndRow, nEndIndex );
    1399             :             }
    1400             :         }
    1401             :     }
    1402             : 
    1403        1415 :     return bFound;
    1404             : }
    1405             : 
    1406             : 
    1407        2182 : bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
    1408             : {
    1409        2182 :     bool bFound = false;
    1410             :     const ScPatternAttr* pPattern;
    1411             :     const ScMergeAttr* pItem;
    1412             :     SCSIZE nIndex;
    1413             : 
    1414        2182 :     Search( nStartRow, nIndex );
    1415        2182 :     SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    1416        2182 :     if (nThisStart < nStartRow)
    1417        2055 :         nThisStart = nStartRow;
    1418             : 
    1419        6725 :     while ( nThisStart <= nEndRow )
    1420             :     {
    1421        2361 :         SCROW nThisEnd = pData[nIndex].nRow;
    1422        2361 :         if (nThisEnd > nEndRow)
    1423        2131 :             nThisEnd = nEndRow;
    1424             : 
    1425        2361 :         pPattern = pData[nIndex].pPattern;
    1426        2361 :         pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
    1427        2361 :         SCsCOL  nCountX = pItem->GetColMerge();
    1428        2361 :         SCsROW  nCountY = pItem->GetRowMerge();
    1429        2361 :         if (nCountX>1 || nCountY>1)
    1430             :         {
    1431             :             const ScMergeAttr* pAttr = (const ScMergeAttr*)
    1432           0 :                                             &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
    1433             :             const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
    1434           0 :                                             &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
    1435             : 
    1436             :             OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" );
    1437             : 
    1438           0 :             SCCOL nThisCol = nCol;
    1439           0 :             SCCOL nMergeEndCol = nThisCol + nCountX - 1;
    1440           0 :             SCROW nMergeEndRow = nThisEnd + nCountY - 1;
    1441             : 
    1442             :             // ApplyAttr for areas
    1443             : 
    1444           0 :             for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
    1445           0 :                 pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
    1446             : 
    1447           0 :             ScPatternAttr*  pNewPattern = new ScPatternAttr( pDocument->GetPool() );
    1448           0 :             SfxItemSet*     pSet = &pNewPattern->GetItemSet();
    1449           0 :             pSet->Put( *pFlagAttr );
    1450             :             pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
    1451           0 :                                                 nTab, *pNewPattern );
    1452           0 :             delete pNewPattern;
    1453             : 
    1454           0 :             Search( nThisEnd, nIndex );    // data changed
    1455             :         }
    1456             : 
    1457        2361 :         ++nIndex;
    1458        2361 :         if ( nIndex < nCount )
    1459         228 :             nThisStart = pData[nIndex-1].nRow+1;
    1460             :         else
    1461        2133 :             nThisStart = MAXROW+1;   // End
    1462             :     }
    1463             : 
    1464        2182 :     return bFound;
    1465             : }
    1466             : 
    1467             : // Remove field, but leave MergeFlags
    1468             : 
    1469           0 : void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
    1470             : {
    1471           0 :     SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), true );
    1472           0 : }
    1473             : 
    1474             : 
    1475           0 : void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
    1476             :                         const ScPatternAttr* pWantedPattern, bool bDefault )
    1477             : {
    1478             :     const ScPatternAttr*    pOldPattern;
    1479             :     const ScMergeFlagAttr*  pItem;
    1480             : 
    1481             :     SCSIZE  nIndex;
    1482             :     SCROW   nRow;
    1483             :     SCROW   nThisRow;
    1484           0 :     bool    bFirstUse = true;
    1485             : 
    1486           0 :     Search( nStartRow, nIndex );
    1487           0 :     nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    1488           0 :     while ( nThisRow <= nEndRow )
    1489             :     {
    1490           0 :         pOldPattern = pData[nIndex].pPattern;
    1491           0 :         if (pOldPattern != pWantedPattern)                          //! else-Zweig ?
    1492             :         {
    1493           0 :             if (nThisRow < nStartRow) nThisRow = nStartRow;
    1494           0 :             nRow = pData[nIndex].nRow;
    1495           0 :             SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
    1496           0 :             pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
    1497             : 
    1498           0 :             if (pItem->IsOverlapped() || pItem->HasAutoFilter())
    1499             :             {
    1500             :                 //  default-constructing a ScPatternAttr for DeleteArea doesn't work
    1501             :                 //  because it would have no cell style information.
    1502             :                 //  Instead, the document's GetDefPattern is copied. Since it is passed as
    1503             :                 //  pWantedPattern, no special treatment of default is needed here anymore.
    1504           0 :                 ScPatternAttr*  pNewPattern = new ScPatternAttr( *pWantedPattern );
    1505           0 :                 SfxItemSet*     pSet = &pNewPattern->GetItemSet();
    1506           0 :                 pSet->Put( *pItem );
    1507           0 :                 SetPatternArea( nThisRow, nAttrRow, pNewPattern, true );
    1508           0 :                 delete pNewPattern;
    1509             :             }
    1510             :             else
    1511             :             {
    1512           0 :                 if ( !bDefault )
    1513             :                 {
    1514           0 :                     if (bFirstUse)
    1515           0 :                         bFirstUse = false;
    1516             :                     else
    1517             :                         // it's in the pool
    1518           0 :                         pDocument->GetPool()->Put( *pWantedPattern );
    1519             :                 }
    1520           0 :                 SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
    1521             :             }
    1522             : 
    1523           0 :             Search( nThisRow, nIndex );   // data changed
    1524             :         }
    1525             : 
    1526           0 :         ++nIndex;
    1527           0 :         nThisRow = pData[nIndex-1].nRow+1;
    1528             :     }
    1529           0 : }
    1530             : 
    1531             : 
    1532        3991 : bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
    1533             : {
    1534             :     const ScPatternAttr* pOldPattern;
    1535             : 
    1536             :     sal_Int16   nOldValue;
    1537             :     SCSIZE  nIndex;
    1538             :     SCROW   nRow;
    1539             :     SCROW   nThisRow;
    1540        3991 :     bool    bChanged = false;
    1541             : 
    1542        3991 :     Search( nStartRow, nIndex );
    1543        3991 :     nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    1544        3991 :     if (nThisRow < nStartRow) nThisRow = nStartRow;
    1545             : 
    1546       12378 :     while ( nThisRow <= nEndRow )
    1547             :     {
    1548        4396 :         pOldPattern = pData[nIndex].pPattern;
    1549        4396 :         nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
    1550        4396 :         if ( (nOldValue | nFlags) != nOldValue )
    1551             :         {
    1552        4362 :             nRow = pData[nIndex].nRow;
    1553        4362 :             SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
    1554        4362 :             ScPatternAttr aNewPattern(*pOldPattern);
    1555        4362 :             aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
    1556        4362 :             SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
    1557        4362 :             Search( nThisRow, nIndex );  // data changed
    1558        4362 :             bChanged = true;
    1559             :         }
    1560             : 
    1561        4396 :         ++nIndex;
    1562        4396 :         nThisRow = pData[nIndex-1].nRow+1;
    1563             :     }
    1564             : 
    1565        3991 :     return bChanged;
    1566             : }
    1567             : 
    1568             : 
    1569       11384 : bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
    1570             : {
    1571             :     const ScPatternAttr* pOldPattern;
    1572             : 
    1573             :     sal_Int16   nOldValue;
    1574             :     SCSIZE  nIndex;
    1575             :     SCROW   nRow;
    1576             :     SCROW   nThisRow;
    1577       11384 :     bool    bChanged = false;
    1578             : 
    1579       11384 :     Search( nStartRow, nIndex );
    1580       11384 :     nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    1581       11384 :     if (nThisRow < nStartRow) nThisRow = nStartRow;
    1582             : 
    1583       34355 :     while ( nThisRow <= nEndRow )
    1584             :     {
    1585       11587 :         pOldPattern = pData[nIndex].pPattern;
    1586       11587 :         nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
    1587       11587 :         if ( (nOldValue & ~nFlags) != nOldValue )
    1588             :         {
    1589         246 :             nRow = pData[nIndex].nRow;
    1590         246 :             SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
    1591         246 :             ScPatternAttr aNewPattern(*pOldPattern);
    1592         246 :             aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
    1593         246 :             SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
    1594         246 :             Search( nThisRow, nIndex );  // data changed
    1595         246 :             bChanged = true;
    1596             :         }
    1597             : 
    1598       11587 :         ++nIndex;
    1599       11587 :         nThisRow = pData[nIndex-1].nRow+1;
    1600             :     }
    1601             : 
    1602       11384 :     return bChanged;
    1603             : }
    1604             : 
    1605             : 
    1606           2 : void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
    1607             : {
    1608             :     const ScPatternAttr* pOldPattern;
    1609             : 
    1610             :     SCSIZE  nIndex;
    1611             :     SCROW   nRow;
    1612             :     SCROW   nThisRow;
    1613             : 
    1614           2 :     Search( nStartRow, nIndex );
    1615           2 :     nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    1616           2 :     if (nThisRow < nStartRow) nThisRow = nStartRow;
    1617             : 
    1618           6 :     while ( nThisRow <= nEndRow )
    1619             :     {
    1620           2 :         pOldPattern = pData[nIndex].pPattern;
    1621           2 :         if ( pOldPattern->HasItemsSet( pWhich ) )
    1622             :         {
    1623           0 :             ScPatternAttr aNewPattern(*pOldPattern);
    1624           0 :             aNewPattern.ClearItems( pWhich );
    1625             : 
    1626           0 :             nRow = pData[nIndex].nRow;
    1627           0 :             SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
    1628           0 :             SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
    1629           0 :             Search( nThisRow, nIndex );  // data changed
    1630             :         }
    1631             : 
    1632           2 :         ++nIndex;
    1633           2 :         nThisRow = pData[nIndex-1].nRow+1;
    1634             :     }
    1635           2 : }
    1636             : 
    1637             : 
    1638           0 : void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
    1639             : {
    1640             :     SCSIZE nIndex;
    1641           0 :     Search( nStartRow, nIndex );
    1642           0 :     SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    1643           0 :     if (nThisStart < nStartRow) nThisStart = nStartRow;
    1644             : 
    1645           0 :     while ( nThisStart <= nEndRow )
    1646             :     {
    1647           0 :         const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
    1648           0 :         const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
    1649             :         const SfxPoolItem* pItem;
    1650             : 
    1651           0 :         bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, false, &pItem ) != SFX_ITEM_SET
    1652           0 :                         || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
    1653           0 :         sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
    1654           0 :         sal_uInt16 nNewValue = nOldValue;
    1655           0 :         if ( bIncrement )
    1656             :         {
    1657           0 :             if ( nNewValue < SC_MAX_INDENT )
    1658             :             {
    1659           0 :                 nNewValue += SC_INDENT_STEP;
    1660           0 :                 if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT;
    1661             :             }
    1662             :         }
    1663             :         else
    1664             :         {
    1665           0 :             if ( nNewValue > 0 )
    1666             :             {
    1667           0 :                 if ( nNewValue > SC_INDENT_STEP )
    1668           0 :                     nNewValue -= SC_INDENT_STEP;
    1669             :                 else
    1670           0 :                     nNewValue = 0;
    1671             :             }
    1672             :         }
    1673             : 
    1674           0 :         if ( bNeedJust || nNewValue != nOldValue )
    1675             :         {
    1676           0 :             SCROW nThisEnd = pData[nIndex].nRow;
    1677           0 :             SCROW nAttrRow = Min( nThisEnd, nEndRow );
    1678           0 :             ScPatternAttr aNewPattern(*pOldPattern);
    1679           0 :             aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
    1680           0 :             if ( bNeedJust )
    1681           0 :                 aNewPattern.GetItemSet().Put(
    1682           0 :                                 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
    1683           0 :             SetPatternArea( nThisStart, nAttrRow, &aNewPattern, true );
    1684             : 
    1685           0 :             nThisStart = nThisEnd + 1;
    1686           0 :             Search( nThisStart, nIndex ); // data changed
    1687             :         }
    1688             :         else
    1689             :         {
    1690           0 :             nThisStart = pData[nIndex].nRow + 1;
    1691           0 :             ++nIndex;
    1692             :         }
    1693             :     }
    1694           0 : }
    1695             : 
    1696             : 
    1697           0 : SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, bool bUp ) const
    1698             : {
    1699           0 :     long nRet = nRow;
    1700           0 :     if (VALIDROW(nRow))
    1701             :     {
    1702             :         SCSIZE nIndex;
    1703           0 :         Search(nRow, nIndex);
    1704           0 :         while (((const ScProtectionAttr&)pData[nIndex].pPattern->
    1705           0 :                 GetItem(ATTR_PROTECTION)).GetProtection())
    1706             :         {
    1707           0 :             if (bUp)
    1708             :             {
    1709           0 :                 if (nIndex==0)
    1710           0 :                     return -1;   // not found
    1711           0 :                 --nIndex;
    1712           0 :                 nRet = pData[nIndex].nRow;
    1713             :             }
    1714             :             else
    1715             :             {
    1716           0 :                 nRet = pData[nIndex].nRow+1;
    1717           0 :                 ++nIndex;
    1718           0 :                 if (nIndex>=nCount)
    1719           0 :                     return MAXROW+1; // not found
    1720             :             }
    1721             :         }
    1722             :     }
    1723           0 :     return nRet;
    1724             : }
    1725             : 
    1726     2400256 : void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
    1727             : {
    1728     2400256 :     SCROW nStart = 0;
    1729     2400256 :     SCSIZE nPos = 0;
    1730     7204596 :     while (nPos < nCount)
    1731             :     {
    1732     2404084 :         SCROW nEnd = pData[nPos].nRow;
    1733     2404084 :         if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
    1734             :         {
    1735     1235968 :             rUsedRows.setTrue(nStart, nEnd);
    1736             : 
    1737     1235968 :             if (bReset)
    1738             :             {
    1739           0 :                 ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
    1740           0 :                 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
    1741             :                 pNewPattern->SetStyleSheet( (ScStyleSheet*)
    1742           0 :                     pDocument->GetStyleSheetPool()->
    1743           0 :                         Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
    1744             :                               SFX_STYLE_FAMILY_PARA,
    1745           0 :                               SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
    1746           0 :                 pData[nPos].pPattern = (const ScPatternAttr*)
    1747           0 :                                             &pDocument->GetPool()->Put(*pNewPattern);
    1748           0 :                 delete pNewPattern;
    1749             : 
    1750           0 :                 if (Concat(nPos))
    1751             :                 {
    1752           0 :                     Search(nStart, nPos);
    1753           0 :                     --nPos;   // because ++ at end
    1754             :                 }
    1755             :             }
    1756             :         }
    1757     2404084 :         nStart = nEnd + 1;
    1758     2404084 :         ++nPos;
    1759             :     }
    1760     2400256 : }
    1761             : 
    1762             : 
    1763           0 : bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
    1764             :         bool bGatherAllStyles ) const
    1765             : {
    1766           0 :     bool    bIsUsed = false;
    1767           0 :     SCSIZE  nPos    = 0;
    1768             : 
    1769           0 :     while ( nPos < nCount )
    1770             :     {
    1771           0 :         const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
    1772           0 :         if ( pStyle )
    1773             :         {
    1774           0 :             pStyle->SetUsage( ScStyleSheet::USED );
    1775           0 :             if ( pStyle == &rStyle )
    1776             :             {
    1777           0 :                 if ( !bGatherAllStyles )
    1778           0 :                     return true;
    1779           0 :                 bIsUsed = true;
    1780             :             }
    1781             :         }
    1782           0 :         nPos++;
    1783             :     }
    1784             : 
    1785           0 :     return bIsUsed;
    1786             : }
    1787             : 
    1788             : 
    1789           2 : bool ScAttrArray::IsEmpty() const
    1790             : {
    1791           2 :     if (nCount == 1)
    1792             :     {
    1793           2 :         if ( pData[0].pPattern != pDocument->GetDefPattern() )
    1794           0 :             return false;
    1795             :         else
    1796           2 :             return true;
    1797             :     }
    1798             :     else
    1799           0 :         return false;
    1800             : }
    1801             : 
    1802             : 
    1803        6144 : bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
    1804             : {
    1805             :     OSL_ENSURE( nCount, "nCount == 0" );
    1806             : 
    1807        6144 :     bool bFound = false;
    1808        6144 :     SCSIZE nStart = 0;
    1809             : 
    1810             :     // Skip first entry if more than 1 row.
    1811             :     // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
    1812             : 
    1813        6144 :     SCSIZE nVisStart = 1;
    1814       12288 :     while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
    1815           0 :         ++nVisStart;
    1816        6144 :     if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 )   // more than 1 row?
    1817        6144 :         nStart = nVisStart;
    1818             : 
    1819       12288 :     while ( nStart < nCount && !bFound )
    1820             :     {
    1821           0 :         if ( pData[nStart].pPattern->IsVisible() )
    1822             :         {
    1823           0 :             rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
    1824           0 :             bFound = true;
    1825             :         }
    1826             :         else
    1827           0 :             ++nStart;
    1828             :     }
    1829             : 
    1830        6144 :     return bFound;
    1831             : }
    1832             : 
    1833             : // size (rows) of a range of attributes after cell content where the search is stopped
    1834             : // (more than a default page size, 2*42 because it's as good as any number)
    1835             : 
    1836             : const SCROW SC_VISATTR_STOP = 84;
    1837             : 
    1838       80134 : bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bFullFormattedArea ) const
    1839             : {
    1840             :     OSL_ENSURE( nCount, "nCount == 0" );
    1841             : 
    1842             :     //  #i30830# changed behavior:
    1843             :     //  ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
    1844             :     //  below the last content cell
    1845             : 
    1846       80134 :     if ( nLastData == MAXROW )
    1847             :     {
    1848           0 :         rLastRow = MAXROW;      // can't look for attributes below MAXROW
    1849           0 :         return true;
    1850             :     }
    1851             : 
    1852             :     // Quick check: last data row in or immediately preceding a run that is the
    1853             :     // last attribution down to the end, e.g. default style or column style.
    1854       80134 :     SCSIZE nPos = nCount - 1;
    1855       80134 :     SCROW nStartRow = (nPos ? pData[nPos-1].nRow + 1 : 0);
    1856       80134 :     if (nStartRow <= nLastData + 1)
    1857             :     {
    1858       80132 :         if (bFullFormattedArea && pData[nPos].pPattern->IsVisible())
    1859             :         {
    1860           0 :             rLastRow = pData[nPos].nRow;
    1861           0 :             return true;
    1862             :         }
    1863             :         else
    1864             :         {
    1865             :             // Ignore here a few rows if data happens to end within
    1866             :             // SC_VISATTR_STOP rows before MAXROW.
    1867       80132 :             rLastRow = nLastData;
    1868       80132 :             return false;
    1869             :         }
    1870             :     }
    1871             : 
    1872             :     // Find a run below last data row.
    1873           2 :     bool bFound = false;
    1874           2 :     Search( nLastData, nPos );
    1875           4 :     while ( nPos < nCount )
    1876             :     {
    1877             :         // find range of visually equal formats
    1878           2 :         SCSIZE nEndPos = nPos;
    1879          16 :         while ( nEndPos < nCount-1 &&
    1880           6 :                 pData[nEndPos].pPattern->IsVisibleEqual( *pData[nEndPos+1].pPattern))
    1881           6 :             ++nEndPos;
    1882           2 :         SCROW nAttrStartRow = ( nPos > 0 ) ? ( pData[nPos-1].nRow + 1 ) : 0;
    1883           2 :         if ( nAttrStartRow <= nLastData )
    1884           2 :             nAttrStartRow = nLastData + 1;
    1885           2 :         SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
    1886           2 :         if ( nAttrSize >= SC_VISATTR_STOP && !bFullFormattedArea )
    1887           2 :             break;  // while, ignore this range and below
    1888           0 :         else if ( pData[nEndPos].pPattern->IsVisible() )
    1889             :         {
    1890           0 :             rLastRow = pData[nEndPos].nRow;
    1891           0 :             bFound = true;
    1892             :         }
    1893           0 :         nPos = nEndPos + 1;
    1894             :     }
    1895             : 
    1896           2 :     return bFound;
    1897             : }
    1898             : 
    1899             : 
    1900           0 : bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
    1901             : {
    1902             :     SCSIZE nIndex;
    1903           0 :     Search( nStartRow, nIndex );
    1904           0 :     SCROW nThisStart = nStartRow;
    1905           0 :     bool bFound = false;
    1906           0 :     while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
    1907             :     {
    1908           0 :         if ( pData[nIndex].pPattern->IsVisible() )
    1909           0 :             bFound = true;
    1910             : 
    1911           0 :         nThisStart = pData[nIndex].nRow + 1;
    1912           0 :         ++nIndex;
    1913             :     }
    1914             : 
    1915           0 :     return bFound;
    1916             : }
    1917             : 
    1918             : 
    1919           0 : bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
    1920             :                                     SCROW nStartRow, SCROW nEndRow ) const
    1921             : {
    1922           0 :     bool bEqual = true;
    1923           0 :     SCSIZE nThisPos = 0;
    1924           0 :     SCSIZE nOtherPos = 0;
    1925           0 :     if ( nStartRow > 0 )
    1926             :     {
    1927           0 :         Search( nStartRow, nThisPos );
    1928           0 :         rOther.Search( nStartRow, nOtherPos );
    1929             :     }
    1930             : 
    1931           0 :     while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
    1932             :     {
    1933           0 :         SCROW nThisRow = pData[nThisPos].nRow;
    1934           0 :         SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
    1935           0 :         const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
    1936           0 :         const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
    1937             :         bEqual = ( pThisPattern == pOtherPattern ||
    1938           0 :                     pThisPattern->IsVisibleEqual(*pOtherPattern) );
    1939             : 
    1940           0 :         if ( nThisRow >= nOtherRow )
    1941             :         {
    1942           0 :             if ( nOtherRow >= nEndRow ) break;
    1943           0 :             ++nOtherPos;
    1944             :         }
    1945           0 :         if ( nThisRow <= nOtherRow )
    1946             :         {
    1947           0 :             if ( nThisRow >= nEndRow ) break;
    1948           0 :             ++nThisPos;
    1949             :         }
    1950             :     }
    1951             : 
    1952           0 :     return bEqual;
    1953             : }
    1954             : 
    1955             : 
    1956        2046 : bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
    1957             : {
    1958             :     // summarised with IsVisibleEqual
    1959             : 
    1960        2046 :     bool bEqual = true;
    1961        2046 :     SCSIZE nThisPos = 0;
    1962        2046 :     SCSIZE nOtherPos = 0;
    1963        2046 :     if ( nStartRow > 0 )
    1964             :     {
    1965           0 :         Search( nStartRow, nThisPos );
    1966           0 :         rOther.Search( nStartRow, nOtherPos );
    1967             :     }
    1968             : 
    1969        4092 :     while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
    1970             :     {
    1971        2046 :         SCROW nThisRow = pData[nThisPos].nRow;
    1972        2046 :         SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
    1973        2046 :         const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
    1974        2046 :         const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
    1975        2046 :         bEqual = ( pThisPattern == pOtherPattern );
    1976             : 
    1977        2046 :         if ( nThisRow >= nOtherRow )
    1978             :         {
    1979        2046 :             if ( nOtherRow >= nEndRow ) break;
    1980           0 :             ++nOtherPos;
    1981             :         }
    1982           0 :         if ( nThisRow <= nOtherRow )
    1983             :         {
    1984           0 :             if ( nThisRow >= nEndRow ) break;
    1985           0 :             ++nThisPos;
    1986             :         }
    1987             :     }
    1988             : 
    1989        2046 :     return bEqual;
    1990             : }
    1991             : 
    1992             : 
    1993           0 : bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
    1994             : {
    1995             :     // Horizontal aggregate are not allowed to be moved out; if whole summary,
    1996             :     // here is not recognized
    1997             : 
    1998           0 :     bool bTest = true;
    1999           0 :     if (!IsEmpty())
    2000             :     {
    2001           0 :         SCSIZE nIndex = 0;
    2002           0 :         if ( nStartRow > 0 )
    2003           0 :             Search( nStartRow, nIndex );
    2004             : 
    2005           0 :         for ( ; nIndex < nCount; nIndex++ )
    2006             :         {
    2007           0 :             if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
    2008           0 :                         GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
    2009             :             {
    2010           0 :                 bTest = false;  // may not be pushed out
    2011           0 :                 break;
    2012             :             }
    2013           0 :             if ( pData[nIndex].nRow >= nEndRow ) // end of range
    2014           0 :                 break;
    2015             :         }
    2016             :     }
    2017           0 :     return bTest;
    2018             : }
    2019             : 
    2020             : 
    2021        5121 : bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
    2022             : {
    2023             :     // if 1st row pushed out is vertically overlapped, summary would be broken
    2024             : 
    2025        5121 :     if (pData)
    2026             :     {
    2027             :         // MAXROW + 1 - nSize   = 1st row pushed out
    2028             : 
    2029        5121 :         SCSIZE nFirstLost = nCount-1;
    2030       10242 :         while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
    2031           0 :             --nFirstLost;
    2032             : 
    2033       10242 :         if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
    2034        5121 :                             GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
    2035           0 :             return false;
    2036             :     }
    2037             : 
    2038        5121 :     return true;
    2039             : }
    2040             : 
    2041             : 
    2042        5121 : void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
    2043             : {
    2044        5121 :     if (!pData)
    2045        5121 :         return;
    2046             : 
    2047        5121 :     SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0;  // expand predecessor
    2048             :     SCSIZE nIndex;
    2049        5121 :     Search( nSearch, nIndex );
    2050             : 
    2051             :     // set ScMergeAttr may not be extended (so behind delete again)
    2052             : 
    2053        5121 :     bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
    2054             : 
    2055        5121 :     SCSIZE nRemove = 0;
    2056             :     SCSIZE i;
    2057        5125 :     for (i = nIndex; i < nCount-1; i++)
    2058             :     {
    2059           4 :         SCROW nNew = pData[i].nRow + nSize;
    2060           4 :         if ( nNew >= MAXROW )    // at end?
    2061             :         {
    2062           0 :             nNew = MAXROW;
    2063           0 :             if (!nRemove)
    2064           0 :                 nRemove = i+1;  // remove the following?
    2065             :         }
    2066           4 :         pData[i].nRow = nNew;
    2067             :     }
    2068             : 
    2069             :     // Remove entries at end ?
    2070             : 
    2071        5121 :     if (nRemove && nRemove < nCount)
    2072           0 :         DeleteRange( nRemove, nCount-1 );
    2073             : 
    2074        5121 :     if (bDoMerge)   // extensively repair (again) ScMergeAttr
    2075             :     {
    2076             :             //  ApplyAttr for areas
    2077             : 
    2078           0 :         const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
    2079           0 :         for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
    2080           0 :             pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
    2081             : 
    2082             :         // reply inserts in this area not summarized
    2083             :     }
    2084             : 
    2085             :     // Don't duplicate the merge flags in the inserted row.
    2086             :     // #i108488# SC_MF_SCENARIO has to be allowed.
    2087        5121 :     RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
    2088             : }
    2089             : 
    2090             : 
    2091        3074 : void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
    2092             : {
    2093        3074 :     if (pData)
    2094             :     {
    2095        3074 :         bool bFirst=true;
    2096        3074 :         SCSIZE nStartIndex = 0;
    2097        3074 :         SCSIZE nEndIndex = 0;
    2098             :         SCSIZE i;
    2099             : 
    2100        3074 :         for ( i = 0; i < nCount-1; i++)
    2101           0 :             if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
    2102             :             {
    2103           0 :                 if (bFirst)
    2104             :                 {
    2105           0 :                     nStartIndex = i;
    2106           0 :                     bFirst = false;
    2107             :                 }
    2108           0 :                 nEndIndex = i;
    2109             :             }
    2110        3074 :         if (!bFirst)
    2111             :         {
    2112             :             SCROW nStart;
    2113           0 :             if (nStartIndex==0)
    2114           0 :                 nStart = 0;
    2115             :             else
    2116           0 :                 nStart = pData[nStartIndex-1].nRow + 1;
    2117             : 
    2118           0 :             if (nStart < nStartRow)
    2119             :             {
    2120           0 :                 pData[nStartIndex].nRow = nStartRow - 1;
    2121           0 :                 ++nStartIndex;
    2122             :             }
    2123           0 :             if (nEndIndex >= nStartIndex)
    2124             :             {
    2125           0 :                 DeleteRange( nStartIndex, nEndIndex );
    2126           0 :                 if (nStartIndex > 0)
    2127           0 :                     if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
    2128           0 :                         DeleteRange( nStartIndex-1, nStartIndex-1 );
    2129             :             }
    2130             :         }
    2131        3074 :         for (i = 0; i < nCount-1; i++)
    2132           0 :             if (pData[i].nRow >= nStartRow)
    2133           0 :                 pData[i].nRow -= nSize;
    2134             : 
    2135             :         // Below does not follow the pattern to detect pressure ranges;
    2136             :         // instead, only remove merge flags.
    2137        3074 :         RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
    2138             :     }
    2139        3074 : }
    2140             : 
    2141             : 
    2142           0 : void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
    2143             : {
    2144           0 :     ScDocumentPool* pDocPool = pDocument->GetPool();
    2145           0 :     for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
    2146           0 :         pDocPool->Remove(*pData[i].pPattern);
    2147             : 
    2148           0 :     memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
    2149           0 :     nCount -= nEndIndex-nStartIndex+1;
    2150           0 : }
    2151             : 
    2152             : 
    2153        2182 : void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
    2154             : {
    2155        2182 :     RemoveAreaMerge( nStartRow, nEndRow );  // remove from combined flags
    2156             : 
    2157        2182 :     if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
    2158        2182 :         SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
    2159             :     else
    2160           0 :         DeleteAreaSafe( nStartRow, nEndRow );  // leave merge flags
    2161        2182 : }
    2162             : 
    2163             : 
    2164           0 : void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
    2165             : {
    2166           0 :     const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
    2167             :     const ScPatternAttr* pOldPattern;
    2168             : 
    2169             :     SCSIZE  nIndex;
    2170             :     SCROW   nRow;
    2171             :     SCROW   nThisRow;
    2172             : 
    2173           0 :     Search( nStartRow, nIndex );
    2174           0 :     nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
    2175           0 :     if (nThisRow < nStartRow) nThisRow = nStartRow;
    2176             : 
    2177           0 :     while ( nThisRow <= nEndRow )
    2178             :     {
    2179           0 :         pOldPattern = pData[nIndex].pPattern;
    2180             : 
    2181           0 :         if ( pOldPattern->GetItemSet().Count() )  // hard attributes ?
    2182             :         {
    2183           0 :             nRow = pData[nIndex].nRow;
    2184           0 :             SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
    2185             : 
    2186           0 :             ScPatternAttr aNewPattern(*pOldPattern);
    2187           0 :             SfxItemSet& rSet = aNewPattern.GetItemSet();
    2188           0 :             for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
    2189           0 :                 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
    2190           0 :                     rSet.ClearItem(nId);
    2191             : 
    2192           0 :             if ( aNewPattern == *pDefPattern )
    2193           0 :                 SetPatternArea( nThisRow, nAttrRow, pDefPattern, false );
    2194             :             else
    2195           0 :                 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
    2196             : 
    2197           0 :             Search( nThisRow, nIndex );  // data changed
    2198             :         }
    2199             : 
    2200           0 :         ++nIndex;
    2201           0 :         nThisRow = pData[nIndex-1].nRow+1;
    2202             :     }
    2203           0 : }
    2204             : 
    2205             : 
    2206             : // move within a document
    2207             : 
    2208        2040 : void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
    2209             : {
    2210        2040 :     SCROW nStart = nStartRow;
    2211        4080 :     for (SCSIZE i = 0; i < nCount; i++)
    2212             :     {
    2213        2040 :         if ((pData[i].nRow >= nStartRow) && ((i==0) ? true : pData[i-1].nRow < nEndRow))
    2214             :         {
    2215             :             // copy (bPutToPool=TRUE)
    2216        2040 :             rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
    2217        4080 :                                         pData[i].pPattern, true );
    2218             :         }
    2219        2040 :         nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
    2220             :     }
    2221        2040 :     DeleteArea(nStartRow, nEndRow);
    2222        2040 : }
    2223             : 
    2224             : 
    2225             : // copy between documents (Clipboard)
    2226             : 
    2227        3099 : void ScAttrArray::CopyArea(
    2228             :     SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, sal_Int16 nStripFlags) const
    2229             : {
    2230        3099 :     nStartRow -= nDy;   // Source
    2231        3099 :     nEndRow -= nDy;
    2232             : 
    2233        3099 :     SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
    2234        3099 :     SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
    2235             : 
    2236        3099 :     ScDocumentPool* pSourceDocPool = pDocument->GetPool();
    2237        3099 :     ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
    2238        3099 :     bool bSamePool = (pSourceDocPool==pDestDocPool);
    2239             : 
    2240        6208 :     for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
    2241             :     {
    2242        3109 :         if (pData[i].nRow >= nStartRow)
    2243             :         {
    2244        3103 :             const ScPatternAttr* pOldPattern = pData[i].pPattern;
    2245             :             const ScPatternAttr* pNewPattern;
    2246             : 
    2247        3103 :             if (IsDefaultItem( pOldPattern ))
    2248             :             {
    2249             :                 // default: nothing changed
    2250             : 
    2251             :                 pNewPattern = (const ScPatternAttr*)
    2252        3093 :                                 &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
    2253             :             }
    2254          10 :             else if ( nStripFlags )
    2255             :             {
    2256           0 :                 ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
    2257           0 :                 sal_Int16 nNewFlags = 0;
    2258           0 :                 if ( nStripFlags != SC_MF_ALL )
    2259           0 :                     nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
    2260           0 :                                 GetValue() & ~nStripFlags;
    2261             : 
    2262           0 :                 if ( nNewFlags )
    2263           0 :                     pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
    2264             :                 else
    2265           0 :                     pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
    2266             : 
    2267           0 :                 if (bSamePool)
    2268           0 :                     pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
    2269             :                 else
    2270           0 :                     pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
    2271           0 :                 delete pTmpPattern;
    2272             :             }
    2273             :             else
    2274             :             {
    2275          10 :                 if (bSamePool)
    2276          10 :                     pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
    2277             :                 else
    2278           0 :                     pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
    2279             :             }
    2280             : 
    2281             :             rAttrArray.SetPatternArea(nDestStart,
    2282        3103 :                             Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
    2283             :         }
    2284             : 
    2285             :         // when pasting from clipboard and skipping filtered rows, the adjusted
    2286             :         // end position can be negative
    2287        3109 :         nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
    2288             :     }
    2289        3099 : }
    2290             : 
    2291             : 
    2292             : // leave flags
    2293             : // summarized with CopyArea
    2294             : 
    2295           5 : void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
    2296             : {
    2297           5 :     nStartRow -= nDy;  // Source
    2298           5 :     nEndRow -= nDy;
    2299             : 
    2300           5 :     SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
    2301           5 :     SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
    2302             : 
    2303           5 :     if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
    2304             :     {
    2305           5 :         CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
    2306          10 :         return;
    2307             :     }
    2308             : 
    2309           0 :     ScDocumentPool* pSourceDocPool = pDocument->GetPool();
    2310           0 :     ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
    2311           0 :     bool bSamePool = (pSourceDocPool==pDestDocPool);
    2312             : 
    2313           0 :     for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
    2314             :     {
    2315           0 :         if (pData[i].nRow >= nStartRow)
    2316             :         {
    2317           0 :             const ScPatternAttr* pOldPattern = pData[i].pPattern;
    2318             :             const ScPatternAttr* pNewPattern;
    2319             : 
    2320           0 :             if (bSamePool)
    2321           0 :                 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
    2322             :             else
    2323           0 :                 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
    2324             : 
    2325             :             rAttrArray.SetPatternAreaSafe(nDestStart,
    2326           0 :                             Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, false);
    2327             :         }
    2328             : 
    2329             :         // when pasting from clipboard and skipping filtered rows, the adjusted
    2330             :         // end position can be negative
    2331           0 :         nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
    2332             :     }
    2333             : }
    2334             : 
    2335             : 
    2336           0 : SCsROW ScAttrArray::SearchStyle(
    2337             :     SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
    2338             :     const ScMarkArray* pMarkArray) const
    2339             : {
    2340           0 :     bool bFound = false;
    2341             : 
    2342           0 :     if (pMarkArray)
    2343             :     {
    2344           0 :         nRow = pMarkArray->GetNextMarked( nRow, bUp );
    2345           0 :         if (!VALIDROW(nRow))
    2346           0 :             return nRow;
    2347             :     }
    2348             : 
    2349             :     SCSIZE nIndex;
    2350           0 :     Search(nRow, nIndex);
    2351           0 :     const ScPatternAttr* pPattern = pData[nIndex].pPattern;
    2352             : 
    2353           0 :     while (nIndex < nCount && !bFound)
    2354             :     {
    2355           0 :         if (pPattern->GetStyleSheet() == pSearchStyle)
    2356             :         {
    2357           0 :             if (pMarkArray)
    2358             :             {
    2359           0 :                 nRow = pMarkArray->GetNextMarked( nRow, bUp );
    2360           0 :                 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
    2361           0 :                 if (nRow >= nStart && nRow <= pData[nIndex].nRow)
    2362           0 :                     bFound = true;
    2363             :             }
    2364             :             else
    2365           0 :                 bFound = true;
    2366             :         }
    2367             : 
    2368           0 :         if (!bFound)
    2369             :         {
    2370           0 :             if (bUp)
    2371             :             {
    2372           0 :                 if (nIndex==0)
    2373             :                 {
    2374           0 :                     nIndex = nCount;
    2375           0 :                     nRow = -1;
    2376             :                 }
    2377             :                 else
    2378             :                 {
    2379           0 :                     --nIndex;
    2380           0 :                     nRow = pData[nIndex].nRow;
    2381           0 :                     pPattern = pData[nIndex].pPattern;
    2382             :                 }
    2383             :             }
    2384             :             else
    2385             :             {
    2386           0 :                 nRow = pData[nIndex].nRow+1;
    2387           0 :                 ++nIndex;
    2388           0 :                 if (nIndex<nCount)
    2389           0 :                     pPattern = pData[nIndex].pPattern;
    2390             :             }
    2391             :         }
    2392             :     }
    2393             : 
    2394             :     OSL_ENSURE( bFound || !ValidRow(nRow), "Internal failure in in ScAttrArray::SearchStyle" );
    2395             : 
    2396           0 :     return nRow;
    2397             : }
    2398             : 
    2399             : 
    2400           0 : bool ScAttrArray::SearchStyleRange(
    2401             :     SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
    2402             :     const ScMarkArray* pMarkArray) const
    2403             : {
    2404           0 :     SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
    2405           0 :     if (VALIDROW(nStartRow))
    2406             :     {
    2407             :         SCSIZE nIndex;
    2408           0 :         Search(nStartRow,nIndex);
    2409             : 
    2410           0 :         rRow = nStartRow;
    2411           0 :         if (bUp)
    2412             :         {
    2413           0 :             if (nIndex>0)
    2414           0 :                 rEndRow = pData[nIndex-1].nRow + 1;
    2415             :             else
    2416           0 :                 rEndRow = 0;
    2417           0 :             if (pMarkArray)
    2418             :             {
    2419           0 :                 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
    2420           0 :                 if (nMarkEnd>rEndRow)
    2421           0 :                     rEndRow = nMarkEnd;
    2422             :             }
    2423             :         }
    2424             :         else
    2425             :         {
    2426           0 :             rEndRow = pData[nIndex].nRow;
    2427           0 :             if (pMarkArray)
    2428             :             {
    2429           0 :                 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
    2430           0 :                 if (nMarkEnd<rEndRow)
    2431           0 :                     rEndRow = nMarkEnd;
    2432             :             }
    2433             :         }
    2434             : 
    2435           0 :         return true;
    2436             :     }
    2437             :     else
    2438           0 :         return false;
    2439             : }
    2440             : 
    2441             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10