Ported calc-extref-interpreter-rework-*.diff from ooo-build.
Re-structured the interpreter code to handle external references with
ocPush, instead of ocExternalRef. This is necessary in order to
support shifting of references in the same way you can with internal
references.
In addition, this change allows re-using of document instances already
loaded when accessing external references that point to one of already
loaded documents. Previously, Calc would load the same document from
disk even when the document was already loaded.
(n#628876)
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 091792a..8964f75 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -496,7 +496,7 @@ public:
ScFieldEditEngine* CreateFieldEditEngine();
void DisposeFieldEditEngine(ScFieldEditEngine*& rpEditEngine);
SC_DLLPUBLIC ScRangeName* GetRangeName();
SC_DLLPUBLIC ScRangeName* GetRangeName() const;
void SetRangeName( ScRangeName* pNewRangeName );
SCTAB GetMaxTableNumber() { return nMaxTableNumber; }
void SetMaxTableNumber(SCTAB nNumber) { nMaxTableNumber = nNumber; }
@@ -796,7 +796,7 @@ public:
SC_DLLPUBLIC void GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue );
SC_DLLPUBLIC double RoundValueAsShown( double fVal, ULONG nFormat );
SC_DLLPUBLIC void GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
sal_uInt32& rFormat );
sal_uInt32& rFormat ) const;
sal_uInt32 GetNumberFormat( const ScRange& rRange ) const;
SC_DLLPUBLIC sal_uInt32 GetNumberFormat( const ScAddress& ) const;
/** If no number format attribute is set and the cell
diff --git a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx
index 8189208..e0988f9 100644
--- a/sc/inc/externalrefmgr.hxx
+++ b/sc/inc/externalrefmgr.hxx
@@ -684,7 +684,47 @@ private:
void insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell);
ScDocument* getSrcDocument(sal_uInt16 nFileId);
void fillCellFormat(sal_uInt32 nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const;
ScExternalRefCache::TokenRef getSingleRefTokenFromSrcDoc(
sal_uInt16 nFileId, const ScDocument* pSrcDoc, const ScAddress& rCell,
ScExternalRefCache::CellFormat* pFmt);
/**
* Retrieve a range token array from a source document instance.
*
* @param pSrcDoc pointer to the source document instance.
* @param rTabName name of the first table.
* @param rRange range specified. Upon successful retrieval, this range
* gets modified to contain the correct table IDs, and in
* case the range is larger than the data area of the source
* document, it gets reduced to the data area.
* @param rCacheData an array of structs, with each struct containing the
* table name and the data in the specified range.
*
* @return range token array
*/
ScExternalRefCache::TokenArrayRef getDoubleRefTokensFromSrcDoc(
const ScDocument* pSrcDoc, const String& rTabName, ScRange& rRange,
::std::vector<ScExternalRefCache::SingleRangeData>& rCacheData);
/**
* Retrieve range name token array from a source document instance.
*
* @param nFileId file ID of the source document.
* @param pSrcDoc pointer to the source document instance
* @param rName range name to retrieve. Note that the range name lookup
* is case <i>in</i>-sensitive, and upon successful retrieval
* of the range name array, this name gets updated to the
* actual range name with the correct casing.
*
* @return range name token array
*/
ScExternalRefCache::TokenArrayRef getRangeNameTokensFromSrcDoc(
sal_uInt16 nFileId, const ScDocument* pSrcDoc, String& rName);
const ScDocument* getInMemorySrcDocument(sal_uInt16 nFileId);
const ScDocument* getSrcDocument(sal_uInt16 nFileId);
SfxObjectShellRef loadSrcDocument(sal_uInt16 nFileId, String& rFilter);
bool isFileLoadable(const String& rFile) const;
@@ -711,7 +751,7 @@ private:
*/
void purgeStaleSrcDocument(sal_Int32 nTimeOut);
sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc);
sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument* pSrcDoc);
private:
/** cache of referenced ranges and names from source documents. */
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
index 68bf83c..8b1e66de 100644
--- a/sc/source/core/data/cell.cxx
+++ b/sc/source/core/data/cell.cxx
@@ -776,7 +776,7 @@ ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, cons
ScToken* t;
while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
{
if ( t->GetOpCode() == ocExternalRef )
if ( t->IsExternalRef() )
{
// External name, cell, and area references.
bCompile = true;
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 6753fc1..1fc9db0 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -93,7 +93,7 @@ using namespace com::sun::star;
//------------------------------------------------------------------------
ScRangeName* ScDocument::GetRangeName()
ScRangeName* ScDocument::GetRangeName() const
{
return pRangeName;
}
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index 148cc36..a296ab0 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -305,7 +305,7 @@ bool ScDocument::MarkUsedExternalReferences( ScTokenArray & rArr )
ScToken* t;
while (!bAllMarked && (t = static_cast<ScToken*>(rArr.GetNextReferenceOrName())) != NULL)
{
if (t->GetOpCode() == ocExternalRef)
if (t->IsExternalRef())
{
if (!pRefMgr)
pRefMgr = GetExternalRefManager();
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 400263b..0bd50b7 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2712,7 +2712,7 @@ double ScDocument::GetValue( const ScAddress& rPos )
void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
sal_uInt32& rFormat )
sal_uInt32& rFormat ) const
{
if (VALIDTAB(nTab))
if (pTab[nTab])
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index edecaad..98c6afb 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -35,6 +35,7 @@
#include "scdll.hxx"
#include "document.hxx"
#include "scmatrix.hxx"
#include "externalrefmgr.hxx"
#include <math.h>
#include <map>
@@ -294,10 +295,15 @@ void DoubleRefToVars( const ScToken* p,
SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
BOOL bDontCheckForTableOp = FALSE );
ScDBRangeBase* PopDoubleRef();
ScDBRangeBase* PopDBDoubleRef();
void PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
BOOL bDontCheckForTableOp = FALSE );
void PopExternalSingleRef(sal_uInt16& rFileId, String& rTabName, ScSingleRefData& rRef);
void PopExternalSingleRef(ScExternalRefCache::TokenRef& rToken, ScExternalRefCache::CellFormat* pFmt = NULL);
void PopExternalDoubleRef(sal_uInt16& rFileId, String& rTabName, ScComplexRefData& rRef);
void PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArray);
void PopExternalDoubleRef(ScMatrixRef& rMat);
BOOL PopDoubleRefOrSingleRef( ScAddress& rAdr );
void PopDoubleRefPushMatrix();
// If MatrixFormula: convert formula::svDoubleRef to svMatrix, create JumpMatrix.
@@ -315,7 +321,12 @@ void PushStringBuffer( const sal_Unicode* pString );
void PushString( const String& rString );
void PushSingleRef(SCCOL nCol, SCROW nRow, SCTAB nTab);
void PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
void PushExternalSingleRef(sal_uInt16 nFileId, const String& rTabName,
SCCOL nCol, SCROW nRow, SCTAB nTab);
void PushExternalDoubleRef(sal_uInt16 nFileId, const String& rTabName,
SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
void PushMatrix(ScMatrix* pMat);
void PushError( USHORT nError );
/// Raw stack type without default replacements.
@@ -327,11 +338,13 @@ formula::StackVar GetStackType( BYTE nParam );
BYTE GetByte() { return cPar; }
// generiert aus DoubleRef positionsabhaengige SingleRef
BOOL DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& rAdr );
double GetDoubleFromMatrix(const ScMatrixRef& pMat);
double GetDouble();
double GetDoubleWithDefault(double nDefault);
BOOL IsMissing();
BOOL GetBool() { return GetDouble() != 0.0; }
const String& GetString();
const String& GetStringFromMatrix(const ScMatrixRef& pMat);
// pop matrix and obtain one element, upper left or according to jump matrix
ScMatValType GetDoubleOrStringFromMatrix( double& rDouble, String& rString );
ScMatrixRef CreateMatrixFromDoubleRef( const formula::FormulaToken* pToken,
@@ -527,7 +540,6 @@ BOOL SetSbxVariable( SbxVariable* pVar, SCCOL nCol, SCROW nRow, SCTAB nTab );
void ScErrorType();
void ScDBArea();
void ScColRowNameAuto();
void ScExternalRef();
void ScGetPivotData();
void ScHyperLink();
void ScBahtText();
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx
index 462bcd04..5e0327e 100644
--- a/sc/source/core/tool/address.cxx
+++ b/sc/source/core/tool/address.cxx
@@ -1008,7 +1008,18 @@ lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAdd
nBits = 0;
if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab )))
nBits = 0;
{
// Specified table name is not found in this document. Assume this is an external document.
bExtDoc = true;
aDocName = aTab;
xub_StrLen n = aTab.SearchBackward('.');
if (n != STRING_NOTFOUND && n > 0)
// Extension found. Strip it.
aTab.Erase(n);
else
// No extension found. This is probably not an external document.
nBits = 0;
}
}
else
{
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index d335c75..fec2086 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3094,6 +3094,59 @@ void ScInterpreter::ScMax( BOOL bTextAsZero )
#pragma optimize("",on)
#endif
namespace {
void IterateMatrix(
const ScMatrixRef& pMat, ScIterFunc eFunc, BOOL bTextAsZero,
ULONG& rCount, short& rFuncFmtType, double& fVal, double& fRes, double& fMem, BOOL& bNull)
{
if (!pMat)
return;
SCSIZE nC, nR;
rFuncFmtType = NUMBERFORMAT_NUMBER;
pMat->GetDimensions(nC, nR);
if( eFunc == ifCOUNT2 )
rCount += (ULONG) nC * nR;
else
{
for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
{
for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
{
if (!pMat->IsString(nMatCol,nMatRow))
{
rCount++;
fVal = pMat->GetDouble(nMatCol,nMatRow);
switch( eFunc )
{
case ifAVERAGE:
case ifSUM:
if ( bNull && fVal != 0.0 )
{
bNull = FALSE;
fMem = fVal;
}
else
fRes += fVal;
break;
case ifSUMSQ: fRes += fVal * fVal; break;
case ifPRODUCT: fRes *= fVal; break;
default: ; // nothing
}
}
else if ( bTextAsZero )
{
rCount++;
if ( eFunc == ifPRODUCT )
fRes = 0.0;
}
}
}
}
}
}
double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
{
@@ -3175,6 +3228,71 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
}
nFuncFmtType = NUMBERFORMAT_NUMBER;
break;
case svExternalSingleRef:
{
ScExternalRefCache::TokenRef pToken;
ScExternalRefCache::CellFormat aFmt;
PopExternalSingleRef(pToken, &aFmt);
if (nGlobalError && (eFunc == ifCOUNT2 || eFunc == ifCOUNT))
{
nGlobalError = 0;
if ( eFunc == ifCOUNT2 )
++nCount;
break;
}
if (!pToken)
break;
StackVar eType = pToken->GetType();
if (eFunc == ifCOUNT2)
{
if (eType != formula::svEmptyCell)
nCount++;
if (nGlobalError)
nGlobalError = 0;
}
else if (eType == formula::svDouble)
{
nCount++;
fVal = pToken->GetDouble();
if (aFmt.mbIsSet)
{
nFuncFmtType = aFmt.mnType;
nFuncFmtIndex = aFmt.mnIndex;
}
switch( eFunc )
{
case ifAVERAGE:
case ifSUM:
if ( bNull && fVal != 0.0 )
{
bNull = FALSE;
fMem = fVal;
}
else
fRes += fVal;
break;
case ifSUMSQ: fRes += fVal * fVal; break;
case ifPRODUCT: fRes *= fVal; break;
case ifCOUNT:
if ( nGlobalError )
{
nGlobalError = 0;
nCount--;
}
break;
default: ; // nothing
}
}
else if (bTextAsZero && eType == formula::svString)
{
nCount++;
if ( eFunc == ifPRODUCT )
fRes = 0.0;
}
}
break;
case svSingleRef :
{
PopSingleRef( aAdr );
@@ -3321,53 +3439,20 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
}
}
break;
case svExternalDoubleRef:
{
ScMatrixRef pMat;
PopExternalDoubleRef(pMat);
if (nGlobalError)
break;
IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fVal, fMem, fRes, bNull);
}
break;
case svMatrix :
{
ScMatrixRef pMat = PopMatrix();
if (pMat)
{
SCSIZE nC, nR;
nFuncFmtType = NUMBERFORMAT_NUMBER;
pMat->GetDimensions(nC, nR);
if( eFunc == ifCOUNT2 )
nCount += (ULONG) nC * nR;
else
{
for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
{
for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
{
if (!pMat->IsString(nMatCol,nMatRow))
{
nCount++;
fVal = pMat->GetDouble(nMatCol,nMatRow);
switch( eFunc )
{
case ifAVERAGE:
case ifSUM:
if ( bNull && fVal != 0.0 )
{
bNull = FALSE;
fMem = fVal;
}
else
fRes += fVal;
break;
case ifSUMSQ: fRes += fVal * fVal; break;
case ifPRODUCT: fRes *= fVal; break;
default: ; // nothing
}
}
else if ( bTextAsZero )
{
nCount++;
if ( eFunc == ifPRODUCT )
fRes = 0.0;
}
}
}
}
}
IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fVal, fMem, fRes, bNull);
}
break;
case svError:
@@ -4082,29 +4167,39 @@ void ScInterpreter::ScMatch()
SCCOL nCol2 = 0;
SCROW nRow2 = 0;
SCTAB nTab2 = 0;
if (GetStackType() == svDoubleRef)
switch (GetStackType())
{
PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
case svDoubleRef:
{
PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
{
PushIllegalParameter();
return;
}
}
break;
case svMatrix:
case svExternalDoubleRef:
{
if (GetStackType() == svMatrix)
pMatSrc = PopMatrix();
else
PopExternalDoubleRef(pMatSrc);
if (!pMatSrc)
{
PushIllegalParameter();
return;
}
}
break;
default:
PushIllegalParameter();
return;
}
}
else if (GetStackType() == svMatrix)
{
pMatSrc = PopMatrix();
if (!pMatSrc)
{
PushIllegalParameter();
return;
}
}
else
{
PushIllegalParameter();
return;
}
if (nGlobalError == 0)
{
double fVal;
@@ -4162,6 +4257,32 @@ void ScInterpreter::ScMatch()
}
}
break;
case svExternalSingleRef:
{
ScExternalRefCache::TokenRef pToken;
PopExternalSingleRef(pToken);
if (!pToken)
{
PushInt(0);
return;
}
if (pToken->GetType() == svDouble)
{
rEntry.bQueryByString = false;
rEntry.nVal = pToken->GetDouble();
}
else
{
rEntry.bQueryByString = true;
*rEntry.pStr = pToken->GetString();
}
}
break;
case svExternalDoubleRef:
// TODO: Implement this.
PushIllegalParameter();
return;
break;
case svMatrix :
{
ScMatValType nType = GetDoubleOrStringFromMatrix(
@@ -5839,7 +5960,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
if ( GetByte() == 3 )
{
// First, get the query criteria range.
::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDBDoubleRef() );
if (!pQueryRef.get())
return NULL;
@@ -5897,7 +6018,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
SetError( errIllegalParameter );
}
auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
auto_ptr<ScDBRangeBase> pDBRef( PopDBDoubleRef() );
if (nGlobalError || !pDBRef.get())
return NULL;
@@ -6285,15 +6406,10 @@ void ScInterpreter::ScIndirect()
{
if (aExtInfo.mbExternal)
{
/* TODO: future versions should implement a proper subroutine
* token. This procedure here is a minimally invasive fix for
* #i101645# in OOo3.1.1 */
// Push a subroutine on the instruction code stack that
// resolves the external reference as the next instruction.
aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok,
aExtInfo, aRefAd, &aRefAd2));
// Signal subroutine call to interpreter.
PushTempToken( new FormulaUnknownToken( ocCall));
PushExternalDoubleRef(
aExtInfo.mnFileId, aExtInfo.maTabName,
aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab());
}
else
PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
@@ -6305,15 +6421,8 @@ void ScInterpreter::ScIndirect()
{
if (aExtInfo.mbExternal)
{
/* TODO: future versions should implement a proper subroutine
* token. This procedure here is a minimally invasive fix for
* #i101645# in OOo3.1.1 */
// Push a subroutine on the instruction code stack that
// resolves the external reference as the next instruction.
aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok,
aExtInfo, aRefAd, NULL));
// Signal subroutine call to interpreter.
PushTempToken( new FormulaUnknownToken( ocCall));
PushExternalSingleRef(
aExtInfo.mnFileId, aExtInfo.maTabName, aRefAd.Col(), aRefAd.Row(), aRefAd.Tab());
}
else
PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
@@ -6497,6 +6606,44 @@ void ScInterpreter::ScOffset()
PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
}
}
else if (GetStackType() == svExternalSingleRef)
{
sal_uInt16 nFileId;
String aTabName;
ScSingleRefData aRef;
PopExternalSingleRef(nFileId, aTabName, aRef);
aRef.CalcAbsIfRel(aPos);
nCol1 = aRef.nCol;
nRow1 = aRef.nRow;
nTab1 = aRef.nTab;
if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
{
nCol1 = (SCCOL)((long) nCol1 + nColPlus);
nRow1 = (SCROW)((long) nRow1 + nRowPlus);
if (!ValidCol(nCol1) || !ValidRow(nRow1))
PushIllegalArgument();
else
PushExternalSingleRef(nFileId, aTabName, nCol1, nRow1, nTab1);
}
else
{
if (nColNew < 0)
nColNew = 1;
if (nRowNew < 0)
nRowNew = 1;
nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 wird veraendert!
nRow1 = (SCROW)((long)nRow1+nRowPlus);
nCol2 = (SCCOL)((long)nCol1+nColNew-1);
nRow2 = (SCROW)((long)nRow1+nRowNew-1);
PushIllegalArgument();
if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
!ValidCol(nCol2) || !ValidRow(nRow2))
PushIllegalArgument();
else
PushExternalDoubleRef(nFileId, aTabName, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
}
}
else if (GetStackType() == svDoubleRef)
{
PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
@@ -6514,6 +6661,33 @@ void ScInterpreter::ScOffset()
else
PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
}
else if (GetStackType() == svExternalDoubleRef)
{
sal_uInt16 nFileId;
String aTabName;
ScComplexRefData aRef;
PopExternalDoubleRef(nFileId, aTabName, aRef);
aRef.CalcAbsIfRel(aPos);
nCol1 = aRef.Ref1.nCol;
nRow1 = aRef.Ref1.nRow;
nTab1 = aRef.Ref1.nTab;
nCol2 = aRef.Ref2.nCol;
nRow2 = aRef.Ref2.nRow;
nTab2 = aRef.Ref2.nTab;
if (nColNew < 0)
nColNew = nCol2 - nCol1 + 1;
if (nRowNew < 0)
nRowNew = nRow2 - nRow1 + 1;
nCol1 = (SCCOL)((long)nCol1+nColPlus);
nRow1 = (SCROW)((long)nRow1+nRowPlus);
nCol2 = (SCCOL)((long)nCol1+nColNew-1);
nRow2 = (SCROW)((long)nRow1+nRowNew-1);
if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
!ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
PushIllegalArgument();
else
PushExternalDoubleRef(nFileId, aTabName, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
}
else
PushIllegalParameter();
}
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 47cde71..2edd18a 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1233,40 +1233,42 @@ void ScInterpreter::DoubleRefToVars( const ScToken* p,
}
}
ScDBRangeBase* ScInterpreter::PopDoubleRef()
ScDBRangeBase* ScInterpreter::PopDBDoubleRef()
{
if (!sp)
StackVar eType = GetStackType();
switch (eType)
{
SetError(errUnknownStackVariable);
return NULL;
}
--sp;
FormulaToken* p = pStack[sp];
switch (p->GetType())
{
case svUnknown:
SetError(errUnknownStackVariable);
break;
case svError:
nGlobalError = p->GetError();
PopError();
break;
case svDoubleRef:
{
SCCOL nCol1, nCol2;
SCROW nRow1, nRow2;
SCTAB nTab1, nTab2;
DoubleRefToVars(static_cast<ScToken*>(p),
nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, false);
PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, false);
if (nGlobalError)
break;
return new ScDBInternalRange(pDok,
ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
}
case svMatrix:
case svExternalDoubleRef:
{
ScMatrixRef pMat = static_cast<ScToken*>(p)->GetMatrix();
ScMatrixRef pMat;
if (eType == svMatrix)
pMat = PopMatrix();
else
PopExternalDoubleRef(pMat);
return new ScDBExternalRange(pDok, pMat);
}
default:
SetError( errIllegalParameter);
}
return NULL;
}
@@ -1386,6 +1388,171 @@ void ScInterpreter::PopDoubleRef( ScRange& rRange, BOOL bDontCheckForTableOp )
SetError( errUnknownStackVariable);
}
void ScInterpreter::PopExternalSingleRef(sal_uInt16& rFileId, String& rTabName, ScSingleRefData& rRef)
{
if (!sp)
{
SetError(errUnknownStackVariable);
return;
}
--sp;
FormulaToken* p = pStack[sp];
StackVar eType = p->GetType();
if (eType == svError)
{
nGlobalError = p->GetError();
return;
}
if (eType != svExternalSingleRef)
{
SetError( errIllegalParameter);
return;
}
rFileId = p->GetIndex();
rTabName = p->GetString();
rRef = static_cast<ScToken*>(p)->GetSingleRef();
}
void ScInterpreter::PopExternalSingleRef(ScExternalRefCache::TokenRef& rToken, ScExternalRefCache::CellFormat* pFmt)
{
sal_uInt16 nFileId;
String aTabName;
ScSingleRefData aData;
PopExternalSingleRef(nFileId, aTabName, aData);
if (nGlobalError)
return;
ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
const String* pFile = pRefMgr->getExternalFileName(nFileId);
if (!pFile)
{
SetError(errNoName);
return;
}
if (aData.IsTabRel())
{
DBG_ERROR("ScCompiler::GetToken: external single reference must have an absolute table reference!");
SetError(errNoRef);
return;
}
aData.CalcAbsIfRel(aPos);
ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
ScExternalRefCache::CellFormat aFmt;
ScExternalRefCache::TokenRef xNew = pRefMgr->getSingleRefToken(
nFileId, aTabName, aAddr, &aPos, NULL, &aFmt);
if (!xNew)
{
SetError(errNoRef);
return;
}
rToken = xNew;
if (pFmt)
*pFmt = aFmt;
}
void ScInterpreter::PopExternalDoubleRef(sal_uInt16& rFileId, String& rTabName, ScComplexRefData& rRef)
{
if (!sp)
{
SetError(errUnknownStackVariable);
return;
}
--sp;
FormulaToken* p = pStack[sp];
StackVar eType = p->GetType();
if (eType == svError)
{
nGlobalError = p->GetError();
return;
}
if (eType != svExternalDoubleRef)
{
SetError( errIllegalParameter);
return;
}
rFileId = p->GetIndex();
rTabName = p->GetString();
rRef = static_cast<ScToken*>(p)->GetDoubleRef();
}
void ScInterpreter::PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArray)
{
sal_uInt16 nFileId;
String aTabName;
ScComplexRefData aData;
PopExternalDoubleRef(nFileId, aTabName, aData);
if (nGlobalError)
return;
ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
const String* pFile = pRefMgr->getExternalFileName(nFileId);
if (!pFile)
{
SetError(errNoName);
return;
}
if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
{
DBG_ERROR("ScCompiler::GetToken: external double reference must have an absolute table reference!");
SetError(errNoRef);
return;
}
aData.CalcAbsIfRel(aPos);
ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab,
aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab);
ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(
nFileId, aTabName, aRange, &aPos);
if (!pArray)
{
SetError(errIllegalArgument);
return;
}
ScToken* pToken = static_cast<ScToken*>(pArray->First());
if (pToken->GetType() != svMatrix)
{
SetError(errIllegalArgument);
return;
}
if (pArray->Next())
{
// Can't handle more than one matrix per parameter.
SetError( errIllegalArgument);
return;
}
rArray = pArray;
}
void ScInterpreter::PopExternalDoubleRef(ScMatrixRef& rMat)
{
ScExternalRefCache::TokenArrayRef pArray;
PopExternalDoubleRef(pArray);
if (nGlobalError)
return;
// For now, we only support single range data for external
// references, which means the array should only contain a
// single matrix token.
ScToken* p = static_cast<ScToken*>(pArray->First());
rMat = p->GetMatrix();
}
BOOL ScInterpreter::PopDoubleRefOrSingleRef( ScAddress& rAdr )
{
@@ -1668,6 +1835,40 @@ void ScInterpreter::PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
}
void ScInterpreter::PushExternalSingleRef(
sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow, SCTAB nTab)
{
if (!IfErrorPushError())
{
ScSingleRefData aRef;
aRef.InitFlags();
aRef.nCol = nCol;
aRef.nRow = nRow;
aRef.nTab = nTab;
PushTempTokenWithoutError( new ScExternalSingleRefToken(nFileId, rTabName, aRef)) ;
}
}
void ScInterpreter::PushExternalDoubleRef(
sal_uInt16 nFileId, const String& rTabName,
SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
{
if (!IfErrorPushError())
{
ScComplexRefData aRef;
aRef.InitFlags();
aRef.Ref1.nCol = nCol1;
aRef.Ref1.nRow = nRow1;
aRef.Ref1.nTab = nTab1;
aRef.Ref2.nCol = nCol2;
aRef.Ref2.nRow = nRow2;
aRef.Ref2.nTab = nTab2;
PushTempTokenWithoutError( new ScExternalDoubleRefToken(nFileId, rTabName, aRef) );
}
}
void ScInterpreter::PushMatrix(ScMatrix* pMat)
{
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushMatrix" );
@@ -1870,6 +2071,23 @@ BOOL ScInterpreter::DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& r
return bOk;
}
double ScInterpreter::GetDoubleFromMatrix(const ScMatrixRef& pMat)
{
if (!pMat)
return 0.0;
if ( !pJumpMatrix )
return pMat->GetDouble( 0 );
SCSIZE nCols, nRows, nC, nR;
pMat->GetDimensions( nCols, nRows);
pJumpMatrix->GetPos( nC, nR);
if ( nC < nCols && nR < nRows )
return pMat->GetDouble( nC, nR);
SetError( errNoValue);
return 0.0;
}
double ScInterpreter::GetDouble()
{
@@ -1905,26 +2123,28 @@ double ScInterpreter::GetDouble()
nVal = 0.0;
}
break;
case svExternalSingleRef:
{
ScExternalRefCache::TokenRef pToken;
PopExternalSingleRef(pToken);
if (!nGlobalError && pToken)
nVal = pToken->GetDouble();
}
break;
case svExternalDoubleRef:
{
ScMatrixRef pMat;
PopExternalDoubleRef(pMat);
if (nGlobalError)
break;
nVal = GetDoubleFromMatrix(pMat);
}
break;
case svMatrix:
{
ScMatrixRef pMat = PopMatrix();
if ( !pMat )
nVal = 0.0;
else if ( !pJumpMatrix )
nVal = pMat->GetDouble( 0 );
else
{
SCSIZE nCols, nRows, nC, nR;
pMat->GetDimensions( nCols, nRows);
pJumpMatrix->GetPos( nC, nR);
if ( nC < nCols && nR < nRows )
nVal = pMat->GetDouble( nC, nR);
else
{
SetError( errNoValue);
nVal = 0.0;
}
}
nVal = GetDoubleFromMatrix(pMat);
}
break;
case svError:
@@ -2013,30 +2233,23 @@ const String& ScInterpreter::GetString()
else
return EMPTY_STRING;
}
case svExternalSingleRef:
{
ScExternalRefCache::TokenRef pToken;
PopExternalSingleRef(pToken);
return nGlobalError ? EMPTY_STRING : pToken->GetString();
}
case svExternalDoubleRef:
{
ScMatrixRef pMat;
PopExternalDoubleRef(pMat);
return GetStringFromMatrix(pMat);
}
//break;
case svMatrix:
{
ScMatrixRef pMat = PopMatrix();
if ( !pMat )
; // nothing
else if ( !pJumpMatrix )
{
aTempStr = pMat->GetString( *pFormatter, 0, 0);
return aTempStr;
}
else
{
SCSIZE nCols, nRows, nC, nR;
pMat->GetDimensions( nCols, nRows);
pJumpMatrix->GetPos( nC, nR);
if ( nC < nCols && nR < nRows )
{
aTempStr = pMat->GetString( *pFormatter, nC, nR);
return aTempStr;
}
else
SetError( errNoValue);
}
return GetStringFromMatrix(pMat);
}
break;
default:
@@ -2046,7 +2259,30 @@ const String& ScInterpreter::GetString()
return EMPTY_STRING;
}
const String& ScInterpreter::GetStringFromMatrix(const ScMatrixRef& pMat)
{
if ( !pMat )
; // nothing
else if ( !pJumpMatrix )
{
aTempStr = pMat->GetString( *pFormatter, 0, 0);
return aTempStr;
}
else
{
SCSIZE nCols, nRows, nC, nR;
pMat->GetDimensions( nCols, nRows);
pJumpMatrix->GetPos( nC, nR);
if ( nC < nCols && nR < nRows )
{
aTempStr = pMat->GetString( *pFormatter, nC, nR);
return aTempStr;
}
else
SetError( errNoValue);
}
return EMPTY_STRING;
}
ScMatValType ScInterpreter::GetDoubleOrStringFromMatrix( double& rDouble,
String& rString )
@@ -3185,82 +3421,6 @@ void ScInterpreter::ScColRowNameAuto()
PushError( errNoRef );
}
void ScInterpreter::ScExternalRef()
{
ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
const String* pFile = pRefMgr->getExternalFileName(pCur->GetIndex());
if (!pFile)
PushError(errNoName);
switch (pCur->GetType())
{
case svExternalSingleRef:
{
ScSingleRefData aData(static_cast<const ScToken*>(pCur)->GetSingleRef());
if (aData.IsTabRel())
{
DBG_ERROR("ScCompiler::GetToken: external single reference must have an absolute table reference!");
break;
}
aData.CalcAbsIfRel(aPos);
ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
ScExternalRefCache::CellFormat aFmt;
ScExternalRefCache::TokenRef xNew = pRefMgr->getSingleRefToken(
pCur->GetIndex(), pCur->GetString(), aAddr, &aPos, NULL, &aFmt);
if (!xNew)
break;
PushTempToken( *xNew); // push a clone
if (aFmt.mbIsSet)
{
nFuncFmtType = aFmt.mnType;
nFuncFmtIndex = aFmt.mnIndex;
}
return;
}
//break; // unreachable, prevent compiler warning
case svExternalDoubleRef:
{
ScComplexRefData aData(static_cast<const ScToken*>(pCur)->GetDoubleRef());
if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
{
DBG_ERROR("ScCompiler::GetToken: external double reference must have an absolute table reference!");
break;
}
aData.CalcAbsIfRel(aPos);
ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab,
aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab);
ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getDoubleRefTokens(
pCur->GetIndex(), pCur->GetString(), aRange, &aPos);
if (!xNew)
break;
ScToken* p = static_cast<ScToken*>(xNew->First());
if (p->GetType() != svMatrix)
break;
if (xNew->Next())
{
// Can't handle more than one matrix per parameter.
SetError( errIllegalArgument);
break;
}
PushMatrix(p->GetMatrix());
return;
}
//break; // unreachable, prevent compiler warning
default:
;
}
PushError(errNoRef);
}
// --- internals ------------------------------------------------------------
@@ -3332,6 +3492,7 @@ void ScInterpreter::GlobalExit() // static
StackVar ScInterpreter::Interpret()
{
// StackPrinter __stack_printer__("ScInterpreter::Interpret");
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Interpret" );
short nRetTypeExpr = NUMBERFORMAT_UNDEFINED;
ULONG nRetIndexExpr = 0;
@@ -3415,7 +3576,6 @@ StackVar ScInterpreter::Interpret()
case ocDBArea : ScDBArea(); break;
case ocColRowNameAuto : ScColRowNameAuto(); break;
// separated case ocPush : Push( (ScToken&) *pCur ); break;
case ocExternalRef : ScExternalRef(); break;
case ocIf : ScIfJump(); break;
case ocChose : ScChoseJump(); break;
case ocAdd : ScAdd(); break;
@@ -3884,9 +4044,15 @@ StackVar ScInterpreter::Interpret()
}
}
// no break
case svExternalDoubleRef:
case svMatrix :
{
ScMatrixRef xMat = PopMatrix();
ScMatrixRef xMat;
if (pCur->GetType() == svMatrix)
xMat = PopMatrix();
else
PopExternalDoubleRef(xMat);
if (xMat)
{
ScMatValType nMatValType;
@@ -3931,6 +4097,23 @@ StackVar ScInterpreter::Interpret()
SetError( errUnknownStackVariable);
}
break;
case svExternalSingleRef:
{
ScExternalRefCache::TokenRef pToken;
ScExternalRefCache::CellFormat aFmt;
PopExternalSingleRef(pToken, &aFmt);
if (nGlobalError)
break;
PushTempToken(*pToken);
if (aFmt.mbIsSet)
{
nFuncFmtType = aFmt.mnType;
nFuncFmtIndex = aFmt.mnIndex;
}
}
break;
default :
SetError( errUnknownStackVariable);
}
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index f8706ac..2dd6dc1 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -240,7 +240,7 @@ void ScRawToken::SetName( USHORT n )
void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
{
eOp = ocExternalRef;
eOp = ocPush;
eType = svExternalSingleRef;
nRefCnt = 0;
@@ -255,7 +255,7 @@ void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabNam
void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
{
eOp = ocExternalRef;
eOp = ocPush;
eType = svExternalDoubleRef;
nRefCnt = 0;
@@ -269,7 +269,7 @@ void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabNam
void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName )
{
eOp = ocExternalRef;
eOp = ocPush;
eType = svExternalName;
nRefCnt = 0;
@@ -319,37 +319,26 @@ ScRawToken* ScRawToken::Clone() const
static USHORT nOffset = lcl_ScRawTokenOffset(); // offset of sbyte
USHORT n = nOffset;
if (eOp == ocExternalRef)
switch( eType )
{
switch (eType)
case svSep: break;
case svByte: n += sizeof(ScRawToken::sbyte); break;
case svDouble: n += sizeof(double); break;
case svString: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
case svSingleRef:
case svDoubleRef: n += sizeof(aRef); break;
case svMatrix: n += sizeof(ScMatrix*); break;
case svIndex: n += sizeof(USHORT); break;
case svJump: n += nJump[ 0 ] * 2 + 2; break;
case svExternal: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
// external references
case svExternalSingleRef:
case svExternalDoubleRef: n += sizeof(extref); break;
case svExternalName: n += sizeof(extname); break;
default:
{
case svExternalSingleRef:
case svExternalDoubleRef: n += sizeof(extref); break;
case svExternalName: n += sizeof(extname); break;
default:
{
DBG_ERROR1( "unknown ScRawToken::Clone() external type %d", int(eType));
}
}
}
else
{
switch( eType )
{
case svSep: break;
case svByte: n += sizeof(ScRawToken::sbyte); break;
case svDouble: n += sizeof(double); break;
case svString: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
case svSingleRef:
case svDoubleRef: n += sizeof(aRef); break;
case svMatrix: n += sizeof(ScMatrix*); break;
case svIndex: n += sizeof(USHORT); break;
case svJump: n += nJump[ 0 ] * 2 + 2; break;
case svExternal: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
default:
{
DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
}
DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
}
}
p = (ScRawToken*) new BYTE[ n ];
@@ -813,7 +802,7 @@ BOOL ScMatrixToken::operator==( const FormulaToken& r ) const
// ============================================================================
ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) :
ScToken( svExternalSingleRef, ocExternalRef),
ScToken( svExternalSingleRef, ocPush),
mnFileId(nFileId),
maTabName(rTabName),
maSingleRef(r)
@@ -879,7 +868,7 @@ BOOL ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const
// ============================================================================
ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r ) :
ScToken( svExternalDoubleRef, ocExternalRef),
ScToken( svExternalDoubleRef, ocPush),
mnFileId(nFileId),
maTabName(rTabName),
maDoubleRef(r)
@@ -965,7 +954,7 @@ BOOL ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const
// ============================================================================
ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) :
ScToken( svExternalName, ocExternalRef),
ScToken( svExternalName, ocPush),
mnFileId(nFileId),
maName(rName)
{
diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
index 34e4867..2b5d534 100644
--- a/sc/source/filter/excel/xeformula.cxx
+++ b/sc/source/filter/excel/xeformula.cxx
@@ -2104,7 +2104,7 @@ void XclExpFmlaCompImpl::ProcessExternalName( const XclExpScToken& rTokData )
{
for( FormulaToken* pScToken = xArray->First(); pScToken; pScToken = xArray->Next() )
{
if( pScToken->GetOpCode() == ocExternalRef )
if( pScToken->IsExternalRef() )
{
switch( pScToken->GetType() )
{
diff --git a/sc/source/filter/excel/xelink.cxx b/sc/source/filter/excel/xelink.cxx
index a9112b9..c6570c2 100644
--- a/sc/source/filter/excel/xelink.cxx
+++ b/sc/source/filter/excel/xelink.cxx
@@ -962,7 +962,7 @@ void XclExpExtName::WriteAddData( XclExpStream& rStrm )
break;
const ScToken* p = static_cast<const ScToken*>(mpArray->First());
if (p->GetOpCode() != ocExternalRef)
if (!p->IsExternalRef())
break;
switch (p->GetType())
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index 7fa3124..68f0b27 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -145,7 +145,7 @@ struct UpdateFormulaCell : public unary_function<ScFormulaCell*, void>
// External names, external cell and range references all have a
// ocExternalRef token.
const ScTokenArray* pCode = pCell->GetCode();
if (!pCode->HasOpCode( ocExternalRef))
if (!pCode->HasExternalRef())
return;
ScTokenArray* pArray = pCell->GetCode();
@@ -1362,7 +1362,7 @@ static FormulaToken* lcl_convertToToken(ScBaseCell* pCell)
return NULL;
}
static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, ScRange& rRange,
static ScTokenArray* lcl_convertToTokenArray(const ScDocument* pSrcDoc, ScRange& rRange,
vector<ScExternalRefCache::SingleRangeData>& rCacheData)
{
ScAddress& s = rRange.aStart;
@@ -1665,6 +1665,27 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
if (pFmt)
pFmt->mbIsSet = false;
const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
if (pSrcDoc)
{
// source document already loaded in memory. Re-use this instance.
// We don't even cache data when the document is loaded.
SCTAB nTab;
if (!pSrcDoc->GetTable(rTabName, nTab))
{
// specified table name doesn't exist in the source document.
ScExternalRefCache::TokenRef pToken(new FormulaErrorToken(errNoRef));
return pToken;
}
if (pTab)
*pTab = nTab;
return getSingleRefTokenFromSrcDoc(
nFileId, pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
}
// Check if the given table name and the cell position is cached.
sal_uInt32 nFmtIndex = 0;
ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
@@ -1672,21 +1693,12 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
if (pToken)
{
// Cache hit !
if (pFmt)
{
short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
if (nFmtType != NUMBERFORMAT_UNDEFINED)
{
pFmt->mbIsSet = true;
pFmt->mnIndex = nFmtIndex;
pFmt->mnType = nFmtType;
}
}
fillCellFormat(nFmtIndex, pFmt);
return pToken;
}
// reference not cached. read from the source document.
ScDocument* pSrcDoc = getSrcDocument(nFileId);
pSrcDoc = getSrcDocument(nFileId);
if (!pSrcDoc)
{
// Source document not reachable. Throw a reference error.
@@ -1694,7 +1706,6 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
return pToken;
}
ScBaseCell* pCell = NULL;
SCTAB nTab;
if (!pSrcDoc->GetTable(rTabName, nTab))
{
@@ -1723,33 +1734,14 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
return pToken;
}
pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell));
pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex);
nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
if (pFmt)
{
short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
if (nFmtType != NUMBERFORMAT_UNDEFINED)
{
pFmt->mbIsSet = true;
pFmt->mnIndex = nFmtIndex;
pFmt->mnType = nFmtType;
}
}
if (!pTok.get())
{
// Generate an error for unresolvable cells.
pTok.reset( new FormulaErrorToken( errNoValue));
}
pToken = getSingleRefTokenFromSrcDoc(
nFileId, pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
// Now, insert the token into cache table but don't cache empty cells.
if (pTok->GetType() != formula::svEmptyCell)
maRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pTok, nFmtIndex);
if (pToken->GetType() != formula::svEmptyCell)
maRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pToken, nFmtIndex);
return pTok;
return pToken;
}
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
@@ -1760,6 +1752,15 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
maybeLinkExternalFile(nFileId);
ScRange aRange(rRange);
const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
if (pSrcDoc)
{
// Document already loaded.
vector<ScExternalRefCache::SingleRangeData> aCacheData;
return getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aRange, aCacheData);
}
// Check if the given table name and the cell position is cached.
ScExternalRefCache::TokenArrayRef pArray =
maRefCache.getCellRangeData(nFileId, rTabName, rRange);
@@ -1767,7 +1768,7 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
// Cache hit !
return pArray;
ScDocument* pSrcDoc = getSrcDocument(nFileId);
pSrcDoc = getSrcDocument(nFileId);
if (!pSrcDoc)
{
// Source document is not reachable. Throw a reference error.
@@ -1776,7 +1777,150 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
return pArray;
}
vector<ScExternalRefCache::SingleRangeData> aCacheData;
pArray = getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aRange, aCacheData);
if (pArray)
// Cache these values.
maRefCache.setCellRangeData(nFileId, aRange, aCacheData, pArray);
else
{
// Array is empty. Fill it with an empty matrix of the required size.
pArray.reset(lcl_fillEmptyMatrix(rRange));
// Make sure to set this range 'cached', to prevent unnecessarily
// accessing the src document time and time again.
ScExternalRefCache::TableTypeRef pCacheTab =
maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
if (pCacheTab)
pCacheTab->setCachedCellRange(
rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
}
return pArray;
}
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
{
if (pCurPos)
insertRefCell(nFileId, *pCurPos);
maybeLinkExternalFile(nFileId);
String aName = rName; // make a copy to have the casing corrected.
const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
if (pSrcDoc)
{
// Document already loaded in memory.
return getRangeNameTokensFromSrcDoc(nFileId, pSrcDoc, aName);
}
ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
if (pArray.get())
// This range name is cached.
return pArray;
pSrcDoc = getSrcDocument(nFileId);
if (!pSrcDoc)
// failed to load document from disk.
return ScExternalRefCache::TokenArrayRef();
pArray = getRangeNameTokensFromSrcDoc(nFileId, pSrcDoc, aName);
if (pArray)
// Cache this range name array.
maRefCache.setRangeNameTokens(nFileId, aName, pArray);
return pArray;
}
void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
{
RefCellMap::iterator itrFile = maRefCells.find(nFileId);
if (itrFile == maRefCells.end())
return;
RefCellSet& rRefCells = itrFile->second;
for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
ScViewData* pViewData = ScDocShell::GetViewData();
if (!pViewData)
return;
ScTabViewShell* pVShell = pViewData->GetViewShell();
if (!pVShell)
return;
// Repainting the grid also repaints the texts, but is there a better way
// to refresh texts?
pVShell->Invalidate(FID_REPAINT);
pVShell->PaintGrid();
}
void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
{
RefCellMap::iterator itr = maRefCells.find(nFileId);
if (itr == maRefCells.end())
{
RefCellSet aRefCells;
pair<RefCellMap::iterator, bool> r = maRefCells.insert(
RefCellMap::value_type(nFileId, aRefCells));
if (!r.second)
// insertion failed.
return;
itr = r.first;
}
ScBaseCell* pCell = mpDoc->GetCell(rCell);
if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
itr->second.insert(static_cast<ScFormulaCell*>(pCell));
}
void ScExternalRefManager::fillCellFormat(sal_uInt32 nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const
{
if (!pFmt)
return;
short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
if (nFmtType != NUMBERFORMAT_UNDEFINED)
{
pFmt->mbIsSet = true;
pFmt->mnIndex = nFmtIndex;
pFmt->mnType = nFmtType;
}
}
ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefTokenFromSrcDoc(
sal_uInt16 nFileId, const ScDocument* pSrcDoc, const ScAddress& rCell,
ScExternalRefCache::CellFormat* pFmt)
{
// Get the cell from src doc, and convert it into a token.
ScBaseCell* pCell = NULL;
pSrcDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
ScExternalRefCache::TokenRef pToken(lcl_convertToToken(pCell));
if (!pToken.get())
{
// Generate an error for unresolvable cells.
pToken.reset( new FormulaErrorToken( errNoValue));
}
// Get number format information.
sal_uInt32 nFmtIndex = 0;
pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), rCell.Tab(), nFmtIndex);
nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
fillCellFormat(nFmtIndex, pFmt);
return pToken;
}
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokensFromSrcDoc(
const ScDocument* pSrcDoc, const String& rTabName, ScRange& rRange,
vector<ScExternalRefCache::SingleRangeData>& rCacheData)
{
ScExternalRefCache::TokenArrayRef pArray;
SCTAB nTab1;
if (!pSrcDoc->GetTable(rTabName, nTab1))
{
// specified table name doesn't exist in the source document.
@@ -1808,42 +1952,14 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
aRange.aEnd.SetTab(nTab1 + nTabSpan);
pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
if (pArray)
// Cache these values.
maRefCache.setCellRangeData(nFileId, aRange, aCacheData, pArray);
else
{
// Array is empty. Fill it with an empty matrix of the required size.
pArray.reset(lcl_fillEmptyMatrix(rRange));
// Make sure to set this range 'cached', to prevent unnecessarily
// accessing the src document time and time again.
ScExternalRefCache::TableTypeRef pCacheTab =
maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
if (pCacheTab)
pCacheTab->setCachedCellRange(
rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
}
rRange = aRange;
rCacheData.swap(aCacheData);
return pArray;
}
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokensFromSrcDoc(
sal_uInt16 nFileId, const ScDocument* pSrcDoc, String& rName)
{
if (pCurPos)
insertRefCell(nFileId, *pCurPos);
maybeLinkExternalFile(nFileId);
ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
if (pArray.get())
return pArray;
ScDocument* pSrcDoc = getSrcDocument(nFileId);
if (!pSrcDoc)
return ScExternalRefCache::TokenArrayRef();
ScRangeName* pExtNames = pSrcDoc->GetRangeName();
String aUpperName = ScGlobal::pCharClass->upper(rName);
USHORT n;
@@ -1896,55 +2012,37 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_u
pNew->AddToken(*pToken);
}
// Make sure to pass the correctly-cased range name here.
maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew);
rName = pRangeData->GetName(); // Get the correctly-cased name.
return pNew;
}
void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
const ScDocument* ScExternalRefManager::getInMemorySrcDocument(sal_uInt16 nFileId)
{
RefCellMap::iterator itrFile = maRefCells.find(nFileId);
if (itrFile == maRefCells.end())
return;
const String* pFileName = getExternalFileName(nFileId);
if (!pFileName)
return NULL;
RefCellSet& rRefCells = itrFile->second;
for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
ScViewData* pViewData = ScDocShell::GetViewData();
if (!pViewData)
return;
ScTabViewShell* pVShell = pViewData->GetViewShell();
if (!pVShell)
return;
// Repainting the grid also repaints the texts, but is there a better way
// to refresh texts?
pVShell->Invalidate(FID_REPAINT);
pVShell->PaintGrid();
}
void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
{
RefCellMap::iterator itr = maRefCells.find(nFileId);
if (itr == maRefCells.end())
TypeId aType(TYPE(ScDocShell));
ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
while (pShell)
{
RefCellSet aRefCells;
pair<RefCellMap::iterator, bool> r = maRefCells.insert(
RefCellMap::value_type(nFileId, aRefCells));
if (!r.second)
// insertion failed.
return;
itr = r.first;
SfxMedium* pMedium = pShell->GetMedium();
if (pMedium)
{
String aName = pMedium->GetName();
// TODO: We should make the case sensitivity platform dependent.
if (pFileName->EqualsIgnoreCaseAscii(aName))
{
// Found !
return pShell->GetDocument();
}
}
pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
}
ScBaseCell* pCell = mpDoc->GetCell(rCell);
if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
itr->second.insert(static_cast<ScFormulaCell*>(pCell));
return NULL;
}
ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
const ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
{
if (!mpDoc->IsExecuteLinkEnabled())
return NULL;
@@ -2418,7 +2516,7 @@ void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
maSrcDocTimer.Stop();
}
sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc)
sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument* pSrcDoc)
{
NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
if (itr == maNumFormatMap.end())