Kaydet (Commit) b9514451 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Support fetching string array that spans over multiple blocks.

Change-Id: I543fca231e0be886159b8ddbd83ceffa1bf69c1b
üst f8fe9f0f
......@@ -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;
......
......@@ -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. */
......
......@@ -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:
......
......@@ -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();
......
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment