summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sc/inc/document.hxx4
-rw-r--r--sc/inc/externalrefmgr.hxx44
-rw-r--r--sc/source/core/data/cell.cxx2
-rw-r--r--sc/source/core/data/documen3.cxx2
-rw-r--r--sc/source/core/data/documen4.cxx2
-rw-r--r--sc/source/core/data/document.cxx2
-rw-r--r--sc/source/core/inc/interpre.hxx18
-rw-r--r--sc/source/core/tool/address.cxx13
-rw-r--r--sc/source/core/tool/interpr1.cxx334
-rw-r--r--sc/source/core/tool/interpr4.cxx445
-rw-r--r--sc/source/core/tool/token.cxx59
-rw-r--r--sc/source/filter/excel/xeformula.cxx2
-rw-r--r--sc/source/filter/excel/xelink.cxx2
-rw-r--r--sc/source/ui/docshell/externalrefmgr.cxx322
14 files changed, 879 insertions, 372 deletions
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 091792a96059..8964f756f07e 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 818920885493..e0988f98632b 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 68bf83c303fa..8b1e66de6c55 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 6753fc1fd3e3..1fc9db02b3d1 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 148cc367534c..a296ab068804 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 400263b280d9..0bd50b75f04d 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 edecaadb39f0..98c6afbe466c 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 462bcd042c86..5e0327e06c91 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 d335c756cc32..fec208671760 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:
{
- PushIllegalParameter();
- return;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
+ {
+ PushIllegalParameter();
+ return;
+ }
}
- }
- else if (GetStackType() == svMatrix)
- {
- pMatSrc = PopMatrix();
- if (!pMatSrc)
+ break;
+ case svMatrix:
+ case svExternalDoubleRef:
{
+ if (GetStackType() == svMatrix)
+ pMatSrc = PopMatrix();
+ else
+ PopExternalDoubleRef(pMatSrc);
+
+ if (!pMatSrc)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ break;
+ default:
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 47cde7186067..2edd18a369f0 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)
- {
- SetError(errUnknownStackVariable);
- return NULL;
- }
-
- --sp;
- FormulaToken* p = pStack[sp];
- switch (p->GetType())
+ StackVar eType = GetStackType();
+ switch (eType)
{
+ 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 f8706acf759a..2dd6dc1ff7ea 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 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;
+
+ // external references
+ case svExternalSingleRef:
+ case svExternalDoubleRef: n += sizeof(extref); break;
+ case svExternalName: n += sizeof(extname); break;
+ default:
{
- 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 34e48671a3bc..2b5d534c6d1e 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 a9112b98c98d..c6570c2736b8 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 7fa31246275a..68f0b277717a 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,38 +1777,8 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
return pArray;
}
- SCTAB nTab1;
- if (!pSrcDoc->GetTable(rTabName, nTab1))
- {
- // specified table name doesn't exist in the source document.
- pArray.reset(new ScTokenArray);
- pArray->AddToken(FormulaErrorToken(errNoRef));
- return pArray;
- }
-
- ScRange aRange(rRange);
- SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
-
vector<ScExternalRefCache::SingleRangeData> aCacheData;
- aCacheData.reserve(nTabSpan+1);
- aCacheData.push_back(ScExternalRefCache::SingleRangeData());
- aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
-
- for (SCTAB i = 1; i < nTabSpan + 1; ++i)
- {
- String aTabName;
- if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
- // source document doesn't have any table by the specified name.
- break;
-
- aCacheData.push_back(ScExternalRefCache::SingleRangeData());
- aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
- }
-
- aRange.aStart.SetTab(nTab1);
- aRange.aEnd.SetTab(nTab1 + nTabSpan);
-
- pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
+ pArray = getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aRange, aCacheData);
if (pArray)
// Cache these values.
@@ -1836,14 +1807,159 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_u
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;
- ScDocument* pSrcDoc = getSrcDocument(nFileId);
+ 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.
+ pArray.reset(new ScTokenArray);
+ pArray->AddToken(FormulaErrorToken(errNoRef));
+ return pArray;
+ }
+
+ ScRange aRange(rRange);
+ SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
+
+ vector<ScExternalRefCache::SingleRangeData> aCacheData;
+ aCacheData.reserve(nTabSpan+1);
+ aCacheData.push_back(ScExternalRefCache::SingleRangeData());
+ aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
+
+ for (SCTAB i = 1; i < nTabSpan + 1; ++i)
+ {
+ String aTabName;
+ if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
+ // source document doesn't have any table by the specified name.
+ break;
+
+ aCacheData.push_back(ScExternalRefCache::SingleRangeData());
+ aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
+ }
+
+ aRange.aStart.SetTab(nTab1);
+ aRange.aEnd.SetTab(nTab1 + nTabSpan);
+
+ pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
+ rRange = aRange;
+ rCacheData.swap(aCacheData);
+ return pArray;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokensFromSrcDoc(
+ sal_uInt16 nFileId, const ScDocument* pSrcDoc, String& rName)
+{
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;
-
- 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();
-}
+ const String* pFileName = getExternalFileName(nFileId);
+ if (!pFileName)
+ return NULL;
-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())