LCOV - code coverage report
Current view: top level - sc/source/core/data - attarray.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 854 1227 69.6 %
Date: 2015-06-13 12:38:46 Functions: 47 58 81.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11