Map shared formula from xls to formula groups, and share the tokens as well.
No more mapping to range names.
Change-Id: Ic43b6ef35a91fe4d6fff748ebc22969ba4e036db
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 045b76a..22bb9bd 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -275,6 +275,7 @@ public:
*/
ScFormulaCell* SetFormulaCell( SCROW nRow, ScFormulaCell* pCell );
ScFormulaCell* SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell );
bool SetGroupFormulaCell( SCROW nRow, ScFormulaCell* pCell );
void SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast = true );
void SetRawString( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const OUString& rStr, bool bBroadcast = true );
@@ -507,8 +508,8 @@ private:
sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow );
sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow );
void ActivateNewFormulaCell( const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell );
void ActivateNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell );
void ActivateNewFormulaCell( const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin = true );
void ActivateNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin = true );
void BroadcastNewCell( SCROW nRow );
bool UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 90e0148..8b82fb7 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -804,6 +804,7 @@ public:
* is deleted automatically on failure to insert.
*/
SC_DLLPUBLIC ScFormulaCell* SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell );
SC_DLLPUBLIC bool SetGroupFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell );
SC_DLLPUBLIC void InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2,
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 6480056..f857aff 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -27,6 +27,7 @@
#include "types.hxx"
#include <set>
#include <boost/noncopyable.hpp>
namespace sc {
@@ -43,7 +44,7 @@ class ScProgress;
class ScTokenArray;
struct ScSimilarFormulaDelta;
struct SC_DLLPUBLIC ScFormulaCellGroup
struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable
{
mutable size_t mnRefCount;
@@ -55,6 +56,8 @@ struct SC_DLLPUBLIC ScFormulaCellGroup
ScFormulaCellGroup();
~ScFormulaCellGroup();
void setCode( const ScTokenArray& rCode );
};
inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 37c1430..a95f2bc 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -340,6 +340,7 @@ public:
* is deleted automatically on failure to insert.
*/
ScFormulaCell* SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
bool SetGroupFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
void SetValue( SCCOL nCol, SCROW nRow, const double& rVal );
void SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError);
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index f9a4ff1..09a9798 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -62,6 +62,12 @@ public:
ScFormulaVectorState GetVectorState() const;
/**
* If the array contains at least one relative row reference or named
* expression, it's variant. Otherwise invariant.
*/
bool IsInvariant() const;
/// Exactly and only one range (valid or deleted)
bool IsReference( ScRange& rRange, const ScAddress& rPos ) const;
/// Exactly and only one valid range (no #REF!s)
diff --git a/sc/qa/unit/data/xls/shared-formula.xls b/sc/qa/unit/data/xls/shared-formula.xls
index a9be6b7..f27acb4 100644
--- a/sc/qa/unit/data/xls/shared-formula.xls
+++ b/sc/qa/unit/data/xls/shared-formula.xls
Binary files differ
diff --git a/sc/qa/unit/filters-test.cxx b/sc/qa/unit/filters-test.cxx
index 1d7eeca..957e0e0 100644
--- a/sc/qa/unit/filters-test.cxx
+++ b/sc/qa/unit/filters-test.cxx
@@ -32,6 +32,8 @@
#include "cellform.hxx"
#include "drwlayer.hxx"
#include "userdat.hxx"
#include "formulacell.hxx"
#include <svx/svdpage.hxx>
using namespace ::com::sun::star;
@@ -344,6 +346,13 @@ void ScFiltersTest::testSharedFormulaXLS()
double fCheck = i*10.0;
CPPUNIT_ASSERT_EQUAL(fCheck, fVal);
}
ScFormulaCell* pCell = pDoc->GetFormulaCell(ScAddress(1,18,0));
CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pCell);
ScFormulaCellGroupRef xGroup = pCell->GetCellGroup();
CPPUNIT_ASSERT_MESSAGE("This cell should be a part of a cell group.", xGroup);
CPPUNIT_ASSERT_MESSAGE("Incorrect group geometry.", xGroup->mnStart == 2 && xGroup->mnLength == 17);
xDocSh->DoClose();
}
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 4474aec..461193c 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -381,16 +381,17 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy
}
void ScColumn::ActivateNewFormulaCell(
const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell )
const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin )
{
ActivateNewFormulaCell(maCells.position(itPos, nRow), rCell);
ActivateNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin);
}
void ScColumn::ActivateNewFormulaCell(
const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin )
{
// See if this new formula cell can join an existing shared formula group.
JoinNewFormulaCell(aPos, rCell);
if (bJoin)
// See if this new formula cell can join an existing shared formula group.
JoinNewFormulaCell(aPos, rCell);
// When we insert from the Clipboard we still have wrong (old) References!
// First they are rewired in CopyBlockFromClip via UpdateReference and the
@@ -1729,6 +1730,20 @@ ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCR
return pCell;
}
bool ScColumn::SetGroupFormulaCell( SCROW nRow, ScFormulaCell* pCell )
{
sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
sal_uInt32 nCellFormat = GetNumberFormat(nRow);
if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
pCell->SetNeedNumberFormat(true);
it = maCells.set(it, nRow, pCell);
maCellTextAttrs.set(nRow, sc::CellTextAttr());
CellStorageModified();
ActivateNewFormulaCell(it, nRow, *pCell, false);
return true;
}
namespace {
class FilterEntriesHandler
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 7a9e9d6..720b504 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -1075,6 +1075,14 @@ ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell*
return maTabs[rPos.Tab()]->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
}
bool ScDocument::SetGroupFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell )
{
if (!TableExists(rPos.Tab()))
return false;
return maTabs[rPos.Tab()]->SetGroupFormulaCell(rPos.Col(), rPos.Row(), pCell);
}
void ScDocument::SetConsolidateDlgData( const ScConsolidateParam* pData )
{
delete pConsolidateDlgData;
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index cdedb66..b9db55a 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -397,6 +397,14 @@ ScFormulaCellGroup::~ScFormulaCellGroup()
delete mpCode;
}
void ScFormulaCellGroup::setCode( const ScTokenArray& rCode )
{
delete mpCode;
mpCode = rCode.Clone();
mbInvariant = mpCode->IsInvariant();
mpCode->GenHash();
}
// ============================================================================
ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
@@ -522,8 +530,6 @@ ScFormulaCell::ScFormulaCell(
if (bSubTotal)
pDocument->AddSubTotalCell(this);
pCode->GenHash();
}
ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
@@ -3358,7 +3364,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
// Re-build formulae groups if necessary - ideally this is done at
// import / insert / delete etc. and is integral to the data structures
pDocument->RebuildFormulaGroups();
// pDocument->RebuildFormulaGroups();
if (!mxGroup || !pCode)
return false;
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 278096e..537f856 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1453,6 +1453,14 @@ ScFormulaCell* ScTable::SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* p
return aCol[nCol].SetFormulaCell(nRow, pCell);
}
bool ScTable::SetGroupFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell )
{
if (!ValidColRow(nCol, nRow))
return false;
return aCol[nCol].SetGroupFormulaCell(nRow, pCell);
}
void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
{
if (ValidColRow(nCol, nRow))
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 4703cde..d74182d 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1474,6 +1474,42 @@ ScFormulaVectorState ScTokenArray::GetVectorState() const
return meVectorState;
}
bool ScTokenArray::IsInvariant() const
{
FormulaToken** p = pCode;
FormulaToken** pEnd = p + static_cast<size_t>(nLen);
for (; p != pEnd; ++p)
{
switch ((*p)->GetType())
{
case svSingleRef:
case svExternalSingleRef:
{
const ScToken* pT = static_cast<const ScToken*>(*p);
const ScSingleRefData& rRef = pT->GetSingleRef();
if (rRef.IsRowRel())
return false;
}
break;
case svDoubleRef:
case svExternalDoubleRef:
{
const ScToken* pT = static_cast<const ScToken*>(*p);
const ScComplexRefData& rRef = pT->GetDoubleRef();
if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
return false;
}
break;
case svIndex:
return false;
default:
;
}
}
return true;
}
bool ScTokenArray::IsReference( ScRange& rRange, const ScAddress& rPos ) const
{
return ImplGetReference(rRange, rPos, false);
diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx
index 4f60d7e..e236dad 100644
--- a/sc/source/filter/excel/excform.cxx
+++ b/sc/source/filter/excel/excform.cxx
@@ -101,7 +101,6 @@ void ImportExcel::Formula4()
void ImportExcel::Formula(
const XclAddress& rXclPos, sal_uInt16 nXF, sal_uInt16 nFormLen, double fCurVal, bool bShrFmla)
{
ScAddress aScPos( ScAddress::UNINITIALIZED );
if (!GetAddressConverter().ConvertAddress(aScPos, rXclPos, GetCurrScTab(), true))
// Conversion failed.
@@ -115,13 +114,18 @@ void ImportExcel::Formula(
if (bShrFmla)
{
// This is a shared formula. Get the token array from the shared formula pool.
pResult = pFormConv->GetShrFmla(maStrm, nFormLen);
if (!pResult)
ScFormulaCellGroupRef xGroup = pFormConv->GetSharedFormula(maStrm, aScPos.Col(), nFormLen);
if (!xGroup)
return;
ScFormulaCell* pCell = new ScFormulaCell( pD, aScPos, pResult );
ScFormulaCell* pCell = new ScFormulaCell(pD, aScPos, xGroup);
pD->EnsureTable(aScPos.Tab());
pCell = pD->SetFormulaCell(aScPos, pCell);
bool bInserted = pD->SetGroupFormulaCell(aScPos, pCell);
if (!bInserted)
{
delete pCell;
return;
}
pCell->SetNeedNumberFormat(false);
if (!rtl::math::isNan(fCurVal))
pCell->SetResultDouble(fCurVal);
@@ -1673,38 +1677,33 @@ const ScTokenArray* ExcelToSc::GetBoolErr( XclBoolError eType )
return pErgebnis;
}
// if a shared formula was found, stream seeks to first byte after <nFormulaLen>,
// else stream pointer stays unchanged
const ScTokenArray* ExcelToSc::GetShrFmla( XclImpStream& aIn, sal_Size nFormulaLen )
ScFormulaCellGroupRef ExcelToSc::GetSharedFormula( XclImpStream& aIn, SCCOL nCol, sal_Size nFormulaLen )
{
if (!nFormulaLen)
return NULL;
return ScFormulaCellGroupRef();
aIn.PushPosition();
sal_uInt8 nOp;
aIn >> nOp;
if (nOp != 0x01) // Shared Formula [ 277]
if (nOp != 0x01) // must be PtgExp token.
{
aIn.PopPosition();
return NULL;
return ScFormulaCellGroupRef();
}
sal_uInt16 nCol, nRow;
aIn >> nRow >> nCol;
sal_uInt16 nLeftCol, nRow;
aIn >> nRow >> nLeftCol;
aStack << aPool.StoreName( GetOldRoot().pShrfmlaBuff->Find(
ScAddress(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), GetCurrScTab())), true);
ScAddress aRefPos(nCol, nRow, GetCurrScTab());
ScFormulaCellGroupRef xGroup = GetOldRoot().pShrfmlaBuff->Find(aRefPos);
aIn.PopPosition();
aIn.Ignore(nFormulaLen);
return aPool[aStack.Get()];
return xGroup;
}
void ExcelToSc::SetError( ScFormulaCell &rCell, const ConvErr eErr )
{
sal_uInt16 nInd;
diff --git a/sc/source/filter/excel/namebuff.cxx b/sc/source/filter/excel/namebuff.cxx
index 6279c87..ac609a4 100644
--- a/sc/source/filter/excel/namebuff.cxx
+++ b/sc/source/filter/excel/namebuff.cxx
@@ -20,9 +20,6 @@
#include "namebuff.hxx"
#include <string.h>
#include "rangenam.hxx"
#include "document.hxx"
#include "compiler.hxx"
#include "scextopt.hxx"
@@ -32,6 +29,7 @@
#include "xltools.hxx"
#include "xiroot.hxx"
#include <string.h>
sal_uInt32 StringHashEntry::MakeHashCode( const String& r )
{
@@ -70,84 +68,41 @@ void NameBuffer::operator <<( const String &rNewString )
maHashes.push_back( new StringHashEntry( rNewString ) );
}
SharedFormulaBuffer::SharedFormulaBuffer( RootData* pRD ) : ExcRoot(pRD) {}
#if OSL_DEBUG_LEVEL > 0
sal_uInt16 nShrCnt;
#endif
size_t SharedFormulaBuffer::ScAddressHashFunc::operator() (const ScAddress &addr) const
{
// Use something simple, it is just a hash.
return static_cast< sal_uInt16 >( addr.Row() ) | (static_cast< sal_uInt8 >( addr.Col() ) << 16);
}
const size_t nBase = 16384; // Range~ und Shared~ Dingens mit jeweils der Haelfte Ids
SharedFormulaBuffer::SharedFormulaBuffer( RootData* pRD ) :
ExcRoot( pRD ),
mnCurrIdx (nBase)
{
#if OSL_DEBUG_LEVEL > 0
nShrCnt = 0;
#endif
}
SharedFormulaBuffer::~SharedFormulaBuffer()
{
}
SharedFormulaBuffer::~SharedFormulaBuffer() {}
void SharedFormulaBuffer::Clear()
{
index_hash.clear();
// do not clear index_list, index calculation depends on complete list size...
// do not change mnCurrIdx
maFormulaGroups.clear();
}
void SharedFormulaBuffer::Store( const ScRange& rRange, const ScTokenArray& rToken )
void SharedFormulaBuffer::Store( const ScRange& rRange, const ScTokenArray& rArray )
{
String aName( CreateName( rRange.aStart ) );
SCROW nGroupLen = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
for (SCCOL i = rRange.aStart.Col(); i <= rRange.aEnd.Col(); ++i)
{
// Create one group per column.
ScAddress aPos = rRange.aStart;
aPos.SetCol(i);
OSL_ENSURE( mnCurrIdx <= 0xFFFF, "*ShrfmlaBuffer::Store(): I'm getting sick...!" );
ScRangeData* pData = new ScRangeData( pExcRoot->pIR->GetDocPtr(), aName, rToken, rRange.aStart, RT_SHARED );
const ScAddress& rMaxPos = pExcRoot->pIR->GetMaxPos();
pData->SetMaxCol(rMaxPos.Col());
pData->SetMaxRow(rMaxPos.Row());
pData->SetIndex( static_cast< sal_uInt16 >( mnCurrIdx ) );
pExcRoot->pIR->GetNamedRanges().insert( pData );
index_hash[rRange.aStart] = static_cast< sal_uInt16 >( mnCurrIdx );
index_list.push_front (rRange);
++mnCurrIdx;
ScFormulaCellGroupRef xNewGroup(new ScFormulaCellGroup);
xNewGroup->mnStart = rRange.aStart.Row();
xNewGroup->mnLength = nGroupLen;
xNewGroup->mpCode = rArray.Clone();
xNewGroup->mbInvariant = rArray.IsInvariant();
xNewGroup->setCode(rArray);
maFormulaGroups.insert(FormulaGroupsType::value_type(aPos, xNewGroup));
}
}
sal_uInt16 SharedFormulaBuffer::Find( const ScAddress & aAddr ) const
ScFormulaCellGroupRef SharedFormulaBuffer::Find( const ScAddress& rRefPos ) const
{
ShrfmlaHash::const_iterator hash = index_hash.find (aAddr);
if (hash != index_hash.end())
return hash->second;
FormulaGroupsType::const_iterator it = maFormulaGroups.find(rRefPos);
if (it == maFormulaGroups.end())
return ScFormulaCellGroupRef();
// It was not hashed on the top left corner ? do a brute force search
unsigned int ind = nBase;
for (ShrfmlaList::const_iterator ptr = index_list.end(); ptr != index_list.begin() ; ind++)
if ((--ptr)->In (aAddr))
return static_cast< sal_uInt16 >( ind );
return static_cast< sal_uInt16 >( mnCurrIdx );
}
#define SHRFMLA_BASENAME "SHARED_FORMULA_"
String SharedFormulaBuffer::CreateName( const ScRange& r )
{
OUString aName = SHRFMLA_BASENAME +
OUString::number( r.aStart.Col() ) + "_" +
OUString::number( r.aStart.Row() ) + "_" +
OUString::number( r.aEnd.Col() ) + "_" +
OUString::number( r.aEnd.Row() ) + "_" +
OUString::number( r.aStart.Tab() );
return aName;
return it->second;
}
sal_Int16 ExtSheetBuffer::Add( const String& rFPAN, const String& rTN, const sal_Bool bSWB )
diff --git a/sc/source/filter/inc/excform.hxx b/sc/source/filter/inc/excform.hxx
index fb866fe..0e2004c 100644
--- a/sc/source/filter/inc/excform.hxx
+++ b/sc/source/filter/inc/excform.hxx
@@ -63,7 +63,7 @@ public:
void GetDummy( const ScTokenArray*& );
const ScTokenArray* GetBoolErr( XclBoolError );
const ScTokenArray* GetShrFmla( XclImpStream& rStrm, sal_Size nFormulaLen );
ScFormulaCellGroupRef GetSharedFormula( XclImpStream& rStrm, SCCOL nCol, sal_Size nFormulaLen );
static void SetError( ScFormulaCell& rCell, const ConvErr eErr );
diff --git a/sc/source/filter/inc/namebuff.hxx b/sc/source/filter/inc/namebuff.hxx
index 6f5aa28..97aebc1 100644
--- a/sc/source/filter/inc/namebuff.hxx
+++ b/sc/source/filter/inc/namebuff.hxx
@@ -26,6 +26,8 @@
#include "xiroot.hxx"
#include "rangenam.hxx"
#include "formulacell.hxx"
#include <boost/unordered_map.hpp>
#include <list>
@@ -146,30 +148,21 @@ inline void NameBuffer::SetBase( sal_uInt16 nNewBase )
nBase = nNewBase;
}
/**
* Store and manage shared formula tokens.
*/
class SharedFormulaBuffer : public ExcRoot
{
struct ScAddressHashFunc : public std::unary_function< const ScAddress &, size_t >
{
size_t operator() (const ScAddress &addr) const;
};
typedef boost::unordered_map <ScAddress, sal_uInt16, ScAddressHashFunc> ShrfmlaHash;
typedef std::list <ScRange> ShrfmlaList;
typedef boost::unordered_map<ScAddress, ScFormulaCellGroupRef, ScAddressHashFunctor> FormulaGroupsType;
ShrfmlaHash index_hash;
ShrfmlaList index_list;
size_t mnCurrIdx;
FormulaGroupsType maFormulaGroups;
public:
SharedFormulaBuffer( RootData* pRD );
virtual ~SharedFormulaBuffer();
void Clear();
void Store( const ScRange& rRange, const ScTokenArray& );
sal_uInt16 Find (const ScAddress & rAddress ) const;
static String CreateName( const ScRange& );
void Clear();
void Store( const ScRange& rRange, const ScTokenArray& rArray );
ScFormulaCellGroupRef Find( const ScAddress& rRefPos ) const;
};