LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/data - attarray.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 668 1198 55.8 %
Date: 2012-12-17 Functions: 36 53 67.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10