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

Generated by: LCOV version 1.10