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

Generated by: LCOV version 1.10