blob: 2ef1f957796c30d36becbb77dc740372ef598790 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
// INCLUDE ---------------------------------------------------------------
#include <tools/debug.hxx>
#include "markarr.hxx"
#include "global.hxx"
#include "address.hxx"
// STATIC DATA -----------------------------------------------------------
//------------------------------------------------------------------------
ScMarkArray::ScMarkArray() :
nCount( 0 ),
nLimit( 0 ),
pData( NULL )
{
// special case "no marks" with pData = NULL
}
//------------------------------------------------------------------------
ScMarkArray::~ScMarkArray()
{
delete[] pData;
}
//------------------------------------------------------------------------
void ScMarkArray::Reset( sal_Bool bMarked )
{
// always create pData here
// (or have separate method to ensure pData)
delete[] pData;
nCount = nLimit = 1;
pData = new ScMarkEntry[1];
pData[0].nRow = MAXROW;
pData[0].bMarked = bMarked;
}
//------------------------------------------------------------------------
sal_Bool ScMarkArray::Search( SCROW nRow, SCSIZE& nIndex ) const
{
long nLo = 0;
long nHi = static_cast<long>(nCount) - 1;
long nStartRow = 0;
long nEndRow = 0;
long i = 0;
sal_Bool bFound = (nCount == 1);
if (pData)
{
while ( !bFound && nLo <= nHi )
{
i = (nLo + nHi) / 2;
if (i > 0)
nStartRow = (long) pData[i - 1].nRow;
else
nStartRow = -1;
nEndRow = (long) pData[i].nRow;
if (nEndRow < (long) nRow)
nLo = ++i;
else
if (nStartRow >= (long) nRow)
nHi = --i;
else
bFound = sal_True;
}
}
else
bFound = sal_False;
if (bFound)
nIndex=(SCSIZE)i;
else
nIndex=0;
return bFound;
}
sal_Bool ScMarkArray::GetMark( SCROW nRow ) const
{
SCSIZE i;
if (Search( nRow, i ))
return pData[i].bMarked;
else
return sal_False;
}
//------------------------------------------------------------------------
void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, sal_Bool bMarked )
{
if (ValidRow(nStartRow) && ValidRow(nEndRow))
{
if ((nStartRow == 0) && (nEndRow == MAXROW))
{
Reset(bMarked);
}
else
{
if (!pData)
Reset(sal_False); // create pData for further processing - could use special case handling!
SCSIZE nNeeded = nCount + 2;
if ( nLimit < nNeeded )
{
nLimit += SC_MARKARRAY_DELTA;
if ( nLimit < nNeeded )
nLimit = nNeeded;
ScMarkEntry* pNewData = new ScMarkEntry[nLimit];
memcpy( pNewData, pData, nCount*sizeof(ScMarkEntry) );
delete[] pData;
pData = pNewData;
}
SCSIZE ni; // number of entries in beginning
SCSIZE nInsert; // insert position (MAXROW+1 := no insert)
sal_Bool bCombined = sal_False;
sal_Bool bSplit = sal_False;
if ( nStartRow > 0 )
{
// skip beginning
SCSIZE nIndex;
Search( nStartRow, nIndex );
ni = nIndex;
nInsert = MAXROWCOUNT;
if ( pData[ni].bMarked != bMarked )
{
if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
{ // may be a split or a simple insert or just a shrink,
// row adjustment is done further down
if ( pData[ni].nRow > nEndRow )
bSplit = sal_True;
ni++;
nInsert = ni;
}
else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
nInsert = ni;
}
if ( ni > 0 && pData[ni-1].bMarked == bMarked )
{ // combine
pData[ni-1].nRow = nEndRow;
nInsert = MAXROWCOUNT;
bCombined = sal_True;
}
}
else
{
nInsert = 0;
ni = 0;
}
SCSIZE nj = ni; // stop position of range to replace
while ( nj < nCount && pData[nj].nRow <= nEndRow )
nj++;
if ( !bSplit )
{
if ( nj < nCount && pData[nj].bMarked == bMarked )
{ // combine
if ( ni > 0 )
{
if ( pData[ni-1].bMarked == bMarked )
{ // adjacent entries
pData[ni-1].nRow = pData[nj].nRow;
nj++;
}
else if ( ni == nInsert )
pData[ni-1].nRow = nStartRow - 1; // shrink
}
nInsert = MAXROWCOUNT;
bCombined = sal_True;
}
else if ( ni > 0 && ni == nInsert )
pData[ni-1].nRow = nStartRow - 1; // shrink
}
if ( ni < nj )
{ // remove middle entries
if ( !bCombined )
{ // replace one entry
pData[ni].nRow = nEndRow;
pData[ni].bMarked = bMarked;
ni++;
nInsert = MAXROWCOUNT;
}
if ( ni < nj )
{ // remove entries
memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScMarkEntry) );
nCount -= nj - ni;
}
}
if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
{ // insert or append new entry
if ( nInsert <= nCount )
{
if ( !bSplit )
memmove( pData + nInsert + 1, pData + nInsert,
(nCount - nInsert) * sizeof(ScMarkEntry) );
else
{
memmove( pData + nInsert + 2, pData + nInsert,
(nCount - nInsert) * sizeof(ScMarkEntry) );
pData[nInsert+1] = pData[nInsert-1];
nCount++;
}
}
if ( nInsert )
pData[nInsert-1].nRow = nStartRow - 1;
pData[nInsert].nRow = nEndRow;
pData[nInsert].bMarked = bMarked;
nCount++;
}
}
}
// InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
}
//UNUSED2009-05 void ScMarkArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
//UNUSED2009-05 {
//UNUSED2009-05 SetMarkArea(nStartRow, nEndRow, sal_False);
//UNUSED2009-05 }
sal_Bool ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const
{
SCSIZE nStartIndex;
SCSIZE nEndIndex;
if (Search( nStartRow, nStartIndex ))
if (pData[nStartIndex].bMarked)
if (Search( nEndRow, nEndIndex ))
if (nEndIndex==nStartIndex)
return sal_True;
return sal_False;
}
sal_Bool ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const
{
sal_Bool bRet = sal_False;
if ( nCount == 1 )
{
if ( pData[0].bMarked )
{
rStartRow = 0;
rEndRow = MAXROW;
bRet = sal_True;
}
}
else if ( nCount == 2 )
{
if ( pData[0].bMarked )
{
rStartRow = 0;
rEndRow = pData[0].nRow;
}
else
{
rStartRow = pData[0].nRow + 1;
rEndRow = MAXROW;
}
bRet = sal_True;
}
else if ( nCount == 3 )
{
if ( pData[1].bMarked )
{
rStartRow = pData[0].nRow + 1;
rEndRow = pData[1].nRow;
bRet = sal_True;
}
}
return bRet;
}
void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const
{
delete[] rDestMarkArray.pData;
if (pData)
{
rDestMarkArray.pData = new ScMarkEntry[nCount];
memmove( rDestMarkArray.pData, pData, nCount * sizeof(ScMarkEntry) );
}
else
rDestMarkArray.pData = NULL;
rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount;
}
SCsROW ScMarkArray::GetNextMarked( SCsROW nRow, sal_Bool bUp ) const
{
if (!pData)
const_cast<ScMarkArray*>(this)->Reset(sal_False); // create pData for further processing
SCsROW nRet = nRow;
if (VALIDROW(nRow))
{
SCSIZE nIndex;
Search(nRow, nIndex);
if (!pData[nIndex].bMarked)
{
if (bUp)
{
if (nIndex>0)
nRet = pData[nIndex-1].nRow;
else
nRet = -1;
}
else
nRet = pData[nIndex].nRow + 1;
}
}
return nRet;
}
SCROW ScMarkArray::GetMarkEnd( SCROW nRow, sal_Bool bUp ) const
{
if (!pData)
const_cast<ScMarkArray*>(this)->Reset(sal_False); // create pData for further processing
SCROW nRet;
SCSIZE nIndex;
Search(nRow, nIndex);
DBG_ASSERT( pData[nIndex].bMarked, "GetMarkEnd ohne bMarked" );
if (bUp)
{
if (nIndex>0)
nRet = pData[nIndex-1].nRow + 1;
else
nRet = 0;
}
else
nRet = pData[nIndex].nRow;
return nRet;
}
//
// -------------- Iterator ----------------------------------------------
//
ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
pArray( pNewArray ),
nPos( 0 )
{
}
ScMarkArrayIter::~ScMarkArrayIter()
{
}
sal_Bool ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom )
{
if ( nPos >= pArray->nCount )
return sal_False;
while (!pArray->pData[nPos].bMarked)
{
++nPos;
if ( nPos >= pArray->nCount )
return sal_False;
}
rBottom = pArray->pData[nPos].nRow;
if (nPos==0)
rTop = 0;
else
rTop = pArray->pData[nPos-1].nRow + 1;
++nPos;
return sal_True;
}