diff options
-rw-r--r-- | sc/inc/document.hxx | 4 | ||||
-rw-r--r-- | sc/inc/externalrefmgr.hxx | 44 | ||||
-rw-r--r-- | sc/source/core/data/cell.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/data/documen3.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/data/documen4.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/inc/interpre.hxx | 18 | ||||
-rw-r--r-- | sc/source/core/tool/address.cxx | 13 | ||||
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 334 | ||||
-rw-r--r-- | sc/source/core/tool/interpr4.cxx | 445 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 59 | ||||
-rw-r--r-- | sc/source/filter/excel/xeformula.cxx | 2 | ||||
-rw-r--r-- | sc/source/filter/excel/xelink.cxx | 2 | ||||
-rw-r--r-- | sc/source/ui/docshell/externalrefmgr.cxx | 322 |
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()) |