blob: c1577d6a154fa6beae16fe169f08a6a5b9a39426 [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 <tools/debug.hxx>
#include <string.h>
#include <memory>
#include <unotools/collatorwrapper.hxx>
#include <unotools/transliterationwrapper.hxx>
#include "token.hxx"
#include "tokenarray.hxx"
#include "rangenam.hxx"
#include "global.hxx"
#include "compiler.hxx"
#include "rangeutl.hxx"
#include "rechead.hxx"
#include "refupdat.hxx"
#include "document.hxx"
using namespace formula;
//========================================================================
// ScRangeData
//========================================================================
// Interner ctor fuer das Suchen nach einem Index
ScRangeData::ScRangeData( sal_uInt16 n )
: pCode( NULL ), nIndex( n ), bModified( sal_False ), mnMaxRow(-1), mnMaxCol(-1), aRangeNameScope( MAXTABCOUNT )
{}
ScRangeData::ScRangeData( ScDocument* pDok,
const String& rName,
const String& rSymbol,
const ScAddress& rAddress,
RangeType nType,
const FormulaGrammar::Grammar eGrammar ) :
aName ( rName ),
aUpperName ( ScGlobal::pCharClass->upper( rName ) ),
pCode ( NULL ),
aPos ( rAddress ),
eType ( nType ),
pDoc ( pDok ),
nIndex ( 0 ),
bModified ( sal_False ),
mnMaxRow (-1),
mnMaxCol (-1),
aRangeNameScope( MAXTABCOUNT )
{
if (rSymbol.Len() > 0)
{
ScCompiler aComp( pDoc, aPos );
aComp.SetGrammar(eGrammar);
pCode = aComp.CompileString( rSymbol );
if( !pCode->GetCodeError() )
{
pCode->Reset();
FormulaToken* p = pCode->GetNextReference();
if( p )// genau eine Referenz als erstes
{
if( p->GetType() == svSingleRef )
eType = eType | RT_ABSPOS;
else
eType = eType | RT_ABSAREA;
}
// ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
// Dies ist fuer die manuelle Eingabe
aComp.CompileTokenArray();
pCode->DelRPN();
}
}
else
{
// #i63513#/#i65690# don't leave pCode as NULL.
// Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too,
// to ensure same behavior if unnecessary copying is left out.
pCode = new ScTokenArray();
}
}
ScRangeData::ScRangeData( ScDocument* pDok,
const String& rName,
const ScTokenArray& rArr,
const ScAddress& rAddress,
RangeType nType ) :
aName ( rName ),
aUpperName ( ScGlobal::pCharClass->upper( rName ) ),
pCode ( new ScTokenArray( rArr ) ),
aPos ( rAddress ),
eType ( nType ),
pDoc ( pDok ),
nIndex ( 0 ),
bModified ( sal_False ),
mnMaxRow (-1),
mnMaxCol (-1),
aRangeNameScope( MAXTABCOUNT )
{
if( !pCode->GetCodeError() )
{
pCode->Reset();
FormulaToken* p = pCode->GetNextReference();
if( p )// genau eine Referenz als erstes
{
if( p->GetType() == svSingleRef )
eType = eType | RT_ABSPOS;
else
eType = eType | RT_ABSAREA;
}
// Die Importfilter haben diesen Test nicht,
// da die benannten Bereiche z.T. noch unvollstaendig sind.
// if( !pCode->GetCodeLen() )
// {
// // ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
// ScCompiler aComp( pDok, aPos, *pCode );
// aComp.CompileTokenArray();
// pCode->DelRPN();
// }
}
}
ScRangeData::ScRangeData( ScDocument* pDok,
const String& rName,
const ScAddress& rTarget ) :
aName ( rName ),
aUpperName ( ScGlobal::pCharClass->upper( rName ) ),
pCode ( new ScTokenArray() ),
aPos ( rTarget ),
eType ( RT_NAME ),
pDoc ( pDok ),
nIndex ( 0 ),
bModified ( sal_False ),
mnMaxRow (-1),
mnMaxCol (-1),
aRangeNameScope( MAXTABCOUNT )
{
ScSingleRefData aRefData;
aRefData.InitAddress( rTarget );
aRefData.SetFlag3D( sal_True );
pCode->AddSingleReference( aRefData );
ScCompiler aComp( pDoc, aPos, *pCode );
aComp.SetGrammar(pDoc->GetGrammar());
aComp.CompileTokenArray();
if ( !pCode->GetCodeError() )
eType |= RT_ABSPOS;
}
ScRangeData::ScRangeData(const ScRangeData& rScRangeData) :
ScDataObject(),
aName (rScRangeData.aName),
aUpperName (rScRangeData.aUpperName),
pCode (rScRangeData.pCode ? rScRangeData.pCode->Clone() : new ScTokenArray()), // echte Kopie erzeugen (nicht copy-ctor)
aPos (rScRangeData.aPos),
eType (rScRangeData.eType),
pDoc (rScRangeData.pDoc),
nIndex (rScRangeData.nIndex),
bModified (rScRangeData.bModified),
mnMaxRow (rScRangeData.mnMaxRow),
mnMaxCol (rScRangeData.mnMaxCol),
aRangeNameScope (rScRangeData.aRangeNameScope)
{}
ScRangeData::~ScRangeData()
{
delete pCode;
}
ScDataObject* ScRangeData::Clone() const
{
return new ScRangeData(*this);
}
void ScRangeData::GuessPosition()
{
// setzt eine Position, mit der alle relative Referenzen bei CalcAbsIfRel
// ohne Fehler verabsolutiert werden koennen
DBG_ASSERT(aPos == ScAddress(), "die Position geht jetzt verloren");
SCsCOL nMinCol = 0;
SCsROW nMinRow = 0;
SCsTAB nMinTab = 0;
ScToken* t;
pCode->Reset();
while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
{
ScSingleRefData& rRef1 = t->GetSingleRef();
if ( rRef1.IsColRel() && rRef1.nRelCol < nMinCol )
nMinCol = rRef1.nRelCol;
if ( rRef1.IsRowRel() && rRef1.nRelRow < nMinRow )
nMinRow = rRef1.nRelRow;
if ( rRef1.IsTabRel() && rRef1.nRelTab < nMinTab )
nMinTab = rRef1.nRelTab;
if ( t->GetType() == svDoubleRef )
{
ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
if ( rRef2.IsColRel() && rRef2.nRelCol < nMinCol )
nMinCol = rRef2.nRelCol;
if ( rRef2.IsRowRel() && rRef2.nRelRow < nMinRow )
nMinRow = rRef2.nRelRow;
if ( rRef2.IsTabRel() && rRef2.nRelTab < nMinTab )
nMinTab = rRef2.nRelTab;
}
}
aPos = ScAddress( (SCCOL)(-nMinCol), (SCROW)(-nMinRow), (SCTAB)(-nMinTab) );
//! Test
// DBG_ERROR(String("Pos ")+String((SCCOL)(-nMinCol))+String("/")+
// String((SCROW)(-nMinRow))+String("/")+String((SCTAB)(-nMinTab)));
}
void ScRangeData::GetSymbol( String& rSymbol, const FormulaGrammar::Grammar eGrammar ) const
{
ScCompiler aComp(pDoc, aPos, *pCode);
aComp.SetGrammar(eGrammar);
aComp.CreateStringFromTokenArray( rSymbol );
}
void ScRangeData::UpdateSymbol( rtl::OUStringBuffer& rBuffer, const ScAddress& rPos,
const FormulaGrammar::Grammar eGrammar )
{
::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
ScCompiler aComp( pDoc, rPos, *pTemp.get());
aComp.SetGrammar(eGrammar);
aComp.MoveRelWrap(GetMaxCol(), GetMaxRow());
aComp.CreateStringFromTokenArray( rBuffer );
}
void ScRangeData::UpdateReference( UpdateRefMode eUpdateRefMode,
const ScRange& r,
SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
{
sal_Bool bChanged = sal_False;
pCode->Reset();
if( pCode->GetNextReference() )
{
sal_Bool bSharedFormula = ((eType & RT_SHARED) == RT_SHARED);
ScCompiler aComp( pDoc, aPos, *pCode );
aComp.SetGrammar(pDoc->GetGrammar());
const sal_Bool bRelRef = aComp.UpdateNameReference( eUpdateRefMode, r,
nDx, nDy, nDz,
bChanged, bSharedFormula);
if (bSharedFormula)
{
if (bRelRef)
eType = eType | RT_SHAREDMOD;
else
eType = eType & ~RT_SHAREDMOD;
}
}
bModified = bChanged;
}
void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
{
sal_Bool bChanged = sal_False;
ScToken* t;
pCode->Reset();
while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
{
if( t->GetType() != svIndex )
{
SingleDoubleRefModifier aMod( *t );
ScComplexRefData& rRef = aMod.Ref();
if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
(!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
( t->GetType() == svSingleRef ||
(!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
(!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
{
if ( ScRefUpdate::UpdateTranspose( pDoc, rSource, rDest, rRef ) != UR_NOTHING )
bChanged = sal_True;
}
}
}
bModified = bChanged;
}
void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
{
sal_Bool bChanged = sal_False;
ScToken* t;
pCode->Reset();
while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
{
if( t->GetType() != svIndex )
{
SingleDoubleRefModifier aMod( *t );
ScComplexRefData& rRef = aMod.Ref();
if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
(!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
( t->GetType() == svSingleRef ||
(!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
(!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
{
if ( ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, rRef ) != UR_NOTHING )
bChanged = sal_True;
}
}
}
bModified = bChanged; // muss direkt hinterher ausgewertet werden
}
sal_Bool ScRangeData::operator== (const ScRangeData& rData) const // fuer Undo
{
if ( nIndex != rData.nIndex ||
aName != rData.aName ||
aPos != rData.aPos ||
eType != rData.eType || aRangeNameScope != rData.aRangeNameScope ) return sal_False;
sal_uInt16 nLen = pCode->GetLen();
if ( nLen != rData.pCode->GetLen() ) return sal_False;
FormulaToken** ppThis = pCode->GetArray();
FormulaToken** ppOther = rData.pCode->GetArray();
for ( sal_uInt16 i=0; i<nLen; i++ )
if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
return sal_False;
return sal_True;
}
//UNUSED2009-05 sal_Bool ScRangeData::IsRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const
//UNUSED2009-05 {
//UNUSED2009-05 sal_Bool bRet = sal_False;
//UNUSED2009-05 ScRange aRange;
//UNUSED2009-05 if ( IsReference(aRange) )
//UNUSED2009-05 {
//UNUSED2009-05 if ( bStartOnly )
//UNUSED2009-05 bRet = ( rPos == aRange.aStart );
//UNUSED2009-05 else
//UNUSED2009-05 bRet = ( aRange.In( rPos ) );
//UNUSED2009-05 }
//UNUSED2009-05 return bRet;
//UNUSED2009-05 }
sal_Bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
{
sal_Bool bRet = sal_False;
ScRange aRange;
if ( IsReference(aRange) )
bRet = ( rBlock == aRange );
return bRet;
}
sal_Bool ScRangeData::IsReference( ScRange& rRange ) const
{
if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS )) && pCode )
return pCode->IsReference( rRange );
return sal_False;
}
sal_Bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const
{
if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
{
::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
ScCompiler aComp( pDoc, rPos, *pTemp);
aComp.SetGrammar(pDoc->GetGrammar());
aComp.MoveRelWrap(MAXCOL, MAXROW);
return pTemp->IsReference( rRange );
}
return sal_False;
}
sal_Bool ScRangeData::IsValidReference( ScRange& rRange ) const
{
if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
return pCode->IsValidReference( rRange );
return sal_False;
}
/* modification to update named range scope */
void ScRangeData::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable)
{
pCode->Reset();
if( pCode->GetNextReference() )
{
ScRangeData* pRangeData = NULL; // must not be dereferenced
sal_Bool bChanged;
ScCompiler aComp( pDoc, aPos, *pCode);
aComp.SetGrammar(pDoc->GetGrammar());
switch (nFlag)
{
case 1: // einfache InsertTab (doc.cxx)
case 4:
pRangeData = aComp.UpdateInsertTab(nOldTable, true ); // und CopyTab (doc2.cxx)
if ( (aRangeNameScope != MAXTABCOUNT) && ( aRangeNameScope >= nOldTable) && ( aRangeNameScope != MAXTAB ) )
aRangeNameScope ++;
break;
case 2: // einfaches delete (doc.cxx)
pRangeData = aComp.UpdateDeleteTab(nOldTable, false, true, bChanged);
if ( aRangeNameScope != MAXTABCOUNT && aRangeNameScope > nOldTable )
aRangeNameScope --;
break;
case 3: // move (doc2.cxx)
{
pRangeData = aComp.UpdateMoveTab(nOldTable, nNewTable, true );
if ( aRangeNameScope != MAXTABCOUNT )
{
if ( aRangeNameScope == nOldTable )
aRangeNameScope = nNewTable;
else if ( (aRangeNameScope > nOldTable) && (aRangeNameScope <= nNewTable) )
aRangeNameScope--;
else if ( (aRangeNameScope >= nNewTable) && (aRangeNameScope < nOldTable) )
aRangeNameScope++;
}
}
break;
case 5:
{
//when copying a sheet, this will be invoked to update the new name range's address in the new sheet
//only need to update the address if the address's tab same as the range scope. because if they are different, the address's tab have been updated in ScRangeName::UpdateTabRef()
//for example, in sheet5(scope is sheet5), there are two name range, one address is sheet5, the other is sheet4, if copy sheet5 to sheet1
//only need to change the first one's address to sheet1
pRangeData = aComp.UpdateMoveTab(nOldTable, nNewTable, true , true);
aRangeNameScope = nNewTable;
}
break;
default:
{
DBG_ERROR("ScRangeName::UpdateTabRef: Unknown Flag");
}
break;
}
if (eType&RT_SHARED)
{
if (pRangeData)
eType = eType | RT_SHAREDMOD;
else
eType = eType & ~RT_SHAREDMOD;
}
}
}
void ScRangeData::MakeValidName( String& rName ) // static
{
//ScCompiler::InitSymbolsNative();
// strip leading invalid characters
xub_StrLen nPos = 0;
xub_StrLen nLen = rName.Len();
while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
++nPos;
if ( nPos>0 )
rName.Erase(0,nPos);
// if the first character is an invalid start character, precede with '_'
if ( rName.Len() && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) )
rName.Insert('_',0);
// replace invalid with '_'
nLen = rName.Len();
for (nPos=0; nPos<nLen; nPos++)
{
if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
rName.SetChar( nPos, '_' );
}
// Ensure that the proposed name is not a reference under any convention,
// same as in IsNameValid()
ScAddress aAddr;
ScRange aRange;
for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
{
ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
// Don't check Parse on VALID, any partial only VALID may result in
// #REF! during compile later!
while (aRange.Parse( rName, NULL, details) || aAddr.Parse( rName, NULL, details))
{
//! Range Parse is partially valid also with invalid sheet name,
//! Address Parse dito, during compile name would generate a #REF!
if ( rName.SearchAndReplace( '.', '_' ) == STRING_NOTFOUND )
rName.Insert('_',0);
}
}
}
sal_Bool ScRangeData::IsNameValid( const String& rName, ScDocument* pDoc )
{
/* XXX If changed, sc/source/filter/ftools/ftools.cxx
* ScfTools::ConvertToScDefinedName needs to be changed too. */
xub_StrLen nPos = 0;
xub_StrLen nLen = rName.Len();
if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_CHAR_NAME ) )
return sal_False;
while ( nPos < nLen )
{
if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) )
return sal_False;
}
ScAddress aAddr;
ScRange aRange;
for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
{
ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
// Don't check Parse on VALID, any partial only VALID may result in
// #REF! during compile later!
if (aRange.Parse( rName, pDoc, details) || aAddr.Parse( rName, pDoc, details))
return sal_False;
}
return sal_True;
}
void ScRangeData::SetMaxRow(SCROW nRow)
{
mnMaxRow = nRow;
}
SCROW ScRangeData::GetMaxRow() const
{
return mnMaxRow >= 0 ? mnMaxRow : MAXROW;
}
void ScRangeData::SetMaxCol(SCCOL nCol)
{
mnMaxCol = nCol;
}
SCCOL ScRangeData::GetMaxCol() const
{
return mnMaxCol >= 0 ? mnMaxCol : MAXCOL;
}
/* MAXTABCOUNT - Global, 0 - sheet1, 1 - sheet2, ... */
/* MAXTABCOUNT -- Global */
/* return value: FALSE -- set fail */
/* TRUE -- set successfully */
bool ScRangeData::SetRangeScope( SCTAB Scope )
{
if ( Scope <= MAXTABCOUNT && Scope >=0 )
{
aRangeNameScope = Scope;
return true;
}
return false;
}
String ScRangeData::GetScopeSheetName() const
{
if ( aRangeNameScope != MAXTABCOUNT )
{
String aTableName;
pDoc->GetName( aRangeNameScope, aTableName );
return aTableName;
}
return EMPTY_STRING;
}
/* end add */
sal_uInt16 ScRangeData::GetErrCode()
{
return pCode ? pCode->GetCodeError() : 0;
}
sal_Bool ScRangeData::HasReferences() const
{
pCode->Reset();
return sal_Bool( pCode->GetNextReference() != NULL );
}
// bei TransferTab von einem in ein anderes Dokument anpassen,
// um Referenzen auf die eigene Tabelle mitzubekommen
void ScRangeData::TransferTabRef( SCTAB nOldTab, SCTAB nNewTab )
{
long nTabDiff = (long)nNewTab - nOldTab;
long nPosDiff = (long)nNewTab - aPos.Tab();
aPos.SetTab( nNewTab );
ScToken* t;
pCode->Reset();
while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
{
ScSingleRefData& rRef1 = t->GetSingleRef();
if ( rRef1.IsTabRel() )
rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nPosDiff );
else
rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nTabDiff );
if ( t->GetType() == svDoubleRef )
{
ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
if ( rRef2.IsTabRel() )
rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nPosDiff );
else
rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nTabDiff );
}
}
}
void ScRangeData::ReplaceRangeNamesInUse( const IndexMap& rMap )
{
bool bCompile = false;
for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
{
if ( p->GetOpCode() == ocName )
{
const sal_uInt16 nOldIndex = p->GetIndex();
IndexMap::const_iterator itr = rMap.find(nOldIndex);
const sal_uInt16 nNewIndex = itr == rMap.end() ? nOldIndex : itr->second;
if ( nOldIndex != nNewIndex )
{
p->SetIndex( nNewIndex );
bCompile = true;
}
}
}
if ( bCompile )
{
ScCompiler aComp( pDoc, aPos, *pCode);
aComp.SetGrammar(pDoc->GetGrammar());
aComp.CompileTokenArray();
}
}
void ScRangeData::ValidateTabRefs()
{
// try to make sure all relative references and the reference position
// are within existing tables, so they can be represented as text
// (if the range of used tables is more than the existing tables,
// the result may still contain invalid tables, because the relative
// references aren't changed so formulas stay the same)
// find range of used tables
SCTAB nMinTab = aPos.Tab();
SCTAB nMaxTab = nMinTab;
ScToken* t;
pCode->Reset();
while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
{
ScSingleRefData& rRef1 = t->GetSingleRef();
if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
{
if ( rRef1.nTab < nMinTab )
nMinTab = rRef1.nTab;
if ( rRef1.nTab > nMaxTab )
nMaxTab = rRef1.nTab;
}
if ( t->GetType() == svDoubleRef )
{
ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
{
if ( rRef2.nTab < nMinTab )
nMinTab = rRef2.nTab;
if ( rRef2.nTab > nMaxTab )
nMaxTab = rRef2.nTab;
}
}
}
SCTAB nTabCount = pDoc->GetTableCount();
if ( nMaxTab >= nTabCount && nMinTab > 0 )
{
// move position and relative tab refs
// The formulas that use the name are not changed by this
SCTAB nMove = nMinTab;
aPos.SetTab( aPos.Tab() - nMove );
pCode->Reset();
while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
{
ScSingleRefData& rRef1 = t->GetSingleRef();
if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab - nMove );
if ( t->GetType() == svDoubleRef )
{
ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab - nMove );
}
}
}
}
extern "C" int
#ifdef WNT
__cdecl
#endif
ScRangeData_QsortNameCompare( const void* p1, const void* p2 )
{
return (int) ScGlobal::GetCollator()->compareString(
(*(const ScRangeData**)p1)->GetName(),
(*(const ScRangeData**)p2)->GetName() );
}
//========================================================================
// ScRangeName
//========================================================================
ScRangeName::ScRangeName(const ScRangeName& rScRangeName, ScDocument* pDocument) :
ScSortedCollection ( rScRangeName ),
pDoc ( pDocument ),
nSharedMaxIndex (rScRangeName.nSharedMaxIndex)
{
for (sal_uInt16 i = 0; i < nCount; i++)
{
((ScRangeData*)At(i))->SetDocument(pDocument);
((ScRangeData*)At(i))->SetIndex(((ScRangeData*)rScRangeName.At(i))->GetIndex());
}
}
short ScRangeName::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
{
sal_uInt16 i1 = ((ScRangeData*)pKey1)->GetIndex();
sal_uInt16 i2 = ((ScRangeData*)pKey2)->GetIndex();
return (short) i1 - (short) i2;
}
/* added for scope support */
bool ScRangeName::HasRangeinSheetScope(SCTAB Scope)
{
for (sal_uInt16 i = 0; i < nCount; i++)
if (((*this)[i])->GetRangeScope() == Scope)
return true;
return false;
}
/* if Scope is global, no range will be removed */
/* if no range is removed, return value is false */
bool ScRangeName::RemoveRangeinScope(SCTAB Scope)
{
bool bRemoved = false;
if ( Scope == MAXTABCOUNT )
return bRemoved;
sal_uInt16 i = 0;
while (i < nCount)
{
if (((*this)[i])->GetRangeScope() == Scope)
{
Free( (*this)[i] );
bRemoved = true;
}
else
i++;
}
return bRemoved;
}
/* it's designed for "Copy Sheet" action. So no name conflict check when copy range to new scope */
/* if the old scope or the new scope is global, no range will be copied */
/* if no range is copied, the return value is false */
bool ScRangeName::CopyRangeinScope(SCTAB oldScope, SCTAB newScope)
{
bool bCopied = false;
if ( (oldScope == MAXTABCOUNT)||(newScope ==MAXTABCOUNT) )
return bCopied;
sal_uInt16 originalCount = nCount;
for ( sal_uInt16 i = 0; i < originalCount; i++)
if ( ((*this)[i])->GetRangeScope() == oldScope)
{
ScRangeData * aCopiedRange = (ScRangeData *)(*this)[i]->Clone();
aCopiedRange->UpdateTabRef(oldScope, 5 , newScope);
aCopiedRange->SetIndex(GetEntryIndex());
Insert( aCopiedRange );
bCopied = true;
}
return bCopied;
}
/* end add */
bool ScRangeName::SearchNameUpper( const String& rUpperName, sal_uInt16& rIndex, SCTAB Scope ) const
{
// SearchNameUpper must be called with an upper-case search string
sal_uInt16 i = 0;
while (i < nCount)
{
if ( (((*this)[i])->GetUpperName() == rUpperName)
&& (((*this)[i])->GetRangeScope() == Scope ))
{
rIndex = i;
return true;
}
i++;
}
return false;
}
bool ScRangeName::SearchName( const String& rName, sal_uInt16& rIndex, SCTAB Scope ) const
{
if ( nCount > 0 )
return SearchNameUpper( ScGlobal::pCharClass->upper( rName ), rIndex, Scope );
else
return false;
}
void ScRangeName::UpdateReference( UpdateRefMode eUpdateRefMode,
const ScRange& rRange,
SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
{
for (sal_uInt16 i=0; i<nCount; i++)
((ScRangeData*)pItems[i])->UpdateReference(eUpdateRefMode, rRange,
nDx, nDy, nDz);
}
void ScRangeName::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
{
for (sal_uInt16 i=0; i<nCount; i++)
((ScRangeData*)pItems[i])->UpdateTranspose( rSource, rDest );
}
void ScRangeName::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
{
for (sal_uInt16 i=0; i<nCount; i++)
((ScRangeData*)pItems[i])->UpdateGrow( rArea, nGrowX, nGrowY );
}
sal_Bool ScRangeName::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
{
return *(ScRangeData*)pKey1 == *(ScRangeData*)pKey2;
}
sal_Bool ScRangeName::Insert(ScDataObject* pScDataObject)
{
if (!((ScRangeData*)pScDataObject)->GetIndex()) // schon gesetzt?
{
((ScRangeData*)pScDataObject)->SetIndex( GetEntryIndex() );
}
return ScSortedCollection::Insert(pScDataObject);
}
// Suche nach einem freien Index
sal_uInt16 ScRangeName::GetEntryIndex()
{
sal_uInt16 nLast = 0;
for ( sal_uInt16 i = 0; i < nCount; i++ )
{
sal_uInt16 nIdx = ((ScRangeData*)pItems[i])->GetIndex();
if( nIdx > nLast )
{
nLast = nIdx;
}
}
return nLast + 1;
}
ScRangeData* ScRangeName::FindIndex( sal_uInt16 nIndex )
{
ScRangeData aDataObj( nIndex );
sal_uInt16 n;
if( Search( &aDataObj, n ) )
return (*this)[ n ];
else
return NULL;
}
//UNUSED2009-05 ScRangeData* ScRangeName::GetRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const
//UNUSED2009-05 {
//UNUSED2009-05 if ( pItems )
//UNUSED2009-05 {
//UNUSED2009-05 for ( sal_uInt16 i = 0; i < nCount; i++ )
//UNUSED2009-05 if ( ((ScRangeData*)pItems[i])->IsRangeAtCursor( rPos, bStartOnly ) )
//UNUSED2009-05 return (ScRangeData*)pItems[i];
//UNUSED2009-05 }
//UNUSED2009-05 return NULL;
//UNUSED2009-05 }
ScRangeData* ScRangeName::GetRangeAtBlock( const ScRange& rBlock ) const
{
if ( pItems )
{
for ( sal_uInt16 i = 0; i < nCount; i++ )
if ( ((ScRangeData*)pItems[i])->IsRangeAtBlock( rBlock ) )
return (ScRangeData*)pItems[i];
}
return NULL;
}
void ScRangeName::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable)
{
if (nFlag == 2)
RemoveRangeinScope( nOldTable );
for (sal_uInt16 i=0; i<nCount; i++)
((ScRangeData*)pItems[i])->UpdateTabRef(nOldTable, nFlag, nNewTable);
if (nFlag ==4)
{
SCTAB copyScope = nOldTable > nNewTable ? nNewTable : nNewTable+1;
CopyRangeinScope( copyScope, nOldTable);
}
}