diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2013-09-09 19:36:30 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@collabora.com> | 2013-09-10 11:47:45 -0400 |
commit | b951445113add8360a3efb97091faefb3c870ce5 (patch) | |
tree | 7e07f5f9a771b79de7a1006d68838658f4745019 /sc | |
parent | f8fe9f0f25787b9d73ec417dd06118e6a72b9631 (diff) |
Support fetching string array that spans over multiple blocks.
Change-Id: I543fca231e0be886159b8ddbd83ceffa1bf69c1b
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/formulacell.hxx | 1 | ||||
-rw-r--r-- | sc/inc/formularesult.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/column2.cxx | 152 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 11 | ||||
-rw-r--r-- | sc/source/core/tool/formularesult.cxx | 49 |
5 files changed, 204 insertions, 10 deletions
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 835eb91f9635..a4947599033d 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -252,6 +252,7 @@ public: sal_uInt16 GetErrCode(); // interpret first if necessary sal_uInt16 GetRawError(); // don't interpret, just return code or result error bool GetErrorOrValue( sal_uInt16& rErr, double& rVal ); + bool GetErrorOrString( sal_uInt16& rErr, OUString& rStr ); sal_uInt8 GetMatrixFlag() const; ScTokenArray* GetCode(); const ScTokenArray* GetCode() const; diff --git a/sc/inc/formularesult.hxx b/sc/inc/formularesult.hxx index 00cc9fdd44d7..4f13524c9839 100644 --- a/sc/inc/formularesult.hxx +++ b/sc/inc/formularesult.hxx @@ -135,6 +135,7 @@ public: bool IsMultiline() const; bool GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const; + bool GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) const; /** Get error code if set or GetCellResultType() is formula::svError or svUnknown, else 0. */ diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 7a97972e0c2a..048402fabd68 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2148,6 +2148,138 @@ bool appendDouble( return false; } +bool appendStrings( + sc::FormulaGroupContext& rCxt, ScDocument* pDoc, + sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, + sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd ) +{ + size_t nLenRemain = nLen; + + for (; it != itEnd; ++it) + { + switch (it->type) + { + case sc::element_type_string: + { + sc::string_block::iterator itData = sc::string_block::begin(*it->data); + sc::string_block::iterator itDataEnd; + if (nLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + itDataEnd = sc::string_block::end(*it->data); + nLenRemain -= it->size; + } + else + { + itDataEnd = itData; + std::advance(itDataEnd, nLenRemain); + nLenRemain = 0; + } + + for (; itData != itDataEnd; ++itData) + rArray.push_back(rCxt.intern(*itData)); + } + break; + case sc::element_type_edittext: + { + sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data); + sc::edittext_block::iterator itDataEnd; + if (nLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + itDataEnd = sc::edittext_block::end(*it->data); + nLenRemain -= it->size; + } + else + { + itDataEnd = itData; + std::advance(itDataEnd, nLenRemain); + nLenRemain = 0; + } + + for (; itData != itDataEnd; ++itData) + { + OUString aStr = ScEditUtil::GetString(**itData, pDoc); + rArray.push_back(rCxt.intern(aStr)); + } + } + break; + case sc::element_type_formula: + { + sc::formula_block::iterator itData = sc::formula_block::begin(*it->data); + sc::formula_block::iterator itDataEnd; + if (nLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + itDataEnd = sc::formula_block::end(*it->data); + nLenRemain -= it->size; + } + else + { + itDataEnd = itData; + std::advance(itDataEnd, nLenRemain); + nLenRemain = 0; + } + + sal_uInt16 nErr; + OUString aStr; + for (; itData != itDataEnd; ++itData) + { + ScFormulaCell& rFC = **itData; + if (!rFC.GetErrorOrString(nErr, aStr) || nErr) + { + if (nErr == ScErrorCodes::errCircularReference) + { + // This cell needs to be recalculated on next visit. + rFC.SetErrCode(0); + rFC.SetDirtyVar(); + } + return false; + } + + rArray.push_back(rCxt.intern(aStr)); + } + } + break; + case sc::element_type_empty: + { + // Fill it with NULL pointers. + if (nLenRemain >= it->size) + { + rArray.resize(rArray.size() + it->size, NULL); + nLenRemain -= it->size; + } + else + { + rArray.resize(rArray.size() + nLenRemain, NULL); + nLenRemain = 0; + } + } + break; + case sc::element_type_numeric: + default: + return false; + } + + if (!nLenRemain) + return true; + } + + return false; +} + +void copyFirstBlock( sc::FormulaGroupContext& rCxt, size_t nLen, const sc::CellStoreType::position_type& rPos ) +{ + rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType); + sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); + rArray.reserve(nLen); + + const OUString* p = &sc::string_block::at(*rPos.first->data, rPos.second); + const OUString* pEnd = p + nLen; + for (; p != pEnd; ++p) + rArray.push_back(rCxt.intern(*p)); +} + } formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 ) @@ -2256,20 +2388,20 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& if (nLenRequested <= nLen) { // Requested length fits a single block. - rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType); + copyFirstBlock(rCxt, nLenRequested, aPos); sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); - rArray.reserve(nLenRequested); - - const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second); - const OUString* pEnd = p + nLenRequested; - for (; p != pEnd; ++p) - rArray.push_back(rCxt.intern(*p)); - return formula::VectorRefArray(&rArray[0]); } - // TODO: handle cases where the requested length goes beyond the - // current block just like we do with numeric array. + copyFirstBlock(rCxt, nLen, aPos); + sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); + + // Fill the remaining array with values from the following blocks. + ++aPos.first; + if (!appendStrings(rCxt, pDocument, rArray, nLenRequested - nLen, aPos.first, maCells.end())) + return formula::VectorRefArray(); + + return formula::VectorRefArray(&rArray[0]); } break; case sc::element_type_empty: diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 0f248a26705f..87a3d0515803 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2082,6 +2082,17 @@ bool ScFormulaCell::GetErrorOrValue( sal_uInt16& rErr, double& rVal ) return aResult.GetErrorOrDouble(rErr, rVal); } +bool ScFormulaCell::GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) +{ + MaybeInterpret(); + + rErr = pCode->GetCodeError(); + if (rErr) + return true; + + return aResult.GetErrorOrString(rErr, rStr); +} + bool ScFormulaCell::HasOneReference( ScRange& r ) const { pCode->Reset(); diff --git a/sc/source/core/tool/formularesult.cxx b/sc/source/core/tool/formularesult.cxx index 511bfa560d4c..ef6c15acc567 100644 --- a/sc/source/core/tool/formularesult.cxx +++ b/sc/source/core/tool/formularesult.cxx @@ -255,6 +255,19 @@ inline bool isValue( formula::StackVar sv ) || sv == formula::svEmptyCell || sv == formula::svHybridValueCell; } +inline bool isString( formula::StackVar sv ) +{ + switch (sv) + { + case formula::svString: + case formula::svHybridCell: + case formula::svHybridValueCell: + return true; + } + + return false; +} + } bool ScFormulaResult::IsValue() const @@ -321,6 +334,42 @@ bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const return true; } +bool ScFormulaResult::GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) const +{ + if (mnError) + { + rErr = mnError; + return true; + } + + formula::StackVar sv = GetCellResultType(); + if (sv == formula::svError) + { + if (GetType() == formula::svMatrixCell) + { + // don't need to test for mpToken here, GetType() already did it + rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)-> + GetUpperLeftToken()->GetError(); + } + else if (mpToken) + { + rErr = mpToken->GetError(); + } + } + + if (rErr) + return true; + + if (!mbToken) + return false; + + if (!isString(sv)) + return false; + + rStr = GetString(); + return true; +} + sal_uInt16 ScFormulaResult::GetResultError() const { if (mnError) |