sc: report a dynamic-array spill cell as a value in ISFORMULA
A spilled cell is stored as a reference formula cell pointing back at the master, so ISFORMULA reported true across the whole spill range. Only the master holds the formula. ISFORMULA now returns true only for the master and false for the cells it spilled into, for both the single-cell and the array-context range form. A classic array formula is unchanged, as it has no dynamic-array master. Change-Id: If4f495b45677001ad13e1f1a2a669d3d235d117b Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6244 Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com> Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com> (cherry picked from commit 5361d8e25d09ccde6922f5758a4d2d35df5c0418) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207894 Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org> Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
committed by
Xisco Fauli
parent
96691462de
commit
f0b1496469
@@ -6637,6 +6637,64 @@ CPPUNIT_TEST_FIXTURE(TestFormula2, testAutoSpillFromChooseAndLet)
|
||||
m_pDoc->DeleteTab(0);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(TestFormula2, testDynamicArrayIsFormula)
|
||||
{
|
||||
// ISFORMULA is true for the master of a dynamic-array spill and
|
||||
// false for the cells it spilled into, even though the spilled
|
||||
// data came from formulas. The same input entered as a classic
|
||||
// array formula keeps every cell a formula.
|
||||
m_pDoc->SetAutoCalc(false);
|
||||
m_pDoc->InsertTab(0, u"Sheet1"_ustr);
|
||||
|
||||
m_pDoc->SetString(ScAddress(1, 0, 0), u"=1+10"_ustr);
|
||||
m_pDoc->SetString(ScAddress(1, 1, 0), u"=1+20"_ustr);
|
||||
m_pDoc->SetString(ScAddress(1, 2, 0), u"=1+30"_ustr);
|
||||
|
||||
// A1 spills =B1:B3 into A1:A3 as a dynamic-array master.
|
||||
ScAddress aPos(0, 0, 0);
|
||||
ScCompiler aComp(*m_pDoc, aPos, m_pDoc->GetGrammar(), false, false);
|
||||
std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(u"=B1:B3"_ustr);
|
||||
auto pCell = new ScFormulaCell(*m_pDoc, aPos, std::move(pCode));
|
||||
pCell->SetAutoDynamicArrayEligible(true);
|
||||
m_pDoc->SetFormulaCell(aPos, pCell);
|
||||
m_pDoc->SetAutoCalc(true);
|
||||
m_pDoc->CalcAll();
|
||||
CPPUNIT_ASSERT(pCell->IsDynamicArrayMaster());
|
||||
|
||||
// A source cell is a real formula, but the cells the master
|
||||
// spilled into are not.
|
||||
m_pDoc->SetString(ScAddress(6, 0, 0), u"=ISFORMULA(B1)"_ustr);
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(6, 0, 0)));
|
||||
|
||||
m_pDoc->SetString(ScAddress(4, 0, 0), u"=ISFORMULA(A1)"_ustr);
|
||||
m_pDoc->SetString(ScAddress(4, 1, 0), u"=ISFORMULA(A2)"_ustr);
|
||||
m_pDoc->SetString(ScAddress(4, 2, 0), u"=ISFORMULA(A3)"_ustr);
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(4, 0, 0)));
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(4, 1, 0)));
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(4, 2, 0)));
|
||||
|
||||
// The range form agrees cell by cell: ISFORMULA over A1:A3 gives
|
||||
// true, false, false across H1:H3.
|
||||
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
||||
aMark.SelectOneTable(0);
|
||||
m_pDoc->InsertMatrixFormula(7, 0, 7, 2, aMark, u"=ISFORMULA(A1:A3)"_ustr);
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(7, 0, 0)));
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(7, 1, 0)));
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(7, 2, 0)));
|
||||
|
||||
// The same =B1:B3 entered as a classic array formula at D1:D3
|
||||
// keeps every cell a formula.
|
||||
m_pDoc->InsertMatrixFormula(3, 0, 3, 2, aMark, u"=B1:B3"_ustr);
|
||||
m_pDoc->SetString(ScAddress(5, 0, 0), u"=ISFORMULA(D1)"_ustr);
|
||||
m_pDoc->SetString(ScAddress(5, 1, 0), u"=ISFORMULA(D2)"_ustr);
|
||||
m_pDoc->SetString(ScAddress(5, 2, 0), u"=ISFORMULA(D3)"_ustr);
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5, 0, 0)));
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5, 1, 0)));
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5, 2, 0)));
|
||||
|
||||
m_pDoc->DeleteTab(0);
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -2865,6 +2865,31 @@ void ScInterpreter::ScIsValue()
|
||||
PushInt( int(bRes) );
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Whether ISFORMULA counts a cell as a formula. A dynamic-array
|
||||
// spill cell is not a formula, only its master is. A classic array
|
||||
// formula cell stays a formula.
|
||||
bool lclReportsAsFormula(const ScDocument& rDocument, const ScAddress& rPosition)
|
||||
{
|
||||
if (rDocument.GetCellType(rPosition) != CELLTYPE_FORMULA)
|
||||
return false;
|
||||
const ScFormulaCell* pCell = rDocument.GetFormulaCell(rPosition);
|
||||
if (pCell && pCell->GetMatrixFlag() == ScMatrixMode::Reference)
|
||||
{
|
||||
ScAddress aOrigin;
|
||||
if (pCell->GetMatrixOrigin(rDocument, aOrigin))
|
||||
{
|
||||
const ScFormulaCell* pMaster = rDocument.GetFormulaCell(aOrigin);
|
||||
if (pMaster && pMaster->IsDynamicArrayMaster())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ScInterpreter::ScIsFormula()
|
||||
{
|
||||
nFuncFmtType = SvNumFormatType::LOGICAL;
|
||||
@@ -2906,8 +2931,7 @@ void ScInterpreter::ScIsFormula()
|
||||
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
|
||||
{
|
||||
aAdr.SetRow(nRow);
|
||||
ScRefCellValue aCell(mrDoc, aAdr);
|
||||
pResMat->PutBoolean( (aCell.getType() == CELLTYPE_FORMULA), i,j);
|
||||
pResMat->PutBoolean(lclReportsAsFormula(mrDoc, aAdr), i, j);
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
@@ -2924,7 +2948,7 @@ void ScInterpreter::ScIsFormula()
|
||||
if ( !PopDoubleRefOrSingleRef( aAdr ) )
|
||||
break;
|
||||
|
||||
bRes = (mrDoc.GetCellType(aAdr) == CELLTYPE_FORMULA);
|
||||
bRes = lclReportsAsFormula(mrDoc, aAdr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user