2795 lines
116 KiB
C++
2795 lines
116 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include "helper/debughelper.hxx"
|
|
#include "helper/qahelper.hxx"
|
|
#include <editutil.hxx>
|
|
#include <formulacell.hxx>
|
|
#include <cellvalue.hxx>
|
|
#include <scopetools.hxx>
|
|
#include <docfunc.hxx>
|
|
#include <dbdocfun.hxx>
|
|
#include <tokenstringcontext.hxx>
|
|
#include <globalnames.hxx>
|
|
#include <dbdata.hxx>
|
|
#include <bcaslot.hxx>
|
|
#include <undomanager.hxx>
|
|
|
|
#include <sfx2/docfile.hxx>
|
|
|
|
#include <memory>
|
|
#include <string_view>
|
|
|
|
using ::std::cerr;
|
|
using ::std::endl;
|
|
|
|
class TestSharedFormula : public ScUcalcTestBase
|
|
{
|
|
};
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulas)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
ScAddress aPos(1, 9, 0); // B10
|
|
m_pDoc->SetString(aPos, u"=A10*2"_ustr); // Insert into B10.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("Expected to be a non-shared cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("Expected to be a non-shared cell.", !pFC->IsShared());
|
|
|
|
aPos.SetRow(10); // B11
|
|
m_pDoc->SetString(aPos, u"=A11*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
aPos.SetRow(8); // B9
|
|
m_pDoc->SetString(aPos, u"=A9*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
aPos.SetRow(12); // B13
|
|
m_pDoc->SetString(aPos, u"=A13*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This formula cell shouldn't be shared yet.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This formula cell shouldn't be shared yet.", !pFC->IsShared());
|
|
|
|
// Insert a formula to B12, and B9:B13 should be shared.
|
|
aPos.SetRow(11); // B12
|
|
m_pDoc->SetString(aPos, u"=A12*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Insert formulas to B15:B16.
|
|
aPos.SetRow(14); // B15
|
|
m_pDoc->SetString(aPos, u"=A15*2"_ustr);
|
|
aPos.SetRow(15); // B16
|
|
m_pDoc->SetString(aPos, u"=A16*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Insert a formula to B14, and B9:B16 should be shared.
|
|
aPos.SetRow(13); // B14
|
|
m_pDoc->SetString(aPos, u"=A14*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Insert an incompatible formula to B12, to split the shared range to B9:B11 and B13:B16.
|
|
aPos.SetRow(11); // B12
|
|
m_pDoc->SetString(aPos, u"=$A$1*4"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell shouldn't be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell shouldn't be shared.", !pFC->IsShared());
|
|
|
|
aPos.SetRow(8); // B9
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
aPos.SetRow(12); // B13
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Extend B13:B16 to B13:B20.
|
|
aPos.SetRow(16); // B17
|
|
m_pDoc->SetString(aPos, u"=A17*2"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A18*2"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A19*2"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A20*2"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC->IsShared());
|
|
// B13:B20 should be shared.
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Empty B19. This should split it into B13:B18, and B20 non-shared.
|
|
aPos.SetRow(18);
|
|
m_pDoc->SetEmptyCell(aPos);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This cell should have been emptied.", CELLTYPE_NONE, m_pDoc->GetCellType(aPos));
|
|
aPos.SetRow(12); // B13
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
// B13:B18 should be shared.
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
// B20 should be non-shared.
|
|
aPos.SetRow(19); // B20
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B20 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
|
|
|
|
// Empty B14, to make B13 non-shared and B15:B18 shared.
|
|
aPos.SetRow(13); // B14
|
|
m_pDoc->SetEmptyCell(aPos);
|
|
aPos.SetRow(12); // B13
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
// B13 should be non-shared.
|
|
CPPUNIT_ASSERT_MESSAGE("B13 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
|
|
// B15:B18 should be shared.
|
|
aPos.SetRow(14); // B15
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Set numeric value to B15, to make B16:B18 shared.
|
|
aPos.SetRow(14);
|
|
m_pDoc->SetValue(aPos, 1.2);
|
|
aPos.SetRow(15);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
// B16:B18 should be shared.
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Set string value to B16 to make B17:B18 shared.
|
|
aPos.SetRow(15);
|
|
ScCellValue aCell(svl::SharedString(u"Test"_ustr));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a string value.", CELLTYPE_STRING, aCell.getType());
|
|
aCell.commit(*m_pDoc, aPos);
|
|
CPPUNIT_ASSERT_EQUAL(aCell.getSharedString()->getString(), m_pDoc->GetString(aPos));
|
|
aPos.SetRow(16);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
// B17:B18 should be shared.
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(16), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Set edit text to B17. Now B18 should be non-shared.
|
|
ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
|
|
rEditEngine.SetTextCurrentDefaults(u"Edit Text"_ustr);
|
|
aPos.SetRow(16);
|
|
m_pDoc->SetEditText(aPos, rEditEngine.CreateTextObject());
|
|
CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT, m_pDoc->GetCellType(aPos));
|
|
aPos.SetRow(17);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC->IsShared());
|
|
|
|
// Set up a new group for shared formulas in B2:B10.
|
|
clearRange(m_pDoc, ScRange(0,0,0,2,100,0));
|
|
|
|
aPos.SetRow(1);
|
|
m_pDoc->SetString(aPos, u"=A2*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A3*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A4*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A5*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A6*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A7*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A8*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A9*10"_ustr);
|
|
aPos.IncRow();
|
|
m_pDoc->SetString(aPos, u"=A10*10"_ustr);
|
|
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B10 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Delete A4:B8. This should split the grouping to B2:B3 and B9:B10.
|
|
clearRange(m_pDoc, ScRange(0,3,0,1,7,0));
|
|
aPos.SetRow(1);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
aPos.SetRow(8);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Delete rows 4:8 and shift row 9 and below up to row 4. This should
|
|
// re-merge the two into a group of B2:B5.
|
|
m_pDoc->DeleteRow(ScRange(0,3,0,m_pDoc->MaxCol(),7,0));
|
|
aPos.SetRow(1);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Insert 2 rows at row 4, to split it into B2:B3 and B6:B7.
|
|
m_pDoc->InsertRow(ScRange(0,3,0,m_pDoc->MaxCol(),4,0));
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
aPos.SetRow(5);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Test implicit intersection with shared formulas.
|
|
aPos.Set(2,0,0);
|
|
{
|
|
// Insert data in C1:D2 and formulas in E1:E2
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "5", "1", "=C:C/D:D" },
|
|
{ "4", "2", "=C:C/D:D" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, aPos, aData);
|
|
}
|
|
aPos.Set(4,1,0);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("E2 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
aPos.SetRow(0);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("5/1=5", 5.0, m_pDoc->GetValue(aPos));
|
|
aPos.SetRow(1);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("4/2=2", 2.0, m_pDoc->GetValue(aPos));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdate)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn off auto calculation.
|
|
|
|
// Set values to A10:A12.
|
|
m_pDoc->SetValue(ScAddress(0,9,0), 1);
|
|
m_pDoc->SetValue(ScAddress(0,10,0), 2);
|
|
m_pDoc->SetValue(ScAddress(0,11,0), 3);
|
|
|
|
{
|
|
// Insert formulas that reference A10:A12 in B1:B3.
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=A10" },
|
|
{ "=A11" },
|
|
{ "=A12" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(1,0,0), aData);
|
|
}
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=A11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=A12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
// Insert cells over A11:B11 to shift to right. This should split the B1:B3 grouping into 3.
|
|
m_pDoc->InsertCol(ScRange(0,10,0,1,10,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=C11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=A12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", !pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", !pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", !pFC->IsShared());
|
|
|
|
// Delete cells over A11:B11 to bring it back to the previous state.
|
|
m_pDoc->DeleteCol(ScRange(0,10,0,1,10,0));
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=A11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=A12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
// Insert cells over A11:A12 and shift down.
|
|
m_pDoc->InsertRow(ScRange(0,10,0,0,11,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=A13"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=A14"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", !pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Delete A11:A12 to bring it back to the way it was.
|
|
m_pDoc->DeleteRow(ScRange(0,10,0,0,11,0));
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=A11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=A12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
// Insert cells over A11:B11 to shift to right again.
|
|
m_pDoc->InsertCol(ScRange(0,10,0,1,10,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=C11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=A12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", !pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", !pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", !pFC->IsShared());
|
|
|
|
// Insert cells over A12:B12 to shift to right.
|
|
m_pDoc->InsertCol(ScRange(0,11,0,1,11,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=A10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=C11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=C12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", !pFC->IsShared());
|
|
// B2 and B3 should be grouped.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Insert cells over A10:B10 to shift to right.
|
|
m_pDoc->InsertCol(ScRange(0,9,0,1,9,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B1", u"=C10"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B2", u"=C11"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in B3", u"=C12"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
|
|
// B1:B3 should be now grouped.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateMove)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Set values in B2:B4.
|
|
for (SCROW i = 1; i <= 3; ++i)
|
|
m_pDoc->SetValue(ScAddress(1,i,0), i);
|
|
|
|
// Make sure the values are really there.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,3,0)));
|
|
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=RC[-1]" },
|
|
{ "=RC[-1]" },
|
|
{ "=RC[-1]" }
|
|
};
|
|
|
|
// Set formulas in C2:C4 that reference B2:B4 individually.
|
|
insertRangeData(m_pDoc, ScAddress(2,1,0), aData);
|
|
|
|
// Check the formula results.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
// Move B2:B4 to B1:B3.
|
|
bool bMoved = m_xDocShell->GetDocFunc().MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(1,0,0), true, true, false, true);
|
|
CPPUNIT_ASSERT(bMoved);
|
|
|
|
// Make sure the values have been moved for real.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
// The formulas should have been adjusted for the move.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=R[-1]C[-1]"_ustr, m_pDoc->GetFormula(2,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=R[-1]C[-1]"_ustr, m_pDoc->GetFormula(2,2,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=R[-1]C[-1]"_ustr, m_pDoc->GetFormula(2,3,0));
|
|
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
pUndoMgr->Undo();
|
|
|
|
// The values should have moved back.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,3,0)));
|
|
|
|
// And the formulas should have been re-adjusted to their original references.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=RC[-1]"_ustr, m_pDoc->GetFormula(2,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=RC[-1]"_ustr, m_pDoc->GetFormula(2,2,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=RC[-1]"_ustr, m_pDoc->GetFormula(2,3,0));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateMove2)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn auto calc off this time.
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Set values in B2:B3, and E2:E3.
|
|
for (SCROW i = 1; i <= 2; ++i)
|
|
{
|
|
m_pDoc->SetValue(ScAddress(1,i,0), i);
|
|
m_pDoc->SetValue(ScAddress(4,i,0), i);
|
|
}
|
|
|
|
// Make sure the values are really there.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(4,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,2,0)));
|
|
|
|
{
|
|
// Set formulas in C2:C3 that reference B2:B3 individually, and F2:F3 to E2:E3.
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=RC[-1]" },
|
|
{ "=RC[-1]" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(2,1,0), aData);
|
|
insertRangeData(m_pDoc, ScAddress(5,1,0), aData);
|
|
}
|
|
|
|
m_pDoc->CalcFormulaTree(); // calculate manually.
|
|
|
|
// Check the formula results.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
|
|
|
|
// Move B2:C3 to C3:D4.
|
|
bool bMoved = m_xDocShell->GetDocFunc().MoveBlock(
|
|
ScRange(1,1,0,2,2,0), ScAddress(2,2,0), true, true, false, true);
|
|
CPPUNIT_ASSERT(bMoved);
|
|
|
|
// Make sure the range has been moved.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
// The formula cells should retain their results even with auto calc off
|
|
// and without recalculation.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,3,0)));
|
|
|
|
// And these formulas in F2:F3 are unaffected, therefore should not change.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
|
|
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
|
|
// Undo the move.
|
|
pUndoMgr->Undo();
|
|
|
|
// Check the formula results. The results should still be intact.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateRange)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Insert values to A3:A5.
|
|
m_pDoc->SetValue(ScAddress(0,2,0), 1);
|
|
m_pDoc->SetValue(ScAddress(0,3,0), 2);
|
|
m_pDoc->SetValue(ScAddress(0,4,0), 3);
|
|
|
|
{
|
|
// Insert formulas to B3:B5.
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=SUM($A$3:$A$5)" },
|
|
{ "=SUM($A$3:$A$5)" },
|
|
{ "=SUM($A$3:$A$5)" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(1,2,0), aData);
|
|
}
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=SUM($A$3:$A$5)"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=SUM($A$3:$A$5)"_ustr, m_pDoc->GetFormula(1,3,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=SUM($A$3:$A$5)"_ustr, m_pDoc->GetFormula(1,4,0));
|
|
|
|
// B3:B5 should be shared.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,3,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B4 should be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B4 should be shared.", pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,4,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC->IsShared());
|
|
|
|
// Insert 2 rows at row 1.
|
|
m_pDoc->InsertRow(ScRange(0,0,0,m_pDoc->MaxCol(),1,0));
|
|
|
|
// B5:B7 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,4,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B5 should be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B5 should be shared.", pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,5,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B6 should be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B6 should be shared.", pFC->IsShared());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,6,0));
|
|
CPPUNIT_ASSERT_MESSAGE("B7 should be shared.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("B7 should be shared.", pFC->IsShared());
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=SUM($A$5:$A$7)"_ustr, m_pDoc->GetFormula(1,4,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=SUM($A$5:$A$7)"_ustr, m_pDoc->GetFormula(1,5,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=SUM($A$5:$A$7)"_ustr, m_pDoc->GetFormula(1,6,0));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
namespace {
|
|
|
|
struct SortByArea
|
|
{
|
|
bool operator ()( const sc::AreaListener& rLeft, const sc::AreaListener& rRight ) const
|
|
{
|
|
if (rLeft.maArea.aStart.Tab() != rRight.maArea.aStart.Tab())
|
|
return rLeft.maArea.aStart.Tab() < rRight.maArea.aStart.Tab();
|
|
|
|
if (rLeft.maArea.aStart.Col() != rRight.maArea.aStart.Col())
|
|
return rLeft.maArea.aStart.Col() < rRight.maArea.aStart.Col();
|
|
|
|
if (rLeft.maArea.aStart.Row() != rRight.maArea.aStart.Row())
|
|
return rLeft.maArea.aStart.Row() < rRight.maArea.aStart.Row();
|
|
|
|
if (rLeft.maArea.aEnd.Tab() != rRight.maArea.aEnd.Tab())
|
|
return rLeft.maArea.aEnd.Tab() < rRight.maArea.aEnd.Tab();
|
|
|
|
if (rLeft.maArea.aEnd.Col() != rRight.maArea.aEnd.Col())
|
|
return rLeft.maArea.aEnd.Col() < rRight.maArea.aEnd.Col();
|
|
|
|
return rLeft.maArea.aEnd.Row() < rRight.maArea.aEnd.Row();
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateRangeDeleteRow)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
m_pDoc->InsertTab(0, u"Formula"_ustr);
|
|
|
|
ScRange aWholeArea(0, 0, 0, 100, 100, 0); // Large enough for all references used in the test.
|
|
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "1", "2", "=SUM(A1:B1)" },
|
|
{ "3", "4", "=SUM(A2:B2)" },
|
|
{ nullptr, nullptr, nullptr },
|
|
{ "5", "6", "=SUM(A4:B4)" },
|
|
{ "7", "8", "=SUM(A5:B5)" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(0,0,0), aData);
|
|
|
|
// Check initial formula values.
|
|
CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,4,0)));
|
|
|
|
// Check the area listener status.
|
|
ScBroadcastAreaSlotMachine* pBASM = m_pDoc->GetBASM();
|
|
CPPUNIT_ASSERT(pBASM);
|
|
std::vector<sc::AreaListener> aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaOverlapType::Inside);
|
|
std::sort(aListeners.begin(), aListeners.end(), SortByArea());
|
|
|
|
// This check makes only sense if group listeners are activated.
|
|
#if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be 2 area listeners.", size_t(2), aListeners.size());
|
|
// First one should be group-listening on A1:B2.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners[0].maArea);
|
|
CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
|
|
// Second one should be group-listening on A4:B5.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners[0].maArea);
|
|
CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
|
|
#endif
|
|
|
|
// Make sure that C1:C2 and C4:C5 are formula groups.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(2,3,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Delete row 3. This will merge the two formula groups.
|
|
ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
rFunc.DeleteCells(ScRange(0,2,0,m_pDoc->MaxCol(),2,0), &aMark, DelCellCmd::Rows, true);
|
|
|
|
// Make sure C1:C4 belong to the same group.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
|
|
// This check makes only sense if group listeners are activated.
|
|
#if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
|
|
// We should only have one listener group-listening on A1:B4.
|
|
aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaOverlapType::Inside);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be 1 area listener.", size_t(1), aListeners.size());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B4.", ScRange(0,0,0,1,3,0), aListeners[0].maArea);
|
|
CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
|
|
#endif
|
|
|
|
// Change the value of B4 and make sure the value of C4 changes.
|
|
rFunc.SetValueCell(ScAddress(1,3,0), 100.0, false);
|
|
CPPUNIT_ASSERT_EQUAL(107.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
|
|
// Undo the value change in B4, and make sure C4 follows.
|
|
pUndoMgr->Undo();
|
|
CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
// Undo the deletion of row 3.
|
|
pUndoMgr->Undo();
|
|
|
|
// Make sure that C1:C2 and C4:C5 are formula groups again.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(2,3,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check the values of formula cells again.
|
|
CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,4,0)));
|
|
|
|
aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaOverlapType::Inside);
|
|
std::sort(aListeners.begin(), aListeners.end(), SortByArea());
|
|
|
|
// This check makes only sense if group listeners are activated.
|
|
#if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be 2 area listeners.", size_t(2), aListeners.size());
|
|
// First one should be group-listening on A1:B2.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners[0].maArea);
|
|
CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
|
|
// Second one should be group-listening on A4:B5.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners[0].maArea);
|
|
CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
|
|
#endif
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateExternal)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
m_pDoc->InsertTab(0, u"Formula"_ustr);
|
|
|
|
// Launch an external document shell.
|
|
ScDocShellRef xExtDocSh = new ScDocShell;
|
|
|
|
SfxMedium* pMed = new SfxMedium(u"file:///extdata.fake"_ustr, StreamMode::STD_READWRITE);
|
|
xExtDocSh->DoLoad(pMed);
|
|
ScDocument& rExtDoc = xExtDocSh->GetDocument();
|
|
|
|
// Populate A1:A3.
|
|
rExtDoc.InsertTab(0, u"Data"_ustr);
|
|
rExtDoc.SetString(ScAddress(0,0,0), u"A"_ustr);
|
|
rExtDoc.SetString(ScAddress(0,1,0), u"B"_ustr);
|
|
rExtDoc.SetString(ScAddress(0,2,0), u"C"_ustr);
|
|
|
|
{
|
|
// Insert formula cells in A7:A10 of the host document, referencing A1:A3
|
|
// of the external document.
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "='file:///extdata.fake'#$Data.A1" },
|
|
{ "='file:///extdata.fake'#$Data.A2" },
|
|
{ "='file:///extdata.fake'#$Data.A3" },
|
|
{ "=COUNTA('file:///extdata.fake'#$Data.A1:A3)" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(0,6,0), aData);
|
|
}
|
|
|
|
// Check the formula results.
|
|
CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(0,6,0)));
|
|
CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(0,7,0)));
|
|
CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(0,8,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,9,0)));
|
|
|
|
// Check the formulas too.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A1"_ustr, m_pDoc->GetFormula(0,6,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A2"_ustr, m_pDoc->GetFormula(0,7,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A3"_ustr, m_pDoc->GetFormula(0,8,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=COUNTA('file:///extdata.fake'#$Data.A1:A3)"_ustr, m_pDoc->GetFormula(0,9,0));
|
|
|
|
// Delete rows 1 and 2. This should not change the references in the formula cells below.
|
|
ScDocFunc& rDocFunc = m_xDocShell->GetDocFunc();
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
rDocFunc.DeleteCells(ScRange(0,0,0,m_pDoc->MaxCol(),1,0), &aMark, DelCellCmd::CellsUp, true);
|
|
|
|
// Check the shifted formula cells now in A5:A8.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A1"_ustr, m_pDoc->GetFormula(0,4,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A2"_ustr, m_pDoc->GetFormula(0,5,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A3"_ustr, m_pDoc->GetFormula(0,6,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=COUNTA('file:///extdata.fake'#$Data.A1:A3)"_ustr, m_pDoc->GetFormula(0,7,0));
|
|
|
|
// Undo and check the formulas again.
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
pUndoMgr->Undo();
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A1"_ustr, m_pDoc->GetFormula(0,6,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A2"_ustr, m_pDoc->GetFormula(0,7,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A3"_ustr, m_pDoc->GetFormula(0,8,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=COUNTA('file:///extdata.fake'#$Data.A1:A3)"_ustr, m_pDoc->GetFormula(0,9,0));
|
|
|
|
// Redo the row deletion and check the formulas again.
|
|
pUndoMgr->Redo();
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A1"_ustr, m_pDoc->GetFormula(0,4,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A2"_ustr, m_pDoc->GetFormula(0,5,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"='file:///extdata.fake'#$Data.A3"_ustr, m_pDoc->GetFormula(0,6,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=COUNTA('file:///extdata.fake'#$Data.A1:A3)"_ustr, m_pDoc->GetFormula(0,7,0));
|
|
|
|
xExtDocSh->DoClose();
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasInsertRow)
|
|
{
|
|
struct
|
|
{
|
|
bool checkContent( ScDocument* pDoc )
|
|
{
|
|
// B1:B2 and B4:B5 should point to $A$5.
|
|
SCROW pRows[] = { 0, 1, 3, 4 };
|
|
for (size_t i = 0; i < SAL_N_ELEMENTS(pRows); ++i)
|
|
{
|
|
ScAddress aPos(1, pRows[i], 0);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=$A$5"_ustr, pDoc->GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
|
|
}
|
|
|
|
// B1:B2 should be grouped.
|
|
ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
if (!pFC || pFC->GetSharedTopRow() != 0 || pFC->GetSharedLength() != 2)
|
|
{
|
|
cerr << "B1:B2 should be grouped." << endl;
|
|
return false;
|
|
}
|
|
|
|
// B4:B5 should be grouped.
|
|
pFC = pDoc->GetFormulaCell(ScAddress(1,3,0));
|
|
if (!pFC || pFC->GetSharedTopRow() != 3 || pFC->GetSharedLength() != 2)
|
|
{
|
|
cerr << "B4:B5 should be grouped." << endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool checkContentUndo( ScDocument* pDoc )
|
|
{
|
|
for (SCROW i = 0; i <= 3; ++i)
|
|
{
|
|
ScAddress aPos(1,i,0);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=$A$4"_ustr, pDoc->GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
|
|
}
|
|
|
|
// Ensure that B5 is empty.
|
|
if (pDoc->GetCellType(ScAddress(1,4,0)) != CELLTYPE_NONE)
|
|
{
|
|
cerr << "B5 should be empty." << endl;
|
|
return false;
|
|
}
|
|
|
|
// B1:B4 should be grouped.
|
|
ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
if (!pFC || pFC->GetSharedTopRow() != 0 || pFC->GetSharedLength() != 4)
|
|
{
|
|
cerr << "B1:B4 should be grouped." << endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} aCheck;
|
|
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Scenario inspired by fdo#76470.
|
|
|
|
// Set value to A4.
|
|
m_pDoc->SetValue(ScAddress(0,3,0), 4.0);
|
|
|
|
{
|
|
// Set formula cells in B1:B4 all referencing A4 as absolute reference.
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=$A$4" },
|
|
{ "=$A$4" },
|
|
{ "=$A$4" },
|
|
{ "=$A$4" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(1,0,0), aData);
|
|
}
|
|
|
|
// Insert a new row at row 3.
|
|
ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
rFunc.InsertCells(ScRange(0,2,0,m_pDoc->MaxCol(),2,0), &aMark, INS_INSROWS_BEFORE, true, true);
|
|
|
|
bool bResult = aCheck.checkContent(m_pDoc);
|
|
CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bResult);
|
|
|
|
// Undo and check its result.
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
pUndoMgr->Undo();
|
|
|
|
bResult = aCheck.checkContentUndo(m_pDoc);
|
|
CPPUNIT_ASSERT_MESSAGE("Failed on the content check after undo.", bResult);
|
|
|
|
// Redo and check its result.
|
|
pUndoMgr->Redo();
|
|
bResult = aCheck.checkContent(m_pDoc);
|
|
CPPUNIT_ASSERT_MESSAGE("Failed on the content check after redo.", bResult);
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasDeleteRows)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
{
|
|
// Fill data cells A1:A20 and formula cells B1:B20. Formulas in
|
|
// B1:B10 and B11:B20 should be different.
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "0", "=RC[-1]+1" },
|
|
{ "1", "=RC[-1]+1" },
|
|
{ "2", "=RC[-1]+1" },
|
|
{ "3", "=RC[-1]+1" },
|
|
{ "4", "=RC[-1]+1" },
|
|
{ "5", "=RC[-1]+1" },
|
|
{ "6", "=RC[-1]+1" },
|
|
{ "7", "=RC[-1]+1" },
|
|
{ "8", "=RC[-1]+1" },
|
|
{ "9", "=RC[-1]+1" },
|
|
{ "10", "=RC[-1]+11" },
|
|
{ "11", "=RC[-1]+11" },
|
|
{ "12", "=RC[-1]+11" },
|
|
{ "13", "=RC[-1]+11" },
|
|
{ "14", "=RC[-1]+11" },
|
|
{ "15", "=RC[-1]+11" },
|
|
{ "16", "=RC[-1]+11" },
|
|
{ "17", "=RC[-1]+11" },
|
|
{ "18", "=RC[-1]+11" },
|
|
{ "19", "=RC[-1]+11" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(0,0,0), aData);
|
|
}
|
|
|
|
// B1:B10 should be shared.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
|
|
// B11:B20 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,10,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,10 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,10 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
|
|
|
|
// Delete rows 9:12
|
|
m_pDoc->DeleteRow(ScRange(0,8,0,m_pDoc->MaxCol(),11,0));
|
|
|
|
// B1:B8 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
|
|
// B9:B16 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,8,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,8 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,8 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
|
|
|
|
// Delete row 3
|
|
m_pDoc->DeleteRow(ScRange(0,2,0,m_pDoc->MaxCol(),2,0));
|
|
|
|
// B1:B7 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
// B8:B15 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,7,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,7 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,7 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
|
|
|
|
// Delete row 5
|
|
m_pDoc->DeleteRow(ScRange(0,4,0,m_pDoc->MaxCol(),4,0));
|
|
|
|
// B1:B6 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
|
|
// B7:B14 should be shared.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,6,0));
|
|
CPPUNIT_ASSERT_MESSAGE("1,6 must be a shared formula cell.", pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("1,6 must be a shared formula cell.", pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasDeleteColumns)
|
|
{
|
|
using namespace formula;
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
|
|
// First, test a single cell case. A value in B1 and formula in C1.
|
|
m_pDoc->SetValue(ScAddress(1,0,0), 11.0);
|
|
m_pDoc->SetString(ScAddress(2,0,0), u"=RC[-1]"_ustr);
|
|
CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,0,0)));
|
|
|
|
// Delete column B.
|
|
rFunc.DeleteCells(ScRange(1,0,0,1,m_pDoc->MaxRow(),0), &aMark, DelCellCmd::CellsLeft, true);
|
|
CPPUNIT_ASSERT_EQUAL(u"#REF!"_ustr, m_pDoc->GetString(ScAddress(1,0,0)));
|
|
|
|
// The reference should still point to row 1 but the column status should be set to 'deleted'.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
const ScTokenArray* pCode = pFC->GetCode();
|
|
CPPUNIT_ASSERT(pCode);
|
|
CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pCode->GetLen());
|
|
const FormulaToken* pToken = pCode->GetArray()[0];
|
|
CPPUNIT_ASSERT_EQUAL(svSingleRef, pToken->GetType());
|
|
const ScSingleRefData* pSRef = pToken->GetSingleRef();
|
|
CPPUNIT_ASSERT(pSRef->IsColDeleted());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pSRef->toAbs(*m_pDoc, ScAddress(1,0,0)).Row());
|
|
|
|
// The formula string should show #REF! in lieu of the column position (only for Calc A1 syntax).
|
|
sc::CompileFormulaContext aCFCxt(*m_pDoc, FormulaGrammar::GRAM_ENGLISH);
|
|
CPPUNIT_ASSERT_EQUAL(u"=#REF!1"_ustr, pFC->GetFormula(aCFCxt));
|
|
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
|
|
// Undo and make sure the deleted flag is gone.
|
|
pUndoMgr->Undo();
|
|
CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,0,0)));
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(u"=B1"_ustr, pFC->GetFormula(aCFCxt));
|
|
|
|
// Clear row 1 and move over to a formula group case.
|
|
clearRange(m_pDoc, ScRange(0,0,0,m_pDoc->MaxCol(),0,0));
|
|
|
|
// Fill A1:B2 with numbers, and C1:C2 with formula that reference those numbers.
|
|
for (SCROW i = 0; i <= 1; ++i)
|
|
{
|
|
m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
|
|
m_pDoc->SetValue(ScAddress(1,i,0), (i+11));
|
|
m_pDoc->SetString(ScAddress(2,i,0), u"=RC[-2]+RC[-1]"_ustr);
|
|
double fCheck = m_pDoc->GetValue(ScAddress(0,i,0));
|
|
fCheck += m_pDoc->GetValue(ScAddress(1,i,0));
|
|
CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i,0)));
|
|
}
|
|
|
|
// Delete column B.
|
|
rFunc.DeleteCells(ScRange(1,0,0,1,m_pDoc->MaxRow(),0), &aMark, DelCellCmd::CellsLeft, true);
|
|
|
|
for (SCROW i = 0; i <= 1; ++i)
|
|
{
|
|
ScAddress aPos(1,i,0);
|
|
CPPUNIT_ASSERT_EQUAL(u"#REF!"_ustr, m_pDoc->GetString(aPos));
|
|
}
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); // B1
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(u"=A1+#REF!1"_ustr, pFC->GetFormula(aCFCxt));
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0)); // B2
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(u"=A2+#REF!2"_ustr, pFC->GetFormula(aCFCxt));
|
|
|
|
// Undo deletion of column B and check the results of C1:C2.
|
|
pUndoMgr->Undo();
|
|
for (SCROW i = 0; i <= 1; ++i)
|
|
{
|
|
double fCheck = m_pDoc->GetValue(ScAddress(0,i,0));
|
|
fCheck += m_pDoc->GetValue(ScAddress(1,i,0));
|
|
CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i,0)));
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateMoveSheets)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Sheet1"_ustr);
|
|
m_pDoc->InsertTab(1, u"Sheet2"_ustr);
|
|
m_pDoc->InsertTab(2, u"Sheet3"_ustr);
|
|
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // make sure auto calc is on.
|
|
|
|
// Switch to R1C1 for ease of repeated formula insertions.
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
// Fill numbers in A1:A8 on Sheet2.
|
|
for (SCROW i = 0; i <= 7; ++i)
|
|
m_pDoc->SetValue(ScAddress(0,i,1), i+1);
|
|
|
|
// Fill formula cells A1:A8 on Sheet1, to refer to the same cell address on Sheet2.
|
|
for (SCROW i = 0; i <= 7; ++i)
|
|
m_pDoc->SetString(ScAddress(0,i,0), u"=Sheet2!RC"_ustr);
|
|
|
|
// Check the results.
|
|
for (SCROW i = 0; i <= 7; ++i)
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,0)));
|
|
|
|
// Move Sheet3 to the leftmost position before Sheet1.
|
|
m_pDoc->MoveTab(2, 0);
|
|
|
|
// Check sheet names.
|
|
std::vector<OUString> aTabNames = m_pDoc->GetAllTableNames();
|
|
CPPUNIT_ASSERT_MESSAGE("There should be at least 3 sheets.", aTabNames.size() >= 3);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet3"_ustr, aTabNames[0]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet1"_ustr, aTabNames[1]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet2"_ustr, aTabNames[2]);
|
|
|
|
// Check the results again on Sheet1.
|
|
for (SCROW i = 0; i <= 7; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,1)));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula expression.", u"=Sheet2!RC"_ustr, m_pDoc->GetFormula(0,i,1));
|
|
}
|
|
|
|
// Insert a new sheet at the left end.
|
|
m_pDoc->InsertTab(0, u"Sheet4"_ustr);
|
|
|
|
// Check sheet names.
|
|
aTabNames = m_pDoc->GetAllTableNames();
|
|
CPPUNIT_ASSERT_MESSAGE("There should be at least 4 sheets.", aTabNames.size() >= 4);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet4"_ustr, aTabNames[0]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet3"_ustr, aTabNames[1]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet1"_ustr, aTabNames[2]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet2"_ustr, aTabNames[3]);
|
|
|
|
// Check the results again on Sheet1.
|
|
for (SCROW i = 0; i <= 7; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,2)));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula expression.", u"=Sheet2!RC"_ustr, m_pDoc->GetFormula(0,i,2));
|
|
}
|
|
|
|
// Delete Sheet4.
|
|
m_pDoc->DeleteTab(0);
|
|
|
|
// Check sheet names.
|
|
aTabNames = m_pDoc->GetAllTableNames();
|
|
CPPUNIT_ASSERT_MESSAGE("There should be at least 3 sheets.", aTabNames.size() >= 3);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet3"_ustr, aTabNames[0]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet1"_ustr, aTabNames[1]);
|
|
CPPUNIT_ASSERT_EQUAL(u"Sheet2"_ustr, aTabNames[2]);
|
|
|
|
// Check the results again on Sheet1.
|
|
for (SCROW i = 0; i <= 7; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,1)));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula expression.", u"=Sheet2!RC"_ustr, m_pDoc->GetFormula(0,i,1));
|
|
}
|
|
|
|
m_pDoc->DeleteTab(2);
|
|
m_pDoc->DeleteTab(1);
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateCopySheets)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // make sure auto calc is on.
|
|
|
|
m_pDoc->InsertTab(0, u"Sheet1"_ustr);
|
|
m_pDoc->InsertTab(1, u"Sheet2"_ustr);
|
|
|
|
m_pDoc->SetValue(ScAddress(0,0,1), 1.0); // A1 on Sheet2
|
|
m_pDoc->SetValue(ScAddress(0,1,1), 2.0); // A2 on Sheet2
|
|
|
|
// Reference values on Sheet2, but use absolute sheet references.
|
|
m_pDoc->SetString(ScAddress(0,0,0), u"=$Sheet2.A1"_ustr);
|
|
m_pDoc->SetString(ScAddress(0,1,0), u"=$Sheet2.A2"_ustr);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
|
|
|
|
// Copy Sheet1 and insert the copied sheet before the current Sheet1 position.
|
|
m_pDoc->CopyTab(0, 0);
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=$Sheet2.A1"_ustr, m_pDoc->GetFormula(0,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=$Sheet2.A2"_ustr, m_pDoc->GetFormula(0,1,0));
|
|
|
|
// Check the values on the copied sheet.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
|
|
|
|
// Check the values on the original sheet.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,1)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,1)));
|
|
|
|
m_pDoc->DeleteTab(2);
|
|
m_pDoc->DeleteTab(1);
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasRefUpdateDeleteSheets)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // make sure auto calc is on.
|
|
|
|
m_pDoc->InsertTab(0, u"Sheet1"_ustr);
|
|
m_pDoc->InsertTab(1, u"Sheet2"_ustr);
|
|
|
|
// Set values to B2:B4 on Sheet2.
|
|
m_pDoc->SetValue(ScAddress(1,1,1), 1.0);
|
|
m_pDoc->SetValue(ScAddress(1,2,1), 2.0);
|
|
m_pDoc->SetValue(ScAddress(1,3,1), 3.0);
|
|
|
|
// Set formulas in A1:A3 on Sheet1 that reference B2:B4 on Sheet2.
|
|
m_pDoc->SetString(ScAddress(0,0,0), u"=Sheet2.B2"_ustr);
|
|
m_pDoc->SetString(ScAddress(0,1,0), u"=Sheet2.B3"_ustr);
|
|
m_pDoc->SetString(ScAddress(0,2,0), u"=Sheet2.B4"_ustr);
|
|
|
|
// Check the formula results.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=Sheet2.B2"_ustr, m_pDoc->GetFormula(0,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=Sheet2.B3"_ustr, m_pDoc->GetFormula(0,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=Sheet2.B4"_ustr, m_pDoc->GetFormula(0,2,0));
|
|
|
|
// Delete Sheet2.
|
|
ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
|
|
rFunc.DeleteTable(1, true);
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=#REF!.B2"_ustr, m_pDoc->GetFormula(0,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=#REF!.B3"_ustr, m_pDoc->GetFormula(0,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=#REF!.B4"_ustr, m_pDoc->GetFormula(0,2,0));
|
|
|
|
// Undo the deletion and make sure the formulas are back to the way they were.
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
pUndoMgr->Undo();
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=Sheet2.B2"_ustr, m_pDoc->GetFormula(0,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=Sheet2.B3"_ustr, m_pDoc->GetFormula(0,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", u"=Sheet2.B4"_ustr, m_pDoc->GetFormula(0,2,0));
|
|
|
|
// TODO: We can't test redo yet as ScUndoDeleteTab::Redo() relies on
|
|
// view shell to do its thing.
|
|
|
|
m_pDoc->DeleteTab(1);
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulasCopyPaste)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
// Fill formula cells B1:B10.
|
|
for (SCROW i = 0; i <= 9; ++i)
|
|
m_pDoc->SetString(1, i, 0, u"=RC[-1]"_ustr);
|
|
|
|
ScAddress aPos(1, 8, 0); // B9
|
|
ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Copy formulas in B6:B9 to the clipboard doc.
|
|
ScRange aSrcRange(1,5,0,1,8,0); // B6:B9
|
|
ScDocument aClipDoc(SCDOCMODE_CLIP);
|
|
copyToClip(m_pDoc, aSrcRange, &aClipDoc);
|
|
pFC = aClipDoc.GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("B9 in the clip doc should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
// Paste them to C2:C10.
|
|
ScRange aDestRange(2,1,0,2,9,0);
|
|
pasteFromClip(m_pDoc, aDestRange, &aClipDoc);
|
|
aPos.SetCol(2);
|
|
aPos.SetRow(1);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("C2 should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
|
|
ScRange aRange(1,0,0,1,9,0); // B1:B10
|
|
ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
|
|
pUndoDoc->InitUndo(*m_pDoc, 0, 0, true, true);
|
|
m_pDoc->CopyToDocument(aRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc);
|
|
std::unique_ptr<ScUndoPaste> pUndo(createUndoPaste(*m_xDocShell, aRange, ScDocumentUniquePtr(pUndoDoc)));
|
|
|
|
// First, make sure the formula cells are shared in the undo document.
|
|
aPos.SetCol(1);
|
|
for (SCROW i = 0; i <= 9; ++i)
|
|
{
|
|
aPos.SetRow(i);
|
|
pFC = pUndoDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("Must be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
}
|
|
|
|
// Overwrite B1:B10.
|
|
for (SCROW i = 0; i <= 9; ++i)
|
|
m_pDoc->SetValue(ScAddress(1,i,0), i*10);
|
|
|
|
for (SCROW i = 0; i <= 9; ++i)
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Numeric cell was expected.", CELLTYPE_VALUE, m_pDoc->GetCellType(ScAddress(1,i,0)));
|
|
|
|
// Undo the action to fill B1:B10 with formula cells again.
|
|
pUndo->Undo();
|
|
|
|
aPos.SetCol(1);
|
|
for (SCROW i = 0; i <= 9; ++i)
|
|
{
|
|
aPos.SetRow(i);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC->GetCode(), pFC->GetSharedCode());
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaInsertColumn)
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Set shared formula group over H2:H3.
|
|
m_pDoc->SetString(ScAddress(7,1,0), u"=G3*B3"_ustr);
|
|
m_pDoc->SetString(ScAddress(7,2,0), u"=G4*B4"_ustr);
|
|
|
|
// Insert a single column at Column F. This used to crash before fdo#74041.
|
|
m_pDoc->InsertCol(ScRange(5,0,0,5,m_pDoc->MaxRow(),0));
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=H3*B3"_ustr, m_pDoc->GetFormula(8,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=H4*B4"_ustr, m_pDoc->GetFormula(8,2,0));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaMoveBlock)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Set values to A1:A3.
|
|
m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
|
|
m_pDoc->SetValue(ScAddress(0,1,0), 2.0);
|
|
m_pDoc->SetValue(ScAddress(0,2,0), 3.0);
|
|
|
|
// Set formulas in B1:B3 to reference A1:A3.
|
|
m_pDoc->SetString(ScAddress(1,0,0), u"=RC[-1]"_ustr);
|
|
m_pDoc->SetString(ScAddress(1,1,0), u"=RC[-1]"_ustr);
|
|
m_pDoc->SetString(ScAddress(1,2,0), u"=RC[-1]"_ustr);
|
|
|
|
ScRange aFormulaRange(1,0,0,1,2,0);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
clearFormulaCellChangedFlag(*m_pDoc, aFormulaRange);
|
|
|
|
// Move A1:A3 to D1:D3.
|
|
ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
|
|
bool bMoved = rFunc.MoveBlock(ScRange(0,0,0,0,2,0), ScAddress(3,0,0), true, true, false, true);
|
|
CPPUNIT_ASSERT(bMoved);
|
|
|
|
// The result should stay the same.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
clearFormulaCellChangedFlag(*m_pDoc, aFormulaRange);
|
|
|
|
// Make sure these formula cells in B1:B3 have correct positions even after the move.
|
|
std::vector<SCROW> aRows { 0, 1, 2 };
|
|
bool bRes = checkFormulaPositions(*m_pDoc, 0, 1, aRows.data(), aRows.size());
|
|
CPPUNIT_ASSERT(bRes);
|
|
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
|
|
// Undo and check the result.
|
|
pUndoMgr->Undo();
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
clearFormulaCellChangedFlag(*m_pDoc, aFormulaRange);
|
|
|
|
// Redo and check the result.
|
|
pUndoMgr->Redo();
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
// Clear the range and start over.
|
|
clearRange(m_pDoc, ScRange(0,0,0,m_pDoc->MaxCol(),m_pDoc->MaxRow(),0));
|
|
|
|
// Set values 1,2,3,4,5 to A1:A5.
|
|
for (SCROW i = 0; i <= 4; ++i)
|
|
m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
|
|
|
|
// Set formulas to B1:B5.
|
|
for (SCROW i = 0; i <= 4; ++i)
|
|
m_pDoc->SetString(ScAddress(1,i,0), u"=RC[-1]"_ustr);
|
|
|
|
// Check the initial formula results.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
|
|
CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
|
|
|
|
// Move A1:A2 to D2:D3.
|
|
bMoved = rFunc.MoveBlock(ScRange(0,0,0,0,1,0), ScAddress(3,1,0), true, true, false, true);
|
|
CPPUNIT_ASSERT(bMoved);
|
|
|
|
// Check the formula values again. They should not change.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
|
|
CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
|
|
|
|
pUndoMgr->Undo();
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
|
|
CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
|
|
|
|
pUndoMgr->Redo();
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
|
|
CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaUpdateOnNamedRangeChange)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
const char* const pName = "MyRange";
|
|
const char* const pExpr1 = "$Test.$A$1:$A$3";
|
|
const char* const pExpr2 = "$Test.$A$1:$A$4";
|
|
|
|
RangeNameDef aName;
|
|
aName.mpName = pName;
|
|
aName.mpExpr = pExpr1;
|
|
aName.mnIndex = 1;
|
|
std::unique_ptr<ScRangeName> pNames(new ScRangeName);
|
|
bool bSuccess = insertRangeNames(m_pDoc, pNames.get(), &aName, &aName + 1);
|
|
CPPUNIT_ASSERT(bSuccess);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames->size());
|
|
m_pDoc->SetRangeName(std::move(pNames));
|
|
|
|
// Set values to A1:A4.
|
|
m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
|
|
m_pDoc->SetValue(ScAddress(0,1,0), 2.0);
|
|
m_pDoc->SetValue(ScAddress(0,2,0), 3.0);
|
|
m_pDoc->SetValue(ScAddress(0,3,0), 4.0);
|
|
|
|
// Set formula to B1:B3.
|
|
m_pDoc->SetString(ScAddress(1,0,0), u"=SUM(MyRange)"_ustr);
|
|
m_pDoc->SetString(ScAddress(1,1,0), u"=SUM(MyRange)"_ustr);
|
|
m_pDoc->SetString(ScAddress(1,2,0), u"=SUM(MyRange)"_ustr);
|
|
|
|
// Set single formula with no named range to B5.
|
|
m_pDoc->SetString(ScAddress(1,4,0), u"=ROW()"_ustr);
|
|
|
|
// Set shared formula with no named range to B7:B8.
|
|
m_pDoc->SetString(ScAddress(1,6,0), u"=ROW()"_ustr);
|
|
m_pDoc->SetString(ScAddress(1,7,0), u"=ROW()"_ustr);
|
|
|
|
// B1:B3 should be grouped.
|
|
ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
// B7:B8 should be grouped.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,6,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
|
|
CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(1,6,0)));
|
|
CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(1,7,0)));
|
|
|
|
// Set a single formula to C1.
|
|
m_pDoc->SetString(ScAddress(2,0,0), u"=AVERAGE(MyRange)"_ustr);
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("C1 should not be shared.", !pFC->IsShared());
|
|
CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
|
|
|
|
// Update the range of MyRange.
|
|
pNames.reset(new ScRangeName);
|
|
aName.mpExpr = pExpr2;
|
|
bSuccess = insertRangeNames(m_pDoc, pNames.get(), &aName, &aName + 1);
|
|
CPPUNIT_ASSERT(bSuccess);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames->size());
|
|
ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
|
|
|
|
typedef std::map<OUString, ScRangeName> NameMapType;
|
|
NameMapType aNewNames;
|
|
OUString aScope(STR_GLOBAL_RANGE_NAME);
|
|
aNewNames.insert(std::make_pair(aScope, std::move(*pNames)));
|
|
rFunc.ModifyAllRangeNames(aNewNames);
|
|
|
|
// Check to make sure all displayed formulas are still good.
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=SUM(MyRange)"_ustr, m_pDoc->GetFormula(1,0,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=SUM(MyRange)"_ustr, m_pDoc->GetFormula(1,1,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=SUM(MyRange)"_ustr, m_pDoc->GetFormula(1,2,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=ROW()"_ustr, m_pDoc->GetFormula(1,4,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=ROW()"_ustr, m_pDoc->GetFormula(1,6,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=ROW()"_ustr, m_pDoc->GetFormula(1,7,0));
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", u"=AVERAGE(MyRange)"_ustr, m_pDoc->GetFormula(2,0,0));
|
|
|
|
// Check the calculation results as well.
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
|
|
CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(1,6,0)));
|
|
CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(1,7,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc->GetValue(ScAddress(2,0,0)));
|
|
|
|
// Change the value of A4 and make sure the value change gets propagated.
|
|
m_pDoc->SetValue(ScAddress(0,3,0), 0.0);
|
|
CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaUpdateOnDBChange)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"RangeTest"_ustr);
|
|
|
|
// Put 1, 2, 3, 4 in A1:A4.
|
|
for (SCROW i = 0; i <= 3; ++i)
|
|
m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
|
|
|
|
ScDBCollection* pDBs = m_pDoc->GetDBCollection();
|
|
CPPUNIT_ASSERT_MESSAGE("Failed to fetch DB collection object.", pDBs);
|
|
|
|
// Define database range 'MyRange' for A1:A2.
|
|
std::unique_ptr<ScDBData> pData(new ScDBData(u"MyRange"_ustr, 0, 0, 0, 0, 1));
|
|
bool bInserted = pDBs->getNamedDBs().insert(std::move(pData));
|
|
CPPUNIT_ASSERT_MESSAGE("Failed to insert a new database range.", bInserted);
|
|
|
|
// Insert in C2:C4 a group of formula cells that reference MyRange.
|
|
for (SCROW i = 1; i <= 3; ++i)
|
|
m_pDoc->SetString(ScAddress(2,i,0), u"=SUM(MyRange)"_ustr);
|
|
|
|
// Make sure C2:C4 is a formula group.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT(pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
// Check the initial formula results.
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
ScDBDocFunc aFunc(*m_xDocShell);
|
|
|
|
// Change the range referenced by MyRange to A1:A4.
|
|
ScDBCollection aNewDBs(*m_pDoc);
|
|
std::unique_ptr<ScDBData> pNewData(new ScDBData(u"MyRange"_ustr, 0, 0, 0, 0, 3));
|
|
bInserted = aNewDBs.getNamedDBs().insert(std::move(pNewData));
|
|
CPPUNIT_ASSERT_MESSAGE("Failed to insert a new database range.", bInserted);
|
|
|
|
std::vector<ScRange> aDeleted;
|
|
aFunc.ModifyAllDBData(aNewDBs, aDeleted);
|
|
|
|
// Check the updated formula results.
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
|
|
CPPUNIT_ASSERT(pUndoMgr);
|
|
|
|
// Undo and check the results.
|
|
pUndoMgr->Undo();
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
// Redo and check the results.
|
|
pUndoMgr->Redo();
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,2,0)));
|
|
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,3,0)));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaAbsCellListener)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
|
|
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=$A$1" },
|
|
{ "=$A$1" },
|
|
{ "=$A$1" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(1,0,0), aData);
|
|
|
|
// A1 should have 3 listeners listening into it.
|
|
const SvtBroadcaster* pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
|
|
CPPUNIT_ASSERT(pBC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pBC->GetAllListeners().size());
|
|
|
|
// Check the formula results.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
// Change the value of A1 and make sure B1:B3 follows.
|
|
m_pDoc->SetValue(ScAddress(0,0,0), 2.5);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc->GetValue(ScAddress(1,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc->GetValue(ScAddress(1,1,0)));
|
|
CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc->GetValue(ScAddress(1,2,0)));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
static double checkNewValuesNotification( ScDocument* pDoc, const ScAddress& rOrgPos )
|
|
{
|
|
ScAddress aPos(rOrgPos);
|
|
aPos.IncCol();
|
|
pDoc->SetValues( aPos, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
|
|
aPos = rOrgPos;
|
|
double fVal = 0.0;
|
|
for (SCROW i=0; i < 5; ++i)
|
|
{
|
|
fVal += pDoc->GetValue(aPos);
|
|
aPos.IncRow();
|
|
}
|
|
return fVal;
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaUnshareAreaListeners)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=SUM(B1:B2)", "1" },
|
|
{ "=SUM(B2:B3)", "2" },
|
|
{ "=SUM(B3:B4)", "4" },
|
|
{ nullptr, "8" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(0,0,0), aData);
|
|
|
|
// Check that A1:A3 is a formula group.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
m_pDoc->SetValue(ScAddress(0,1,0), 23.0); // unshare at A2
|
|
m_pDoc->SetValue(ScAddress(1,1,0), 16.0); // change value of B2
|
|
m_pDoc->SetValue(ScAddress(1,2,0), 32.0); // change value of B3
|
|
// A1 and A3 should be recalculated.
|
|
CPPUNIT_ASSERT_EQUAL(17.0, m_pDoc->GetValue(ScAddress(0,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL(40.0, m_pDoc->GetValue(ScAddress(0,2,0)));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 1,3,0));
|
|
|
|
for (int nRun = 0; nRun < 7; ++nRun)
|
|
{
|
|
// Data in A2:C6
|
|
const ScAddress aOrgPos(0,1,0);
|
|
const std::vector<std::vector<const char*>> aData2 = {
|
|
{ "=SUM(B2:C2)", "1", "2" },
|
|
{ "=SUM(B3:C3)", "4", "8" },
|
|
{ "=SUM(B4:C4)", "16", "32" },
|
|
{ "=SUM(B5:C5)", "64", "128" },
|
|
{ "=SUM(B6:C6)", "256", "512" },
|
|
};
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Check that A2:A6 is a formula group.
|
|
pFC = m_pDoc->GetFormulaCell(aOrgPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aOrgPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
|
|
|
|
// Overwrite and thus unshare formula in A3.
|
|
// Check different code paths with different methods.
|
|
ScAddress aPos(aOrgPos);
|
|
aPos.IncRow(2);
|
|
switch (nRun)
|
|
{
|
|
case 0:
|
|
// Directly set a different formula cell, which bypasses
|
|
// ScDocument::SetString(), mimicking formula input in view.
|
|
{
|
|
ScFormulaCell* pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B4"_ustr);
|
|
ScDocFunc& rDocFunc = m_xDocShell->GetDocFunc();
|
|
rDocFunc.SetFormulaCell( aPos, pCell, false);
|
|
}
|
|
break;
|
|
case 1:
|
|
m_pDoc->SetString( aPos, u"=B4"_ustr); // set formula
|
|
break;
|
|
case 2:
|
|
m_pDoc->SetString( aPos, u"x"_ustr); // set string
|
|
break;
|
|
case 3:
|
|
m_pDoc->SetString( aPos, u"4096"_ustr); // set number/numeric
|
|
break;
|
|
case 4:
|
|
m_pDoc->SetValue( aPos, 4096.0); // set numeric
|
|
break;
|
|
case 5:
|
|
m_pDoc->SetValues( aPos, {4096.0}); // set numeric vector
|
|
break;
|
|
case 6:
|
|
// Set formula cell vector.
|
|
{
|
|
ScFormulaCell* pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B4"_ustr);
|
|
std::vector<ScFormulaCell*> aCells { pCell };
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Check that A2:A3 and A5:A6 are two formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(3);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check that listeners were set up and formulas are updated when B2:B6
|
|
// get new values input (tdf#123736).
|
|
aPos = aOrgPos;
|
|
aPos.IncCol();
|
|
m_pDoc->SetValues( aPos, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
|
|
|
|
aPos = aOrgPos;
|
|
CPPUNIT_ASSERT_EQUAL(1026.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
CPPUNIT_ASSERT_EQUAL(2056.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
if (nRun != 2) // if not string
|
|
CPPUNIT_ASSERT_EQUAL(4096.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
CPPUNIT_ASSERT_EQUAL(8320.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
CPPUNIT_ASSERT_EQUAL(16896.0, m_pDoc->GetValue(aPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,5,0));
|
|
}
|
|
|
|
// Check detach/regroup combinations of overlapping when setting formula
|
|
// cell vectors.
|
|
{
|
|
// Fixed data in A3:C7, modified formula range A1:A9
|
|
const ScAddress aOrgPos(0,2,0);
|
|
ScAddress aPos( ScAddress::UNINITIALIZED);
|
|
ScFormulaCell* pCell;
|
|
std::vector<ScFormulaCell*> aCells;
|
|
const std::vector<std::vector<const char*>> aData2 = {
|
|
{ "=SUM(B3:C3)", "1", "2" },
|
|
{ "=SUM(B4:C4)", "4", "8" },
|
|
{ "=SUM(B5:C5)", "16", "32" },
|
|
{ "=SUM(B6:C6)", "64", "128" },
|
|
{ "=SUM(B7:C7)", "256", "512" },
|
|
};
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Add grouping formulas in A1:A2, keep A3:A7
|
|
aPos = ScAddress(0,0,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=SUM(B1:C1)"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=SUM(B2:C2)"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check it is one formula group.
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Add formulas in A1:A2, keep A3:A7
|
|
aPos = ScAddress(0,0,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B1+C1"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B2+C2"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(2);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Add formula in A2, overwrite A3, keep A4:A7
|
|
aPos = ScAddress(0,1,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B2+C2"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B3+C3"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(2);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A4", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Overwrite A3:A4, keep A5:A7
|
|
aPos = ScAddress(0,2,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B3+C3"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B4+C4"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(2);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Keep A3, overwrite A4:A5, keep A6:A7
|
|
aPos = ScAddress(0,3,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B4+C4"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B5+C5"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", !pFC->IsSharedTop());
|
|
aPos.IncRow(1);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A4", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(2);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A6", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Keep A3:A4, overwrite A5:A6, keep A7
|
|
aPos = ScAddress(0,4,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B5+C5"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B6+C6"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(2);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
aPos.IncRow(2);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A7", !pFC->IsSharedTop());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Keep A3:A5, overwrite A6:A7
|
|
aPos = ScAddress(0,5,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B6+C6"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B7+C7"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(3), pFC->GetSharedLength());
|
|
aPos.IncRow(3);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A6", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Keep A3:A6, overwrite A7, add A8
|
|
aPos = ScAddress(0,6,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B7+C7"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B8+C8"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
aPos.IncRow(4);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A7", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Keep A3:A7, add A8:A9
|
|
aPos = ScAddress(0,7,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B8+C8"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=B9+C9"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check formula groups.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
|
|
aPos.IncRow(5);
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A7", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Keep A3:A7, add grouping formulas in A8:A9
|
|
aPos = ScAddress(0,7,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=SUM(B8:C8)"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=SUM(B9:C9)"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check it is one formula group.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
|
|
insertRangeData(m_pDoc, aOrgPos, aData2);
|
|
|
|
// Overwrite grouping formulas in A4:A5
|
|
aPos = ScAddress(0,3,0);
|
|
std::vector<ScFormulaCell*>().swap( aCells);
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=SUM(B4:C4)"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow();
|
|
pCell = new ScFormulaCell( *m_pDoc, aPos, u"=SUM(B5:C5)"_ustr);
|
|
aCells.push_back(pCell);
|
|
aPos.IncRow(-1);
|
|
m_pDoc->SetFormulaCells( aPos, aCells);
|
|
|
|
// Check it is one formula group.
|
|
aPos = aOrgPos;
|
|
pFC = m_pDoc->GetFormulaCell(aPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
|
|
|
|
// Check notification of setting new values.
|
|
CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
|
|
|
|
clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaListenerDeleteArea)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test0"_ustr);
|
|
m_pDoc->InsertTab(1, u"Test1"_ustr);
|
|
|
|
const std::vector<std::vector<const char*>> aData0 = {
|
|
{ "", "", "=Test1.C1" },
|
|
{ "", "", "=Test1.C2" }
|
|
};
|
|
const std::vector<std::vector<const char*>> aData1 = {
|
|
{ "=Test0.A1", "=Test0.B1", "=SUM(A1:B1)" },
|
|
{ "=Test0.A2", "=Test0.B2", "=SUM(A2:B2)" },
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(0,0,0), aData0);
|
|
insertRangeData(m_pDoc, ScAddress(0,0,1), aData1);
|
|
|
|
// Check that Test1.A1:A2 and Test1.B1:B2 are formula groups.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,0,1));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,1));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
m_pDoc->SetValue(ScAddress(0,1,0), 1.0); // change value of Test0.A2
|
|
m_pDoc->SetValue(ScAddress(1,1,0), 2.0); // change value of Test0.B2
|
|
// Test0.C2 should be recalculated.
|
|
CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
|
|
// Delete Test0.B2
|
|
clearRange(m_pDoc, ScRange(1,1,0));
|
|
// Test0.C2 should be recalculated.
|
|
CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
|
|
|
|
m_pDoc->DeleteTab(1);
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaUpdateOnReplacement)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "1" },
|
|
{ "=SUM($A$1:$A1)" },
|
|
{ "=SUM($A$1:$A2)" },
|
|
{ "=SUM($A$1:$A3)" },
|
|
{ "=SUM($A$1:$A4)" },
|
|
{ "=SUM($A$1:$A5)" },
|
|
{ "=SUM($A$1:$A6)" },
|
|
{ "=SUM($A$1:$A7)" }
|
|
};
|
|
|
|
insertRangeData(m_pDoc, ScAddress(0,0,0), aData);
|
|
|
|
// Check that A2:A8 is a formula group.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
|
|
{ // Check initial results.
|
|
ScAddress aPos(0,0,0);
|
|
const double fResult[] = { 1.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 };
|
|
for (SCROW nRow = 1; nRow < 8; ++nRow)
|
|
{
|
|
aPos.SetRow(nRow);
|
|
CPPUNIT_ASSERT_EQUAL( fResult[nRow], m_pDoc->GetValue( aPos));
|
|
}
|
|
}
|
|
|
|
// Set up an undo object for deleting A4.
|
|
ScRange aUndoRange(0,3,0,0,3,0);
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
aMark.SetMultiMarkArea(aUndoRange);
|
|
ScDocumentUniquePtr pUndoDoc(new ScDocument(SCDOCMODE_UNDO));
|
|
pUndoDoc->InitUndo(*m_pDoc, 0, 0);
|
|
m_pDoc->CopyToDocument(aUndoRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc, &aMark);
|
|
ScUndoDeleteContents aUndo(m_xDocShell.get(), aMark, aUndoRange, std::move(pUndoDoc), false, InsertDeleteFlags::CONTENTS, true);
|
|
|
|
// Delete A4.
|
|
clearRange(m_pDoc, aUndoRange);
|
|
|
|
// Check that A2:A3 and A5:A8 are formula groups.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,4,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
|
|
{ // Check results of A4 deleted.
|
|
ScAddress aPos(0,0,0);
|
|
const double fResult[] = { 1.0, 1.0, 2.0, 0.0, 4.0, 8.0, 16.0, 32.0 };
|
|
for (SCROW nRow = 1; nRow < 8; ++nRow)
|
|
{
|
|
aPos.SetRow(nRow);
|
|
CPPUNIT_ASSERT_EQUAL( fResult[nRow], m_pDoc->GetValue( aPos));
|
|
}
|
|
}
|
|
|
|
// Restore A4.
|
|
aUndo.Undo();
|
|
|
|
// Check that A2:A8 is a formula group.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
|
|
{ // Check initial results.
|
|
ScAddress aPos(0,0,0);
|
|
const double fResult[] = { 1.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 };
|
|
for (SCROW nRow = 1; nRow < 8; ++nRow)
|
|
{
|
|
aPos.SetRow(nRow);
|
|
CPPUNIT_ASSERT_EQUAL( fResult[nRow], m_pDoc->GetValue( aPos));
|
|
}
|
|
}
|
|
|
|
// Delete A4 using selection.
|
|
m_pDoc->DeleteSelection(InsertDeleteFlags::ALL, aMark);
|
|
|
|
// Check that A2:A3 and A5:A8 are formula groups.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,4,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
|
|
{ // Check results of A4 deleted.
|
|
ScAddress aPos(0,0,0);
|
|
const double fResult[] = { 1.0, 1.0, 2.0, 0.0, 4.0, 8.0, 16.0, 32.0 };
|
|
for (SCROW nRow = 1; nRow < 8; ++nRow)
|
|
{
|
|
aPos.SetRow(nRow);
|
|
CPPUNIT_ASSERT_EQUAL( fResult[nRow], m_pDoc->GetValue( aPos));
|
|
}
|
|
}
|
|
|
|
// Restore A4.
|
|
aUndo.Undo();
|
|
|
|
// Check that A2:A8 is a formula group.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
|
|
{ // Check initial results.
|
|
ScAddress aPos(0,0,0);
|
|
const double fResult[] = { 1.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 };
|
|
for (SCROW nRow = 1; nRow < 8; ++nRow)
|
|
{
|
|
aPos.SetRow(nRow);
|
|
CPPUNIT_ASSERT_EQUAL( fResult[nRow], m_pDoc->GetValue( aPos));
|
|
}
|
|
}
|
|
|
|
// Replace A4 with 0.
|
|
m_pDoc->SetString( ScAddress(0,3,0), u"0"_ustr);
|
|
|
|
// Check that A2:A3 and A5:A8 are formula groups.
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,1,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
pFC = m_pDoc->GetFormulaCell(ScAddress(0,4,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
|
|
|
|
{ // Check results of A4 set to zero.
|
|
ScAddress aPos(0,0,0);
|
|
const double fResult[] = { 1.0, 1.0, 2.0, 0.0, 4.0, 8.0, 16.0, 32.0 };
|
|
for (SCROW nRow = 1; nRow < 8; ++nRow)
|
|
{
|
|
aPos.SetRow(nRow);
|
|
CPPUNIT_ASSERT_EQUAL( fResult[nRow], m_pDoc->GetValue( aPos));
|
|
}
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaDeleteTopCell)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "=SUM(B$1:B$2)", "1" },
|
|
{ "=SUM(B$1:B$2)", "2" }
|
|
};
|
|
|
|
insertRangeData( m_pDoc, ScAddress(0,0,0), aData);
|
|
|
|
// Check that A1:A2 is a formula group.
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( ScAddress(0,0,0));
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
|
|
// Check results A1:A2.
|
|
CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue( ScAddress(0,0,0)));
|
|
CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue( ScAddress(0,1,0)));
|
|
|
|
// Delete cell A1.
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
m_xDocShell->GetDocFunc().DeleteCell( ScAddress(0,0,0), aMark, InsertDeleteFlags::CONTENTS, false, /*bApi=*/ true);
|
|
// Check it's gone.
|
|
CPPUNIT_ASSERT(!m_pDoc->GetFormulaCell( ScAddress(0,0,0)));
|
|
|
|
// Check result A2.
|
|
CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue( ScAddress(0,1,0)));
|
|
|
|
// Replace B1 with 4.
|
|
m_pDoc->SetString( ScAddress(1,0,0), u"4"_ustr);
|
|
|
|
// Check result A2.
|
|
CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue( ScAddress(0,1,0)));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaCutCopyMoveIntoRef)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
// tdf#123714 case 1
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Data in A1:C3
|
|
std::vector<std::vector<const char*>> aData = {
|
|
{ "=B1", "", "1" },
|
|
{ "=B2", "", "1" },
|
|
{ "=B3", "", "" }
|
|
};
|
|
const ScAddress aOrgPos(0,0,0);
|
|
insertRangeData( m_pDoc, aOrgPos, aData);
|
|
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
|
|
// Set up clip document.
|
|
ScDocument aClipDoc(SCDOCMODE_CLIP);
|
|
aClipDoc.ResetClip(m_pDoc, &aMark);
|
|
// Cut C1:C2 to clipboard.
|
|
cutToClip(*m_xDocShell, ScRange(2,0,0, 2,1,0), &aClipDoc, false);
|
|
|
|
// Paste to B1:B2
|
|
ScRange aPasteRange(1,0,0, 1,1,0);
|
|
aMark.SetMarkArea(aPasteRange);
|
|
m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
|
|
|
|
// Check data in A1:A2 after Paste.
|
|
ScAddress aPos(aOrgPos);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("A1", 1.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("A2", 1.0, m_pDoc->GetValue(aPos));
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
// tdf#123714 case 2
|
|
{
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Data in A1:C3
|
|
std::vector<std::vector<const char*>> aData = {
|
|
{ "1", "2", "=SUM(A1:B1)" },
|
|
{ "4", "8", "=SUM(A2:B2)" },
|
|
{ "16", "32", "=SUM(A3:B3)" },
|
|
{ "64", "128", "=SUM(A4:B4)" },
|
|
};
|
|
const ScAddress aOrgPos(0,0,0);
|
|
insertRangeData( m_pDoc, aOrgPos, aData);
|
|
|
|
ScAddress aPos;
|
|
// Check results in C1:C4
|
|
const double fVec0[] = { 3.0, 12.0, 48.0, 192.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec0[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
|
|
// Set up clip document.
|
|
ScDocument aClipDoc(SCDOCMODE_CLIP);
|
|
aClipDoc.ResetClip(m_pDoc, &aMark);
|
|
// Cut B1:B2 to clipboard.
|
|
cutToClip(*m_xDocShell, ScRange(1,0,0, 1,1,0), &aClipDoc, false);
|
|
|
|
// Check results in C1:C4 after Cut.
|
|
const double fVec1[] = { 1.0, 4.0, 48.0, 192.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec1[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
// Paste to B3:B4
|
|
ScRange aPasteRange(1,2,0, 1,3,0);
|
|
aMark.SetMarkArea(aPasteRange);
|
|
m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
|
|
|
|
// Check results in C1:C4 after Paste.
|
|
const double fVec2[] = { 1.0, 4.0, 18.0, 72.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec2[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
// Paste to B1:B2
|
|
aPasteRange = ScRange(1,0,0, 1,1,0);
|
|
aMark.SetMarkArea(aPasteRange);
|
|
m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
|
|
|
|
// Check results in C1:C4 after Paste.
|
|
const double fVec3[] = { 3.0, 12.0, 18.0, 72.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec3[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
}
|
|
|
|
// tdf#121002
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaCutCopyMoveWithRef)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Data in A1:C4
|
|
std::vector<std::vector<const char*>> aData = {
|
|
{ "", "", "=SUM(A1:B1)" },
|
|
{ "", "", "=SUM(A2:B2)" },
|
|
{ "1", "2", "=SUM(A3:B3)" },
|
|
{ "4", "8", "=SUM(A4:B4)" }
|
|
};
|
|
const ScAddress aOrgPos(0,0,0);
|
|
insertRangeData( m_pDoc, aOrgPos, aData);
|
|
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
|
|
ScAddress aPos( ScAddress::UNINITIALIZED);
|
|
|
|
// Check results in C1:C4
|
|
const double fVec0[] = { 0.0, 0.0, 3.0, 12.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec0[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
// Set up clip document.
|
|
ScDocument aClipDoc(SCDOCMODE_CLIP);
|
|
aClipDoc.ResetClip(m_pDoc, &aMark);
|
|
// Cut A3:B3 to clipboard.
|
|
cutToClip(*m_xDocShell, ScRange(0,2,0, 1,2,0), &aClipDoc, false);
|
|
|
|
// Check results in C1:C4 after Cut.
|
|
const double fVec1[] = { 0.0, 0.0, 0.0, 12.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec1[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
// Paste to A1:B1
|
|
ScRange aPasteRange(0,0,0, 1,0,0);
|
|
aMark.SetMarkArea(aPasteRange);
|
|
m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
|
|
|
|
// Check results in C1:C4 after Paste.
|
|
const double fVec2[] = { 3.0, 0.0, 3.0, 12.0 };
|
|
aPos = ScAddress(2,0,0);
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL( fVec2[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
// Check formulas in C1:C4 after Paste.
|
|
const std::u16string_view sForm[] = { u"=SUM(A1:B1)", u"=SUM(A2:B2)", u"=SUM(A1:B1)", u"=SUM(A4:B4)" };
|
|
for (SCROW i=0; i < 4; ++i)
|
|
{
|
|
OUString aFormula = m_pDoc->GetFormula( 2,i,0 );
|
|
CPPUNIT_ASSERT_EQUAL( OUString(sForm[i]), aFormula);
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
// tdf#120013
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaCutCopyMoveWithinRun)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Data in C3:E9
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "2200", "", "=SUM(C$3:C3)-SUM(D$3:D3)" },
|
|
{ "", "", "=SUM(C$3:C4)-SUM(D$3:D4)" },
|
|
{ "", "1900", "=SUM(C$3:C5)-SUM(D$3:D5)" },
|
|
{ "", "", "=SUM(C$3:C6)-SUM(D$3:D6)" },
|
|
{ "1600", "", "=SUM(C$3:C7)-SUM(D$3:D7)" },
|
|
{ "", "1000", "=SUM(C$3:C8)-SUM(D$3:D8)" },
|
|
{ "", "", "=SUM(C$3:C9)-SUM(D$3:D9)" }
|
|
};
|
|
const ScAddress aOrgPos(2,2,0);
|
|
insertRangeData( m_pDoc, aOrgPos, aData);
|
|
|
|
// Check that E3:E9 is a formula group.
|
|
const ScAddress aFormulaPos(4,2,0);
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( aFormulaPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW>(7), pFC->GetSharedLength());
|
|
|
|
ScAddress aPos( ScAddress::UNINITIALIZED);
|
|
|
|
// Check results in E3:E9
|
|
const double fVec0[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 900.0, 900.0 };
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec0), aData.size());
|
|
aPos = aFormulaPos;
|
|
for (size_t i=0; i < SAL_N_ELEMENTS(fVec0); ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9", fVec0[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
ScMarkData aMark(m_pDoc->GetSheetLimits());
|
|
aMark.SelectOneTable(0);
|
|
|
|
// Set up clip document.
|
|
ScDocument aClipDoc(SCDOCMODE_CLIP);
|
|
aClipDoc.ResetClip(m_pDoc, &aMark);
|
|
// Cut A8:D8 to clipboard.
|
|
cutToClip(*m_xDocShell, ScRange(0,7,0, 3,7,0), &aClipDoc, false);
|
|
|
|
// Check results in E3:E9 after Cut.
|
|
const double fVec1[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 1900.0, 1900.0 };
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec1), aData.size());
|
|
aPos = aFormulaPos;
|
|
for (size_t i=0; i < SAL_N_ELEMENTS(fVec1); ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Cut.", fVec1[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
// Paste to A4:D4
|
|
ScRange aPasteRange(0,3,0, 3,3,0);
|
|
aMark.SetMarkArea(aPasteRange);
|
|
m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
|
|
|
|
// Check results in E3:E9 after Paste.
|
|
const double fVec2[] = { 2200.0, 1200.0, -700.0, -700.0, 900.0, 900.0, 900.0 };
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec2), aData.size());
|
|
aPos = aFormulaPos;
|
|
for (size_t i=0; i < SAL_N_ELEMENTS(fVec2); ++i)
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Paste.", fVec2[i], m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
// tdf#129396
|
|
CPPUNIT_TEST_FIXTURE(TestSharedFormula, testSharedFormulaInsertShift)
|
|
{
|
|
sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
|
|
|
|
m_pDoc->InsertTab(0, u"Test"_ustr);
|
|
|
|
// Data in A1:C2
|
|
const std::vector<std::vector<const char*>> aData = {
|
|
{ "1", "2", "=SUM(A1:B1)" },
|
|
{ "4", "8", "=SUM(A2:B2)" }
|
|
};
|
|
const ScAddress aOrgPos(0,0,0);
|
|
insertRangeData( m_pDoc, aOrgPos, aData);
|
|
|
|
{
|
|
// Check that C1:C2 is a formula group.
|
|
const ScAddress aFormulaPos(2,0,0);
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( aFormulaPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
}
|
|
|
|
{
|
|
// Check results in C1:C2
|
|
ScAddress aPos( aOrgPos);
|
|
aPos.SetCol(2);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "C1", 3.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "C2", 12.0, m_pDoc->GetValue(aPos));
|
|
}
|
|
|
|
const bool bSuccess = m_pDoc->InsertCol( 0, 0, 1, 0, 2, 1);
|
|
CPPUNIT_ASSERT_MESSAGE( "InsertCol", bSuccess);
|
|
|
|
{
|
|
// Check that D1:D2 is a formula group.
|
|
const ScAddress aFormulaPos(3,0,0);
|
|
const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( aFormulaPos);
|
|
CPPUNIT_ASSERT(pFC);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos.Row(), pFC->GetSharedTopRow());
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW>(2), pFC->GetSharedLength());
|
|
}
|
|
|
|
{
|
|
// Modify values in B1:B2
|
|
ScAddress aPos( aOrgPos);
|
|
aPos.SetCol(1);
|
|
m_pDoc->SetValue(aPos, 16.0);
|
|
aPos.IncRow();
|
|
m_pDoc->SetValue(aPos, 32.0);
|
|
}
|
|
|
|
{
|
|
// Check results in D1:D2
|
|
ScAddress aPos( aOrgPos);
|
|
aPos.SetCol(3);
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "D1", 17.0, m_pDoc->GetValue(aPos));
|
|
aPos.IncRow();
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "D2", 36.0, m_pDoc->GetValue(aPos));
|
|
}
|
|
|
|
m_pDoc->DeleteTab(0);
|
|
}
|
|
|
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|