1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include <string_view>
13 #include "helper/debughelper.hxx"
14 #include "helper/qahelper.hxx"
15 #include <editutil.hxx>
16 #include <formulacell.hxx>
17 #include <cellvalue.hxx>
19 #include <undoblk.hxx>
20 #include <scopetools.hxx>
21 #include <docfunc.hxx>
22 #include <dbdocfun.hxx>
23 #include <tokenarray.hxx>
24 #include <tokenstringcontext.hxx>
25 #include <globalnames.hxx>
27 #include <bcaslot.hxx>
28 #include <sharedformula.hxx>
30 #include <svl/sharedstring.hxx>
31 #include <sfx2/docfile.hxx>
33 #include <formula/grammar.hxx>
35 void Test::testSharedFormulas()
37 m_pDoc
->InsertTab(0, "Test");
39 ScAddress
aPos(1, 9, 0); // B10
40 m_pDoc
->SetString(aPos
, "=A10*2"); // Insert into B10.
41 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(aPos
);
42 CPPUNIT_ASSERT_MESSAGE("Expected to be a non-shared cell.", pFC
&& !pFC
->IsShared());
44 aPos
.SetRow(10); // B11
45 m_pDoc
->SetString(aPos
, "=A11*2");
46 pFC
= m_pDoc
->GetFormulaCell(aPos
);
47 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
48 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(9), pFC
->GetSharedTopRow());
49 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
50 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
53 m_pDoc
->SetString(aPos
, "=A9*2");
54 pFC
= m_pDoc
->GetFormulaCell(aPos
);
55 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
56 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedTopRow());
57 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
58 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
60 aPos
.SetRow(12); // B13
61 m_pDoc
->SetString(aPos
, "=A13*2");
62 pFC
= m_pDoc
->GetFormulaCell(aPos
);
63 CPPUNIT_ASSERT_MESSAGE("This formula cell shouldn't be shared yet.", pFC
&& !pFC
->IsShared());
65 // Insert a formula to B12, and B9:B13 should be shared.
66 aPos
.SetRow(11); // B12
67 m_pDoc
->SetString(aPos
, "=A12*2");
68 pFC
= m_pDoc
->GetFormulaCell(aPos
);
69 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
70 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedTopRow());
71 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(5), pFC
->GetSharedLength());
72 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
74 // Insert formulas to B15:B16.
75 aPos
.SetRow(14); // B15
76 m_pDoc
->SetString(aPos
, "=A15*2");
77 aPos
.SetRow(15); // B16
78 m_pDoc
->SetString(aPos
, "=A16*2");
79 pFC
= m_pDoc
->GetFormulaCell(aPos
);
80 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
81 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(14), pFC
->GetSharedTopRow());
82 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
83 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
85 // Insert a formula to B14, and B9:B16 should be shared.
86 aPos
.SetRow(13); // B14
87 m_pDoc
->SetString(aPos
, "=A14*2");
88 pFC
= m_pDoc
->GetFormulaCell(aPos
);
89 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
90 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedTopRow());
91 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedLength());
92 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
94 // Insert an incompatible formula to B12, to split the shared range to B9:B11 and B13:B16.
95 aPos
.SetRow(11); // B12
96 m_pDoc
->SetString(aPos
, "=$A$1*4");
97 pFC
= m_pDoc
->GetFormulaCell(aPos
);
98 CPPUNIT_ASSERT_MESSAGE("This cell shouldn't be shared.", pFC
&& !pFC
->IsShared());
100 aPos
.SetRow(8); // B9
101 pFC
= m_pDoc
->GetFormulaCell(aPos
);
102 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
103 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedTopRow());
104 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
105 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
107 aPos
.SetRow(12); // B13
108 pFC
= m_pDoc
->GetFormulaCell(aPos
);
109 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
110 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), pFC
->GetSharedTopRow());
111 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
112 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
114 // Extend B13:B16 to B13:B20.
115 aPos
.SetRow(16); // B17
116 m_pDoc
->SetString(aPos
, "=A17*2");
118 m_pDoc
->SetString(aPos
, "=A18*2");
120 m_pDoc
->SetString(aPos
, "=A19*2");
122 m_pDoc
->SetString(aPos
, "=A20*2");
123 pFC
= m_pDoc
->GetFormulaCell(aPos
);
124 CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC
&& pFC
->IsShared());
125 // B13:B20 should be shared.
126 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), pFC
->GetSharedTopRow());
127 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedLength());
128 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
130 // Empty B19. This should split it into B13:B18, and B20 non-shared.
132 m_pDoc
->SetEmptyCell(aPos
);
133 CPPUNIT_ASSERT_EQUAL_MESSAGE("This cell should have been emptied.", CELLTYPE_NONE
, m_pDoc
->GetCellType(aPos
));
134 aPos
.SetRow(12); // B13
135 pFC
= m_pDoc
->GetFormulaCell(aPos
);
137 // B13:B18 should be shared.
138 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), pFC
->GetSharedTopRow());
139 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedLength());
140 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
141 // B20 should be non-shared.
142 aPos
.SetRow(19); // B20
143 pFC
= m_pDoc
->GetFormulaCell(aPos
);
144 CPPUNIT_ASSERT_MESSAGE("B20 should be a formula cell.", pFC
);
145 CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC
->IsShared());
147 // Empty B14, to make B13 non-shared and B15:B18 shared.
148 aPos
.SetRow(13); // B14
149 m_pDoc
->SetEmptyCell(aPos
);
150 aPos
.SetRow(12); // B13
151 pFC
= m_pDoc
->GetFormulaCell(aPos
);
152 // B13 should be non-shared.
153 CPPUNIT_ASSERT_MESSAGE("B13 should be a formula cell.", pFC
);
154 CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC
->IsShared());
155 // B15:B18 should be shared.
156 aPos
.SetRow(14); // B15
157 pFC
= m_pDoc
->GetFormulaCell(aPos
);
159 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(14), pFC
->GetSharedTopRow());
160 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
161 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
163 // Set numeric value to B15, to make B16:B18 shared.
165 m_pDoc
->SetValue(aPos
, 1.2);
167 pFC
= m_pDoc
->GetFormulaCell(aPos
);
169 // B16:B18 should be shared.
170 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(15), pFC
->GetSharedTopRow());
171 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
172 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
174 // Set string value to B16 to make B17:B18 shared.
176 ScCellValue
aCell(svl::SharedString("Test"));
177 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a string value.", CELLTYPE_STRING
, aCell
.meType
);
178 aCell
.commit(*m_pDoc
, aPos
);
179 CPPUNIT_ASSERT_EQUAL(aCell
.mpString
->getString(), m_pDoc
->GetString(aPos
));
181 pFC
= m_pDoc
->GetFormulaCell(aPos
);
183 // B17:B18 should be shared.
184 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(16), pFC
->GetSharedTopRow());
185 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
186 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
188 // Set edit text to B17. Now B18 should be non-shared.
189 ScFieldEditEngine
& rEditEngine
= m_pDoc
->GetEditEngine();
190 rEditEngine
.SetTextCurrentDefaults("Edit Text");
192 m_pDoc
->SetEditText(aPos
, rEditEngine
.CreateTextObject());
193 CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT
, m_pDoc
->GetCellType(aPos
));
195 pFC
= m_pDoc
->GetFormulaCell(aPos
);
196 CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC
);
197 CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC
->IsShared());
199 // Set up a new group for shared formulas in B2:B10.
200 clearRange(m_pDoc
, ScRange(0,0,0,2,100,0));
203 m_pDoc
->SetString(aPos
, "=A2*10");
205 m_pDoc
->SetString(aPos
, "=A3*10");
207 m_pDoc
->SetString(aPos
, "=A4*10");
209 m_pDoc
->SetString(aPos
, "=A5*10");
211 m_pDoc
->SetString(aPos
, "=A6*10");
213 m_pDoc
->SetString(aPos
, "=A7*10");
215 m_pDoc
->SetString(aPos
, "=A8*10");
217 m_pDoc
->SetString(aPos
, "=A9*10");
219 m_pDoc
->SetString(aPos
, "=A10*10");
221 pFC
= m_pDoc
->GetFormulaCell(aPos
);
222 CPPUNIT_ASSERT_MESSAGE("B10 should be a formula cell.", pFC
);
223 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
224 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(9), pFC
->GetSharedLength());
225 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
227 // Delete A4:B8. This should split the grouping to B2:B3 and B9:B10.
228 clearRange(m_pDoc
, ScRange(0,3,0,1,7,0));
230 pFC
= m_pDoc
->GetFormulaCell(aPos
);
231 CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC
);
232 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
233 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
234 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
237 pFC
= m_pDoc
->GetFormulaCell(aPos
);
238 CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC
);
239 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedTopRow());
240 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
241 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
243 // Delete rows 4:8 and shift row 9 and below up to row 4. This should
244 // re-merge the two into a group of B2:B5.
245 m_pDoc
->DeleteRow(ScRange(0,3,0,MAXCOL
,7,0));
247 pFC
= m_pDoc
->GetFormulaCell(aPos
);
248 CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC
);
249 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
250 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
251 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
253 // Insert 2 rows at row 4, to split it into B2:B3 and B6:B7.
254 m_pDoc
->InsertRow(ScRange(0,3,0,MAXCOL
,4,0));
255 pFC
= m_pDoc
->GetFormulaCell(aPos
);
256 CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC
);
257 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
258 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
259 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
262 pFC
= m_pDoc
->GetFormulaCell(aPos
);
263 CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC
);
264 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(5), pFC
->GetSharedTopRow());
265 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
266 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
268 // Test implicit intersection with shared formulas.
271 // Insert data in C1:D2 and formulas in E1:E2
272 const char* pData
[][3] = {
273 { "5", "1", "=C:C/D:D" },
274 { "4", "2", "=C:C/D:D" }
277 insertRangeData(m_pDoc
, aPos
, pData
, SAL_N_ELEMENTS(pData
));
280 pFC
= m_pDoc
->GetFormulaCell(aPos
);
281 CPPUNIT_ASSERT_MESSAGE("E2 should be a formula cell.", pFC
);
282 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
283 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
284 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
287 CPPUNIT_ASSERT_EQUAL_MESSAGE("5/1=5", 5.0, m_pDoc
->GetValue(aPos
));
289 CPPUNIT_ASSERT_EQUAL_MESSAGE("4/2=2", 2.0, m_pDoc
->GetValue(aPos
));
291 m_pDoc
->DeleteTab(0);
294 void Test::testSharedFormulasRefUpdate()
296 m_pDoc
->InsertTab(0, "Test");
298 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, false); // turn off auto calculation.
300 // Set values to A10:A12.
301 m_pDoc
->SetValue(ScAddress(0,9,0), 1);
302 m_pDoc
->SetValue(ScAddress(0,10,0), 2);
303 m_pDoc
->SetValue(ScAddress(0,11,0), 3);
306 // Insert formulas that reference A10:A12 in B1:B3.
307 const char* pData
[][1] = {
313 insertRangeData(m_pDoc
, ScAddress(1,0,0), pData
, SAL_N_ELEMENTS(pData
));
316 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
317 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "A11", "Wrong formula in B2");
318 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "A12", "Wrong formula in B3");
320 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
321 CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC
&& pFC
->IsShared());
322 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
323 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
325 // Insert cells over A11:B11 to shift to right. This should split the B1:B3 grouping into 3.
326 m_pDoc
->InsertCol(ScRange(0,10,0,1,10,0));
327 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
328 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "C11", "Wrong formula in B2");
329 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "A12", "Wrong formula in B3");
331 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
332 CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
333 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,1,0));
334 CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
335 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,2,0));
336 CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
338 // Delete cells over A11:B11 to bring it back to the previous state.
339 m_pDoc
->DeleteCol(ScRange(0,10,0,1,10,0));
341 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
342 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "A11", "Wrong formula in B2");
343 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "A12", "Wrong formula in B3");
345 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
346 CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC
&& pFC
->IsShared());
347 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
348 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
350 // Insert cells over A11:A12 and shift down.
351 m_pDoc
->InsertRow(ScRange(0,10,0,0,11,0));
352 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
353 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "A13", "Wrong formula in B2");
354 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "A14", "Wrong formula in B3");
356 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
357 CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
358 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,1,0));
359 CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC
&& pFC
->IsShared());
360 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
361 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
363 // Delete A11:A12 to bring it back to the way it was.
364 m_pDoc
->DeleteRow(ScRange(0,10,0,0,11,0));
366 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
367 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "A11", "Wrong formula in B2");
368 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "A12", "Wrong formula in B3");
370 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
371 CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC
&& pFC
->IsShared());
372 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
373 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
375 // Insert cells over A11:B11 to shift to right again.
376 m_pDoc
->InsertCol(ScRange(0,10,0,1,10,0));
377 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
378 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "C11", "Wrong formula in B2");
379 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "A12", "Wrong formula in B3");
381 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
382 CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
383 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,1,0));
384 CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
385 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,2,0));
386 CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
388 // Insert cells over A12:B12 to shift to right.
389 m_pDoc
->InsertCol(ScRange(0,11,0,1,11,0));
390 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "A10", "Wrong formula in B1");
391 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "C11", "Wrong formula in B2");
392 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "C12", "Wrong formula in B3");
394 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
395 CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC
&& !pFC
->IsShared());
396 // B2 and B3 should be grouped.
397 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,1,0));
398 CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC
&& pFC
->IsShared());
399 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
400 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
402 // Insert cells over A10:B10 to shift to right.
403 m_pDoc
->InsertCol(ScRange(0,9,0,1,9,0));
404 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "C10", "Wrong formula in B1");
405 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "C11", "Wrong formula in B2");
406 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "C12", "Wrong formula in B3");
408 // B1:B3 should be now grouped.
409 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
410 CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC
&& pFC
->IsShared());
411 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
412 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
414 m_pDoc
->DeleteTab(0);
417 void Test::testSharedFormulasRefUpdateMove()
419 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
420 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
422 m_pDoc
->InsertTab(0, "Test");
424 // Set values in B2:B4.
425 for (SCROW i
= 1; i
<= 3; ++i
)
426 m_pDoc
->SetValue(ScAddress(1,i
,0), i
);
428 // Make sure the values are really there.
429 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
430 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
431 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
433 const char* aData
[][1] = {
439 // Set formulas in C2:C4 that reference B2:B4 individually.
440 insertRangeData(m_pDoc
, ScAddress(2,1,0), aData
, SAL_N_ELEMENTS(aData
));
442 // Check the formula results.
443 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
444 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
445 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
447 // Move B2:B4 to B1:B3.
448 bool bMoved
= getDocShell().GetDocFunc().MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(1,0,0), true, true, false, true);
449 CPPUNIT_ASSERT(bMoved
);
451 // Make sure the values have been moved for real.
452 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
453 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
454 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
456 // The formulas should have been adjusted for the move.
457 CPPUNIT_ASSERT(checkFormula(*m_pDoc
, ScAddress(2,1,0), "R[-1]C[-1]"));
458 CPPUNIT_ASSERT(checkFormula(*m_pDoc
, ScAddress(2,2,0), "R[-1]C[-1]"));
459 CPPUNIT_ASSERT(checkFormula(*m_pDoc
, ScAddress(2,3,0), "R[-1]C[-1]"));
461 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
462 CPPUNIT_ASSERT(pUndoMgr
);
465 // The values should have moved back.
466 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
467 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
468 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
470 // And the formulas should have been re-adjusted to their original references.
471 CPPUNIT_ASSERT(checkFormula(*m_pDoc
, ScAddress(2,1,0), "RC[-1]"));
472 CPPUNIT_ASSERT(checkFormula(*m_pDoc
, ScAddress(2,2,0), "RC[-1]"));
473 CPPUNIT_ASSERT(checkFormula(*m_pDoc
, ScAddress(2,3,0), "RC[-1]"));
475 m_pDoc
->DeleteTab(0);
478 void Test::testSharedFormulasRefUpdateMove2()
480 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, false); // turn auto calc off this time.
481 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
483 m_pDoc
->InsertTab(0, "Test");
485 // Set values in B2:B3, and E2:E3.
486 for (SCROW i
= 1; i
<= 2; ++i
)
488 m_pDoc
->SetValue(ScAddress(1,i
,0), i
);
489 m_pDoc
->SetValue(ScAddress(4,i
,0), i
);
492 // Make sure the values are really there.
493 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
494 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
495 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(4,1,0)));
496 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(4,2,0)));
499 // Set formulas in C2:C3 that reference B2:B3 individually, and F2:F3 to E2:E3.
500 const char* pData
[][1] = {
505 insertRangeData(m_pDoc
, ScAddress(2,1,0), pData
, SAL_N_ELEMENTS(pData
));
506 insertRangeData(m_pDoc
, ScAddress(5,1,0), pData
, SAL_N_ELEMENTS(pData
));
509 m_pDoc
->CalcFormulaTree(); // calculate manually.
511 // Check the formula results.
512 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
513 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
514 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(5,1,0)));
515 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(5,2,0)));
517 // Move B2:C3 to C3:D4.
518 bool bMoved
= getDocShell().GetDocFunc().MoveBlock(
519 ScRange(1,1,0,2,2,0), ScAddress(2,2,0), true, true, false, true);
520 CPPUNIT_ASSERT(bMoved
);
522 // Make sure the range has been moved.
523 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
524 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
526 // The formula cells should retain their results even with auto calc off
527 // and without recalculation.
528 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(3,2,0)));
529 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(3,3,0)));
531 // And these formulas in F2:F3 are unaffected, therefore should not change.
532 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(5,1,0)));
533 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(5,2,0)));
535 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
536 CPPUNIT_ASSERT(pUndoMgr
);
541 // Check the formula results. The results should still be intact.
542 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
543 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
544 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(5,1,0)));
545 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(5,2,0)));
547 m_pDoc
->DeleteTab(0);
550 void Test::testSharedFormulasRefUpdateRange()
552 m_pDoc
->InsertTab(0, "Test");
554 // Insert values to A3:A5.
555 m_pDoc
->SetValue(ScAddress(0,2,0), 1);
556 m_pDoc
->SetValue(ScAddress(0,3,0), 2);
557 m_pDoc
->SetValue(ScAddress(0,4,0), 3);
560 // Insert formulas to B3:B5.
561 const char* pData
[][1] = {
562 { "=SUM($A$3:$A$5)" },
563 { "=SUM($A$3:$A$5)" },
564 { "=SUM($A$3:$A$5)" }
567 insertRangeData(m_pDoc
, ScAddress(1,2,0), pData
, SAL_N_ELEMENTS(pData
));
570 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "SUM($A$3:$A$5)", "Wrong formula");
571 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,3,0), "SUM($A$3:$A$5)", "Wrong formula");
572 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,4,0), "SUM($A$3:$A$5)", "Wrong formula");
574 // B3:B5 should be shared.
575 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,2,0));
576 CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC
&& pFC
->IsShared());
577 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,3,0));
578 CPPUNIT_ASSERT_MESSAGE("B4 should be shared.", pFC
&& pFC
->IsShared());
579 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,4,0));
580 CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC
&& pFC
->IsShared());
582 // Insert 2 rows at row 1.
583 m_pDoc
->InsertRow(ScRange(0,0,0,MAXCOL
,1,0));
585 // B5:B7 should be shared.
586 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,4,0));
587 CPPUNIT_ASSERT_MESSAGE("B5 should be shared.", pFC
&& pFC
->IsShared());
588 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,5,0));
589 CPPUNIT_ASSERT_MESSAGE("B6 should be shared.", pFC
&& pFC
->IsShared());
590 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,6,0));
591 CPPUNIT_ASSERT_MESSAGE("B7 should be shared.", pFC
&& pFC
->IsShared());
593 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedTopRow());
594 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
596 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,4,0), "SUM($A$5:$A$7)", "Wrong formula");
597 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,5,0), "SUM($A$5:$A$7)", "Wrong formula");
598 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,6,0), "SUM($A$5:$A$7)", "Wrong formula");
600 m_pDoc
->DeleteTab(0);
607 bool operator ()( const sc::AreaListener
& rLeft
, const sc::AreaListener
& rRight
) const
609 if (rLeft
.maArea
.aStart
.Tab() != rRight
.maArea
.aStart
.Tab())
610 return rLeft
.maArea
.aStart
.Tab() < rRight
.maArea
.aStart
.Tab();
612 if (rLeft
.maArea
.aStart
.Col() != rRight
.maArea
.aStart
.Col())
613 return rLeft
.maArea
.aStart
.Col() < rRight
.maArea
.aStart
.Col();
615 if (rLeft
.maArea
.aStart
.Row() != rRight
.maArea
.aStart
.Row())
616 return rLeft
.maArea
.aStart
.Row() < rRight
.maArea
.aStart
.Row();
618 if (rLeft
.maArea
.aEnd
.Tab() != rRight
.maArea
.aEnd
.Tab())
619 return rLeft
.maArea
.aEnd
.Tab() < rRight
.maArea
.aEnd
.Tab();
621 if (rLeft
.maArea
.aEnd
.Col() != rRight
.maArea
.aEnd
.Col())
622 return rLeft
.maArea
.aEnd
.Col() < rRight
.maArea
.aEnd
.Col();
624 return rLeft
.maArea
.aEnd
.Row() < rRight
.maArea
.aEnd
.Row();
630 void Test::testSharedFormulasRefUpdateRangeDeleteRow()
632 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
633 m_pDoc
->InsertTab(0, "Formula");
635 ScRange
aWholeArea(0, 0, 0, 100, 100, 0); // Large enough for all references used in the test.
637 const char* aData
[][3] = {
638 { "1", "2", "=SUM(A1:B1)" },
639 { "3", "4", "=SUM(A2:B2)" },
640 { nullptr, nullptr, nullptr },
641 { "5", "6", "=SUM(A4:B4)" },
642 { "7", "8", "=SUM(A5:B5)" }
645 insertRangeData(m_pDoc
, ScAddress(0,0,0), aData
, SAL_N_ELEMENTS(aData
));
647 // Check initial formula values.
648 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
649 CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
650 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
651 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
653 // Check the area listener status.
654 ScBroadcastAreaSlotMachine
* pBASM
= m_pDoc
->GetBASM();
655 CPPUNIT_ASSERT(pBASM
);
656 std::vector
<sc::AreaListener
> aListeners
= pBASM
->GetAllListeners(aWholeArea
, sc::AreaOverlapType::Inside
);
657 std::sort(aListeners
.begin(), aListeners
.end(), SortByArea());
659 // This check makes only sense if group listeners are activated.
660 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
661 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be 2 area listeners.", size_t(2), aListeners
.size());
662 // First one should be group-listening on A1:B2.
663 CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners
[0].maArea
);
664 CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners
[0].mbGroupListening
);
665 // Second one should be group-listening on A4:B5.
666 CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners
[0].maArea
);
667 CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners
[0].mbGroupListening
);
670 // Make sure that C1:C2 and C4:C5 are formula groups.
671 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
673 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
674 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
676 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,3,0));
678 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedTopRow());
679 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
681 // Delete row 3. This will merge the two formula groups.
682 ScDocFunc
& rFunc
= getDocShell().GetDocFunc();
683 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
684 aMark
.SelectOneTable(0);
685 rFunc
.DeleteCells(ScRange(0,2,0,MAXCOL
,2,0), &aMark
, DelCellCmd::Rows
, true);
687 // Make sure C1:C4 belong to the same group.
688 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
690 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
691 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
693 // This check makes only sense if group listeners are activated.
694 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
695 // We should only have one listener group-listening on A1:B4.
696 aListeners
= pBASM
->GetAllListeners(aWholeArea
, sc::AreaOverlapType::Inside
);
697 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be 1 area listener.", size_t(1), aListeners
.size());
698 CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B4.", ScRange(0,0,0,1,3,0), aListeners
[0].maArea
);
699 CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners
[0].mbGroupListening
);
702 // Change the value of B4 and make sure the value of C4 changes.
703 rFunc
.SetValueCell(ScAddress(1,3,0), 100.0, false);
704 CPPUNIT_ASSERT_EQUAL(107.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
706 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
707 CPPUNIT_ASSERT(pUndoMgr
);
709 // Undo the value change in B4, and make sure C4 follows.
711 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
713 // Undo the deletion of row 3.
716 // Make sure that C1:C2 and C4:C5 are formula groups again.
717 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
719 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
720 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
722 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,3,0));
724 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedTopRow());
725 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
727 // Check the values of formula cells again.
728 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
729 CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
730 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
731 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
733 aListeners
= pBASM
->GetAllListeners(aWholeArea
, sc::AreaOverlapType::Inside
);
734 std::sort(aListeners
.begin(), aListeners
.end(), SortByArea());
736 // This check makes only sense if group listeners are activated.
737 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
738 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be 2 area listeners.", size_t(2), aListeners
.size());
739 // First one should be group-listening on A1:B2.
740 CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners
[0].maArea
);
741 CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners
[0].mbGroupListening
);
742 // Second one should be group-listening on A4:B5.
743 CPPUNIT_ASSERT_EQUAL_MESSAGE("This listener should be listening on A1:B2.", ScRange(0,0,0,1,1,0), aListeners
[0].maArea
);
744 CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners
[0].mbGroupListening
);
747 m_pDoc
->DeleteTab(0);
750 void Test::testSharedFormulasRefUpdateExternal()
752 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
753 m_pDoc
->InsertTab(0, "Formula");
755 // Launch an external document shell.
756 ScDocShellRef xExtDocSh
= new ScDocShell
;
757 xExtDocSh
->SetIsInUcalc();
759 SfxMedium
* pMed
= new SfxMedium("file:///extdata.fake", StreamMode::STD_READWRITE
);
760 xExtDocSh
->DoInitNew(pMed
);
761 ScDocument
& rExtDoc
= xExtDocSh
->GetDocument();
764 rExtDoc
.InsertTab(0, "Data");
765 rExtDoc
.SetString(ScAddress(0,0,0), "A");
766 rExtDoc
.SetString(ScAddress(0,1,0), "B");
767 rExtDoc
.SetString(ScAddress(0,2,0), "C");
770 // Insert formula cells in A7:A10 of the host document, referencing A1:A3
771 // of the external document.
772 const char* pData
[][1] = {
773 { "='file:///extdata.fake'#$Data.A1" },
774 { "='file:///extdata.fake'#$Data.A2" },
775 { "='file:///extdata.fake'#$Data.A3" },
776 { "=COUNTA('file:///extdata.fake'#$Data.A1:A3)" }
779 insertRangeData(m_pDoc
, ScAddress(0,6,0), pData
, SAL_N_ELEMENTS(pData
));
782 // Check the formula results.
783 CPPUNIT_ASSERT_EQUAL(OUString("A"), m_pDoc
->GetString(ScAddress(0,6,0)));
784 CPPUNIT_ASSERT_EQUAL(OUString("B"), m_pDoc
->GetString(ScAddress(0,7,0)));
785 CPPUNIT_ASSERT_EQUAL(OUString("C"), m_pDoc
->GetString(ScAddress(0,8,0)));
786 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
788 // Check the formulas too.
789 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A1", "Wrong formula!");
790 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,7,0), "'file:///extdata.fake'#$Data.A2", "Wrong formula!");
791 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,8,0), "'file:///extdata.fake'#$Data.A3", "Wrong formula!");
792 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,9,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)", "Wrong formula!");
794 // Delete rows 1 and 2. This should not change the references in the formula cells below.
795 ScDocFunc
& rDocFunc
= getDocShell().GetDocFunc();
796 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
797 aMark
.SelectOneTable(0);
798 rDocFunc
.DeleteCells(ScRange(0,0,0,MAXCOL
,1,0), &aMark
, DelCellCmd::CellsUp
, true);
800 // Check the shifted formula cells now in A5:A8.
801 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,4,0), "'file:///extdata.fake'#$Data.A1", "Wrong formula!");
802 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,5,0), "'file:///extdata.fake'#$Data.A2", "Wrong formula!");
803 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A3", "Wrong formula!");
804 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,7,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)", "Wrong formula!");
806 // Undo and check the formulas again.
807 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
808 CPPUNIT_ASSERT(pUndoMgr
);
810 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A1", "Wrong formula!");
811 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,7,0), "'file:///extdata.fake'#$Data.A2", "Wrong formula!");
812 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,8,0), "'file:///extdata.fake'#$Data.A3", "Wrong formula!");
813 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,9,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)", "Wrong formula!");
815 // Redo the row deletion and check the formulas again.
817 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,4,0), "'file:///extdata.fake'#$Data.A1", "Wrong formula!");
818 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,5,0), "'file:///extdata.fake'#$Data.A2", "Wrong formula!");
819 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A3", "Wrong formula!");
820 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,7,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)", "Wrong formula!");
822 xExtDocSh
->DoClose();
824 m_pDoc
->DeleteTab(0);
827 void Test::testSharedFormulasInsertRow()
831 bool checkContent( ScDocument
* pDoc
)
833 // B1:B2 and B4:B5 should point to $A$5.
834 SCROW pRows
[] = { 0, 1, 3, 4 };
835 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pRows
); ++i
)
837 ScAddress
aPos(1, pRows
[i
], 0);
838 ASSERT_FORMULA_EQUAL(*pDoc
, aPos
, "$A$5", "Wrong formula!");
841 // B1:B2 should be grouped.
842 ScFormulaCell
* pFC
= pDoc
->GetFormulaCell(ScAddress(1,0,0));
843 if (!pFC
|| pFC
->GetSharedTopRow() != 0 || pFC
->GetSharedLength() != 2)
845 cerr
<< "B1:B2 should be grouped." << endl
;
849 // B4:B5 should be grouped.
850 pFC
= pDoc
->GetFormulaCell(ScAddress(1,3,0));
851 if (!pFC
|| pFC
->GetSharedTopRow() != 3 || pFC
->GetSharedLength() != 2)
853 cerr
<< "B4:B5 should be grouped." << endl
;
860 bool checkContentUndo( ScDocument
* pDoc
)
862 for (SCROW i
= 0; i
<= 3; ++i
)
864 ScAddress
aPos(1,i
,0);
865 ASSERT_FORMULA_EQUAL(*pDoc
, aPos
, "$A$4", "Wrong formula!");
868 // Ensure that B5 is empty.
869 if (pDoc
->GetCellType(ScAddress(1,4,0)) != CELLTYPE_NONE
)
871 cerr
<< "B5 should be empty." << endl
;
875 // B1:B4 should be grouped.
876 ScFormulaCell
* pFC
= pDoc
->GetFormulaCell(ScAddress(1,0,0));
877 if (!pFC
|| pFC
->GetSharedTopRow() != 0 || pFC
->GetSharedLength() != 4)
879 cerr
<< "B1:B4 should be grouped." << endl
;
888 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
889 m_pDoc
->InsertTab(0, "Test");
891 // Scenario inspired by fdo#76470.
894 m_pDoc
->SetValue(ScAddress(0,3,0), 4.0);
897 // Set formula cells in B1:B4 all referencing A4 as absolute reference.
898 const char* pData
[][1] = {
905 insertRangeData(m_pDoc
, ScAddress(1,0,0), pData
, SAL_N_ELEMENTS(pData
));
908 // Insert a new row at row 3.
909 ScDocFunc
& rFunc
= getDocShell().GetDocFunc();
910 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
911 aMark
.SelectOneTable(0);
912 rFunc
.InsertCells(ScRange(0,2,0,MAXCOL
,2,0), &aMark
, INS_INSROWS_BEFORE
, true, true);
914 bool bResult
= aCheck
.checkContent(m_pDoc
);
915 CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bResult
);
917 // Undo and check its result.
918 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
919 CPPUNIT_ASSERT(pUndoMgr
);
922 bResult
= aCheck
.checkContentUndo(m_pDoc
);
923 CPPUNIT_ASSERT_MESSAGE("Failed on the content check after undo.", bResult
);
925 // Redo and check its result.
927 bResult
= aCheck
.checkContent(m_pDoc
);
928 CPPUNIT_ASSERT_MESSAGE("Failed on the content check after redo.", bResult
);
930 m_pDoc
->DeleteTab(0);
933 void Test::testSharedFormulasDeleteRows()
935 m_pDoc
->InsertTab(0, "Test");
936 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
939 // Fill data cells A1:A20 and formula cells B1:B20. Formulas in
940 // B1:B10 and B11:B20 should be different.
941 const char* pData
[][2] = {
942 { "0", "=RC[-1]+1" },
943 { "1", "=RC[-1]+1" },
944 { "2", "=RC[-1]+1" },
945 { "3", "=RC[-1]+1" },
946 { "4", "=RC[-1]+1" },
947 { "5", "=RC[-1]+1" },
948 { "6", "=RC[-1]+1" },
949 { "7", "=RC[-1]+1" },
950 { "8", "=RC[-1]+1" },
951 { "9", "=RC[-1]+1" },
952 { "10", "=RC[-1]+11" },
953 { "11", "=RC[-1]+11" },
954 { "12", "=RC[-1]+11" },
955 { "13", "=RC[-1]+11" },
956 { "14", "=RC[-1]+11" },
957 { "15", "=RC[-1]+11" },
958 { "16", "=RC[-1]+11" },
959 { "17", "=RC[-1]+11" },
960 { "18", "=RC[-1]+11" },
961 { "19", "=RC[-1]+11" }
964 insertRangeData(m_pDoc
, ScAddress(0,0,0), pData
, SAL_N_ELEMENTS(pData
));
967 // B1:B10 should be shared.
968 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
969 CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC
&& pFC
->IsShared());
970 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
971 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(10), pFC
->GetSharedLength());
972 // B11:B20 should be shared.
973 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,10,0));
974 CPPUNIT_ASSERT_MESSAGE("1,10 must be a shared formula cell.", pFC
&& pFC
->IsShared());
975 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(10), pFC
->GetSharedTopRow());
976 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(10), pFC
->GetSharedLength());
979 m_pDoc
->DeleteRow(ScRange(0,8,0,MAXCOL
,11,0));
981 // B1:B8 should be shared.
982 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
983 CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC
&& pFC
->IsShared());
984 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
985 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedLength());
986 // B9:B16 should be shared.
987 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,8,0));
988 CPPUNIT_ASSERT_MESSAGE("1,8 must be a shared formula cell.", pFC
&& pFC
->IsShared());
989 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedTopRow());
990 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedLength());
993 m_pDoc
->DeleteRow(ScRange(0,2,0,MAXCOL
,2,0));
995 // B1:B7 should be shared.
996 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
997 CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC
&& pFC
->IsShared());
998 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
999 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(7), pFC
->GetSharedLength());
1000 // B8:B15 should be shared.
1001 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,7,0));
1002 CPPUNIT_ASSERT_MESSAGE("1,7 must be a shared formula cell.", pFC
&& pFC
->IsShared());
1003 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(7), pFC
->GetSharedTopRow());
1004 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedLength());
1007 m_pDoc
->DeleteRow(ScRange(0,4,0,MAXCOL
,4,0));
1009 // B1:B6 should be shared.
1010 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
1011 CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC
&& pFC
->IsShared());
1012 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
1013 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedLength());
1014 // B7:B14 should be shared.
1015 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,6,0));
1016 CPPUNIT_ASSERT_MESSAGE("1,6 must be a shared formula cell.", pFC
&& pFC
->IsShared());
1017 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
1018 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(8), pFC
->GetSharedLength());
1021 void Test::testSharedFormulasDeleteColumns()
1023 using namespace formula
;
1025 m_pDoc
->InsertTab(0, "Test");
1027 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
1028 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1030 ScDocFunc
& rFunc
= getDocShell().GetDocFunc();
1031 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
1032 aMark
.SelectOneTable(0);
1034 // First, test a single cell case. A value in B1 and formula in C1.
1035 m_pDoc
->SetValue(ScAddress(1,0,0), 11.0);
1036 m_pDoc
->SetString(ScAddress(2,0,0), "=RC[-1]");
1037 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
1040 rFunc
.DeleteCells(ScRange(1,0,0,1,MAXROW
,0), &aMark
, DelCellCmd::CellsLeft
, true);
1041 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(1,0,0)));
1043 // The reference should still point to row 1 but the column status should be set to 'deleted'.
1044 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
1045 CPPUNIT_ASSERT(pFC
);
1046 const ScTokenArray
* pCode
= pFC
->GetCode();
1047 CPPUNIT_ASSERT(pCode
&& pCode
->GetLen() == 1);
1048 const FormulaToken
* pToken
= pCode
->GetArray()[0];
1049 CPPUNIT_ASSERT_EQUAL(svSingleRef
, pToken
->GetType());
1050 const ScSingleRefData
* pSRef
= pToken
->GetSingleRef();
1051 CPPUNIT_ASSERT(pSRef
->IsColDeleted());
1052 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pSRef
->toAbs(*m_pDoc
, ScAddress(1,0,0)).Row());
1054 // The formula string should show #REF! in lieu of the column position (only for Calc A1 syntax).
1055 sc::CompileFormulaContext
aCFCxt(*m_pDoc
, FormulaGrammar::GRAM_ENGLISH
);
1056 CPPUNIT_ASSERT_EQUAL(OUString("=#REF!1"), pFC
->GetFormula(aCFCxt
));
1058 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
1059 CPPUNIT_ASSERT(pUndoMgr
);
1061 // Undo and make sure the deleted flag is gone.
1063 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
1064 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
1065 CPPUNIT_ASSERT(pFC
);
1066 CPPUNIT_ASSERT_EQUAL(OUString("=B1"), pFC
->GetFormula(aCFCxt
));
1068 // Clear row 1 and move over to a formula group case.
1069 clearRange(m_pDoc
, ScRange(0,0,0,MAXCOL
,0,0));
1071 // Fill A1:B2 with numbers, and C1:C2 with formula that reference those numbers.
1072 for (SCROW i
= 0; i
<= 1; ++i
)
1074 m_pDoc
->SetValue(ScAddress(0,i
,0), (i
+1));
1075 m_pDoc
->SetValue(ScAddress(1,i
,0), (i
+11));
1076 m_pDoc
->SetString(ScAddress(2,i
,0), "=RC[-2]+RC[-1]");
1077 double fCheck
= m_pDoc
->GetValue(ScAddress(0,i
,0));
1078 fCheck
+= m_pDoc
->GetValue(ScAddress(1,i
,0));
1079 CPPUNIT_ASSERT_EQUAL(fCheck
, m_pDoc
->GetValue(ScAddress(2,i
,0)));
1083 rFunc
.DeleteCells(ScRange(1,0,0,1,MAXROW
,0), &aMark
, DelCellCmd::CellsLeft
, true);
1085 for (SCROW i
= 0; i
<= 1; ++i
)
1087 ScAddress
aPos(1,i
,0);
1088 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(aPos
));
1091 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0)); // B1
1092 CPPUNIT_ASSERT(pFC
);
1093 CPPUNIT_ASSERT_EQUAL(OUString("=A1+#REF!1"), pFC
->GetFormula(aCFCxt
));
1094 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,1,0)); // B2
1095 CPPUNIT_ASSERT(pFC
);
1096 CPPUNIT_ASSERT_EQUAL(OUString("=A2+#REF!2"), pFC
->GetFormula(aCFCxt
));
1098 // Undo deletion of column B and check the results of C1:C2.
1100 for (SCROW i
= 0; i
<= 1; ++i
)
1102 double fCheck
= m_pDoc
->GetValue(ScAddress(0,i
,0));
1103 fCheck
+= m_pDoc
->GetValue(ScAddress(1,i
,0));
1104 CPPUNIT_ASSERT_EQUAL(fCheck
, m_pDoc
->GetValue(ScAddress(2,i
,0)));
1107 m_pDoc
->DeleteTab(0);
1110 void Test::testSharedFormulasRefUpdateMoveSheets()
1112 m_pDoc
->InsertTab(0, "Sheet1");
1113 m_pDoc
->InsertTab(1, "Sheet2");
1114 m_pDoc
->InsertTab(2, "Sheet3");
1116 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // make sure auto calc is on.
1118 // Switch to R1C1 for ease of repeated formula insertions.
1119 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1121 // Fill numbers in A1:A8 on Sheet2.
1122 for (SCROW i
= 0; i
<= 7; ++i
)
1123 m_pDoc
->SetValue(ScAddress(0,i
,1), i
+1);
1125 // Fill formula cells A1:A8 on Sheet1, to refer to the same cell address on Sheet2.
1126 for (SCROW i
= 0; i
<= 7; ++i
)
1127 m_pDoc
->SetString(ScAddress(0,i
,0), "=Sheet2!RC");
1129 // Check the results.
1130 for (SCROW i
= 0; i
<= 7; ++i
)
1131 CPPUNIT_ASSERT_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(ScAddress(0,i
,0)));
1133 // Move Sheet3 to the leftmost position before Sheet1.
1134 m_pDoc
->MoveTab(2, 0);
1136 // Check sheet names.
1137 std::vector
<OUString
> aTabNames
= m_pDoc
->GetAllTableNames();
1138 CPPUNIT_ASSERT_MESSAGE("There should be at least 3 sheets.", aTabNames
.size() >= 3);
1139 CPPUNIT_ASSERT_EQUAL(OUString("Sheet3"), aTabNames
[0]);
1140 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aTabNames
[1]);
1141 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aTabNames
[2]);
1143 // Check the results again on Sheet1.
1144 for (SCROW i
= 0; i
<= 7; ++i
)
1146 CPPUNIT_ASSERT_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(ScAddress(0,i
,1)));
1147 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,i
,1), "Sheet2!RC", "Wrong formula expression.");
1150 // Insert a new sheet at the left end.
1151 m_pDoc
->InsertTab(0, "Sheet4");
1153 // Check sheet names.
1154 aTabNames
= m_pDoc
->GetAllTableNames();
1155 CPPUNIT_ASSERT_MESSAGE("There should be at least 4 sheets.", aTabNames
.size() >= 4);
1156 CPPUNIT_ASSERT_EQUAL(OUString("Sheet4"), aTabNames
[0]);
1157 CPPUNIT_ASSERT_EQUAL(OUString("Sheet3"), aTabNames
[1]);
1158 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aTabNames
[2]);
1159 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aTabNames
[3]);
1161 // Check the results again on Sheet1.
1162 for (SCROW i
= 0; i
<= 7; ++i
)
1164 CPPUNIT_ASSERT_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(ScAddress(0,i
,2)));
1165 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,i
,2), "Sheet2!RC", "Wrong formula expression.");
1169 m_pDoc
->DeleteTab(0);
1171 // Check sheet names.
1172 aTabNames
= m_pDoc
->GetAllTableNames();
1173 CPPUNIT_ASSERT_MESSAGE("There should be at least 3 sheets.", aTabNames
.size() >= 3);
1174 CPPUNIT_ASSERT_EQUAL(OUString("Sheet3"), aTabNames
[0]);
1175 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aTabNames
[1]);
1176 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aTabNames
[2]);
1178 // Check the results again on Sheet1.
1179 for (SCROW i
= 0; i
<= 7; ++i
)
1181 CPPUNIT_ASSERT_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(ScAddress(0,i
,1)));
1182 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,i
,1), "Sheet2!RC", "Wrong formula expression.");
1185 m_pDoc
->DeleteTab(2);
1186 m_pDoc
->DeleteTab(1);
1187 m_pDoc
->DeleteTab(0);
1190 void Test::testSharedFormulasRefUpdateCopySheets()
1192 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // make sure auto calc is on.
1194 m_pDoc
->InsertTab(0, "Sheet1");
1195 m_pDoc
->InsertTab(1, "Sheet2");
1197 m_pDoc
->SetValue(ScAddress(0,0,1), 1.0); // A1 on Sheet2
1198 m_pDoc
->SetValue(ScAddress(0,1,1), 2.0); // A2 on Sheet2
1200 // Reference values on Sheet2, but use absolute sheet references.
1201 m_pDoc
->SetString(ScAddress(0,0,0), "=$Sheet2.A1");
1202 m_pDoc
->SetString(ScAddress(0,1,0), "=$Sheet2.A2");
1204 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
1205 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1207 // Copy Sheet1 and insert the copied sheet before the current Sheet1 position.
1208 m_pDoc
->CopyTab(0, 0);
1210 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,0,0), "$Sheet2.A1", "Wrong formula");
1211 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,1,0), "$Sheet2.A2", "Wrong formula");
1213 // Check the values on the copied sheet.
1214 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
1215 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1217 // Check the values on the original sheet.
1218 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,1)));
1219 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,1)));
1221 m_pDoc
->DeleteTab(2);
1222 m_pDoc
->DeleteTab(1);
1223 m_pDoc
->DeleteTab(0);
1226 void Test::testSharedFormulasRefUpdateDeleteSheets()
1228 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // make sure auto calc is on.
1230 m_pDoc
->InsertTab(0, "Sheet1");
1231 m_pDoc
->InsertTab(1, "Sheet2");
1233 // Set values to B2:B4 on Sheet2.
1234 m_pDoc
->SetValue(ScAddress(1,1,1), 1.0);
1235 m_pDoc
->SetValue(ScAddress(1,2,1), 2.0);
1236 m_pDoc
->SetValue(ScAddress(1,3,1), 3.0);
1238 // Set formulas in A1:A3 on Sheet1 that reference B2:B4 on Sheet2.
1239 m_pDoc
->SetString(ScAddress(0,0,0), "=Sheet2.B2");
1240 m_pDoc
->SetString(ScAddress(0,1,0), "=Sheet2.B3");
1241 m_pDoc
->SetString(ScAddress(0,2,0), "=Sheet2.B4");
1243 // Check the formula results.
1244 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
1245 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1246 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
1248 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,0,0), "Sheet2.B2", "Wrong formula");
1249 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,1,0), "Sheet2.B3", "Wrong formula");
1250 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,2,0), "Sheet2.B4", "Wrong formula");
1253 ScDocFunc
& rFunc
= getDocShell().GetDocFunc();
1254 rFunc
.DeleteTable(1, true);
1256 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,0,0), "#REF!.B2", "Wrong formula");
1257 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,1,0), "#REF!.B3", "Wrong formula");
1258 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,2,0), "#REF!.B4", "Wrong formula");
1260 // Undo the deletion and make sure the formulas are back to the way they were.
1261 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
1262 CPPUNIT_ASSERT(pUndoMgr
);
1265 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,0,0), "Sheet2.B2", "Wrong formula");
1266 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,1,0), "Sheet2.B3", "Wrong formula");
1267 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(0,2,0), "Sheet2.B4", "Wrong formula");
1269 // TODO: We can't test redo yet as ScUndoDeleteTab::Redo() relies on
1270 // view shell to do its thing.
1272 m_pDoc
->DeleteTab(1);
1273 m_pDoc
->DeleteTab(0);
1276 void Test::testSharedFormulasCopyPaste()
1278 m_pDoc
->InsertTab(0, "Test");
1279 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1281 // Fill formula cells B1:B10.
1282 for (SCROW i
= 0; i
<= 9; ++i
)
1283 m_pDoc
->SetString(1, i
, 0, "=RC[-1]");
1285 ScAddress
aPos(1, 8, 0); // B9
1286 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(aPos
);
1287 CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC
);
1288 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
1289 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(10), pFC
->GetSharedLength());
1290 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
1292 // Copy formulas in B6:B9 to the clipboard doc.
1293 ScRange
aSrcRange(1,5,0,1,8,0); // B6:B9
1294 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
1295 copyToClip(m_pDoc
, aSrcRange
, &aClipDoc
);
1296 pFC
= aClipDoc
.GetFormulaCell(aPos
);
1297 CPPUNIT_ASSERT_MESSAGE("B9 in the clip doc should be a formula cell.", pFC
);
1298 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(5), pFC
->GetSharedTopRow());
1299 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
1300 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
1302 // Paste them to C2:C10.
1303 ScRange
aDestRange(2,1,0,2,9,0);
1304 pasteFromClip(m_pDoc
, aDestRange
, &aClipDoc
);
1307 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1308 CPPUNIT_ASSERT_MESSAGE("C2 should be a formula cell.", pFC
);
1309 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
1310 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(9), pFC
->GetSharedLength());
1311 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
1313 ScRange
aRange(1,0,0,1,9,0); // B1:B10
1314 ScDocument
* pUndoDoc
= new ScDocument(SCDOCMODE_UNDO
);
1315 pUndoDoc
->InitUndo(*m_pDoc
, 0, 0, true, true);
1316 m_pDoc
->CopyToDocument(aRange
, InsertDeleteFlags::CONTENTS
, false, *pUndoDoc
);
1317 std::unique_ptr
<ScUndoPaste
> pUndo(createUndoPaste(getDocShell(), aRange
, ScDocumentUniquePtr(pUndoDoc
)));
1319 // First, make sure the formula cells are shared in the undo document.
1321 for (SCROW i
= 0; i
<= 9; ++i
)
1324 pFC
= pUndoDoc
->GetFormulaCell(aPos
);
1325 CPPUNIT_ASSERT_MESSAGE("Must be a formula cell.", pFC
);
1326 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
1327 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(10), pFC
->GetSharedLength());
1328 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
1331 // Overwrite B1:B10.
1332 for (SCROW i
= 0; i
<= 9; ++i
)
1333 m_pDoc
->SetValue(ScAddress(1,i
,0), i
*10);
1335 for (SCROW i
= 0; i
<= 9; ++i
)
1336 CPPUNIT_ASSERT_EQUAL_MESSAGE("Numeric cell was expected.", CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,i
,0)));
1338 // Undo the action to fill B1:B10 with formula cells again.
1342 for (SCROW i
= 0; i
<= 9; ++i
)
1345 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1346 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC
);
1347 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
1348 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(10), pFC
->GetSharedLength());
1349 CPPUNIT_ASSERT_EQUAL_MESSAGE("The token is expected to be shared.", pFC
->GetCode(), pFC
->GetSharedCode());
1352 m_pDoc
->DeleteTab(0);
1355 void Test::testSharedFormulaInsertColumn()
1357 m_pDoc
->InsertTab(0, "Test");
1359 // Set shared formula group over H2:H3.
1360 m_pDoc
->SetString(ScAddress(7,1,0), "=G3*B3");
1361 m_pDoc
->SetString(ScAddress(7,2,0), "=G4*B4");
1363 // Insert a single column at Column F. This used to crash before fdo#74041.
1364 m_pDoc
->InsertCol(ScRange(5,0,0,5,MAXROW
,0));
1366 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(8,1,0), "H3*B3", "Wrong formula!");
1367 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(8,2,0), "H4*B4", "Wrong formula!");
1369 m_pDoc
->DeleteTab(0);
1372 void Test::testSharedFormulaMoveBlock()
1374 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
1375 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1377 m_pDoc
->InsertTab(0, "Test");
1379 // Set values to A1:A3.
1380 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
1381 m_pDoc
->SetValue(ScAddress(0,1,0), 2.0);
1382 m_pDoc
->SetValue(ScAddress(0,2,0), 3.0);
1384 // Set formulas in B1:B3 to reference A1:A3.
1385 m_pDoc
->SetString(ScAddress(1,0,0), "=RC[-1]");
1386 m_pDoc
->SetString(ScAddress(1,1,0), "=RC[-1]");
1387 m_pDoc
->SetString(ScAddress(1,2,0), "=RC[-1]");
1389 ScRange
aFormulaRange(1,0,0,1,2,0);
1391 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1392 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1393 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1395 clearFormulaCellChangedFlag(*m_pDoc
, aFormulaRange
);
1397 // Move A1:A3 to D1:D3.
1398 ScDocFunc
& rFunc
= getDocShell().GetDocFunc();
1399 bool bMoved
= rFunc
.MoveBlock(ScRange(0,0,0,0,2,0), ScAddress(3,0,0), true, true, false, true);
1400 CPPUNIT_ASSERT(bMoved
);
1402 // The result should stay the same.
1403 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1404 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1405 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1407 clearFormulaCellChangedFlag(*m_pDoc
, aFormulaRange
);
1409 // Make sure these formula cells in B1:B3 have correct positions even after the move.
1410 std::vector
<SCROW
> aRows
;
1414 bool bRes
= checkFormulaPositions(*m_pDoc
, 0, 1, aRows
.data(), aRows
.size());
1415 CPPUNIT_ASSERT(bRes
);
1417 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
1418 CPPUNIT_ASSERT(pUndoMgr
);
1420 // Undo and check the result.
1422 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1423 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1424 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1426 clearFormulaCellChangedFlag(*m_pDoc
, aFormulaRange
);
1428 // Redo and check the result.
1430 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1431 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1432 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1434 // Clear the range and start over.
1435 clearRange(m_pDoc
, ScRange(0,0,0,MAXCOL
,MAXROW
,0));
1437 // Set values 1,2,3,4,5 to A1:A5.
1438 for (SCROW i
= 0; i
<= 4; ++i
)
1439 m_pDoc
->SetValue(ScAddress(0,i
,0), (i
+1));
1441 // Set formulas to B1:B5.
1442 for (SCROW i
= 0; i
<= 4; ++i
)
1443 m_pDoc
->SetString(ScAddress(1,i
,0), "=RC[-1]");
1445 // Check the initial formula results.
1446 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1447 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1448 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1449 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
1450 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
1452 // Move A1:A2 to D2:D3.
1453 bMoved
= rFunc
.MoveBlock(ScRange(0,0,0,0,1,0), ScAddress(3,1,0), true, true, false, true);
1454 CPPUNIT_ASSERT(bMoved
);
1456 // Check the formula values again. They should not change.
1457 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1458 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1459 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1460 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
1461 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
1464 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1465 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1466 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1467 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
1468 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
1471 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1472 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1473 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1474 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
1475 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
1477 m_pDoc
->DeleteTab(0);
1480 void Test::testSharedFormulaUpdateOnNamedRangeChange()
1482 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
1484 m_pDoc
->InsertTab(0, "Test");
1486 const char* const pName
= "MyRange";
1487 const char* const pExpr1
= "$Test.$A$1:$A$3";
1488 const char* const pExpr2
= "$Test.$A$1:$A$4";
1491 aName
.mpName
= pName
;
1492 aName
.mpExpr
= pExpr1
;
1494 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
1495 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), &aName
, &aName
+ 1);
1496 CPPUNIT_ASSERT(bSuccess
);
1497 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames
->size());
1498 m_pDoc
->SetRangeName(std::move(pNames
));
1500 // Set values to A1:A4.
1501 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
1502 m_pDoc
->SetValue(ScAddress(0,1,0), 2.0);
1503 m_pDoc
->SetValue(ScAddress(0,2,0), 3.0);
1504 m_pDoc
->SetValue(ScAddress(0,3,0), 4.0);
1506 // Set formula to B1:B3.
1507 m_pDoc
->SetString(ScAddress(1,0,0), "=SUM(MyRange)");
1508 m_pDoc
->SetString(ScAddress(1,1,0), "=SUM(MyRange)");
1509 m_pDoc
->SetString(ScAddress(1,2,0), "=SUM(MyRange)");
1511 // Set single formula with no named range to B5.
1512 m_pDoc
->SetString(ScAddress(1,4,0), "=ROW()");
1514 // Set shared formula with no named range to B7:B8.
1515 m_pDoc
->SetString(ScAddress(1,6,0), "=ROW()");
1516 m_pDoc
->SetString(ScAddress(1,7,0), "=ROW()");
1518 // B1:B3 should be grouped.
1519 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,0));
1520 CPPUNIT_ASSERT(pFC
);
1521 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
1522 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
1524 // B7:B8 should be grouped.
1525 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,6,0));
1526 CPPUNIT_ASSERT(pFC
);
1527 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
1528 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
1530 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1531 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1532 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1534 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
1535 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(1,6,0)));
1536 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(1,7,0)));
1538 // Set a single formula to C1.
1539 m_pDoc
->SetString(ScAddress(2,0,0), "=AVERAGE(MyRange)");
1540 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
1541 CPPUNIT_ASSERT(pFC
);
1542 CPPUNIT_ASSERT_MESSAGE("C1 should not be shared.", !pFC
->IsShared());
1543 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
1545 // Update the range of MyRange.
1546 pNames
.reset(new ScRangeName
);
1547 aName
.mpExpr
= pExpr2
;
1548 bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), &aName
, &aName
+ 1);
1549 CPPUNIT_ASSERT(bSuccess
);
1550 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames
->size());
1551 ScDocFunc
& rFunc
= getDocShell().GetDocFunc();
1553 typedef std::map
<OUString
, std::unique_ptr
<ScRangeName
>> NameMapType
;
1554 NameMapType aNewNames
;
1555 OUString
aScope(STR_GLOBAL_RANGE_NAME
);
1556 aNewNames
.insert(std::make_pair(aScope
, std::move(pNames
)));
1557 rFunc
.ModifyAllRangeNames(aNewNames
);
1559 // Check to make sure all displayed formulas are still good.
1560 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,0,0), "SUM(MyRange)", "Wrong formula!");
1561 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,1,0), "SUM(MyRange)", "Wrong formula!");
1562 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,2,0), "SUM(MyRange)", "Wrong formula!");
1563 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,4,0), "ROW()", "Wrong formula!");
1564 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,6,0), "ROW()", "Wrong formula!");
1565 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(1,7,0), "ROW()", "Wrong formula!");
1566 ASSERT_FORMULA_EQUAL(*m_pDoc
, ScAddress(2,0,0), "AVERAGE(MyRange)", "Wrong formula!");
1568 // Check the calculation results as well.
1569 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1570 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1571 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1572 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
1573 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(1,6,0)));
1574 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(1,7,0)));
1575 CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc
->GetValue(ScAddress(2,0,0)));
1577 // Change the value of A4 and make sure the value change gets propagated.
1578 m_pDoc
->SetValue(ScAddress(0,3,0), 0.0);
1579 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1580 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1581 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1583 m_pDoc
->DeleteTab(0);
1586 void Test::testSharedFormulaUpdateOnDBChange()
1588 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
1590 m_pDoc
->InsertTab(0, "RangeTest");
1592 // Put 1, 2, 3, 4 in A1:A4.
1593 for (SCROW i
= 0; i
<= 3; ++i
)
1594 m_pDoc
->SetValue(ScAddress(0,i
,0), (i
+1));
1596 ScDBCollection
* pDBs
= m_pDoc
->GetDBCollection();
1597 CPPUNIT_ASSERT_MESSAGE("Failed to fetch DB collection object.", pDBs
);
1599 // Define database range 'MyRange' for A1:A2.
1600 std::unique_ptr
<ScDBData
> pData(new ScDBData("MyRange", 0, 0, 0, 0, 1));
1601 bool bInserted
= pDBs
->getNamedDBs().insert(std::move(pData
));
1602 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new database range.", bInserted
);
1604 // Insert in C2:C4 a group of formula cells that reference MyRange.
1605 for (SCROW i
= 1; i
<= 3; ++i
)
1606 m_pDoc
->SetString(ScAddress(2,i
,0), "=SUM(MyRange)");
1608 // Make sure C2:C4 is a formula group.
1609 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,1,0));
1610 CPPUNIT_ASSERT(pFC
);
1611 CPPUNIT_ASSERT(pFC
->IsSharedTop());
1612 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
1614 // Check the initial formula results.
1615 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
1616 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
1617 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
1619 ScDBDocFunc
aFunc(getDocShell());
1621 // Change the range referenced by MyRange to A1:A4.
1622 ScDBCollection
aNewDBs(*m_pDoc
);
1623 std::unique_ptr
<ScDBData
> pNewData(new ScDBData("MyRange", 0, 0, 0, 0, 3));
1624 bInserted
= aNewDBs
.getNamedDBs().insert(std::move(pNewData
));
1625 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new database range.", bInserted
);
1627 std::vector
<ScRange
> aDeleted
;
1628 aFunc
.ModifyAllDBData(aNewDBs
, aDeleted
);
1630 // Check the updated formula results.
1631 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
1632 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
1633 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
1635 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
1636 CPPUNIT_ASSERT(pUndoMgr
);
1638 // Undo and check the results.
1640 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
1641 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
1642 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
1644 // Redo and check the results.
1646 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
1647 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
1648 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
1650 m_pDoc
->DeleteTab(0);
1653 void Test::testSharedFormulaAbsCellListener()
1655 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
1657 m_pDoc
->InsertTab(0, "Test");
1659 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
1661 const char* pData
[][1] = {
1667 insertRangeData(m_pDoc
, ScAddress(1,0,0), pData
, SAL_N_ELEMENTS(pData
));
1669 // A1 should have 3 listeners listening into it.
1670 const SvtBroadcaster
* pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1671 CPPUNIT_ASSERT(pBC
);
1672 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pBC
->GetAllListeners().size());
1674 // Check the formula results.
1675 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
1676 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
1677 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
1679 // Change the value of A1 and make sure B1:B3 follows.
1680 m_pDoc
->SetValue(ScAddress(0,0,0), 2.5);
1682 CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc
->GetValue(ScAddress(1,0,0)));
1683 CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc
->GetValue(ScAddress(1,1,0)));
1684 CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc
->GetValue(ScAddress(1,2,0)));
1686 m_pDoc
->DeleteTab(0);
1689 static double checkNewValuesNotification( ScDocument
* pDoc
, const ScAddress
& rOrgPos
)
1691 ScAddress
aPos(rOrgPos
);
1693 pDoc
->SetValues( aPos
, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
1696 for (SCROW i
=0; i
< 5; ++i
)
1698 fVal
+= pDoc
->GetValue(aPos
);
1704 void Test::testSharedFormulaUnshareAreaListeners()
1706 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
1708 m_pDoc
->InsertTab(0, "Test");
1710 const char* pData
[][2] = {
1711 { "=SUM(B1:B2)", "1" },
1712 { "=SUM(B2:B3)", "2" },
1713 { "=SUM(B3:B4)", "4" },
1717 insertRangeData(m_pDoc
, ScAddress(0,0,0), pData
, SAL_N_ELEMENTS(pData
));
1719 // Check that A1:A3 is a formula group.
1720 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,0,0));
1721 CPPUNIT_ASSERT(pFC
);
1722 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
1723 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), pFC
->GetSharedLength());
1725 m_pDoc
->SetValue(ScAddress(0,1,0), 23.0); // unshare at A2
1726 m_pDoc
->SetValue(ScAddress(1,1,0), 16.0); // change value of B2
1727 m_pDoc
->SetValue(ScAddress(1,2,0), 32.0); // change value of B3
1728 // A1 and A3 should be recalculated.
1729 CPPUNIT_ASSERT_EQUAL(17.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
1730 CPPUNIT_ASSERT_EQUAL(40.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
1732 clearRange(m_pDoc
, ScRange( 0,0,0, 1,3,0));
1734 for (int nRun
= 0; nRun
< 7; ++nRun
)
1737 const ScAddress
aOrgPos(0,1,0);
1738 const char* pData2
[][3] = {
1739 { "=SUM(B2:C2)", "1", "2" },
1740 { "=SUM(B3:C3)", "4", "8" },
1741 { "=SUM(B4:C4)", "16", "32" },
1742 { "=SUM(B5:C5)", "64", "128" },
1743 { "=SUM(B6:C6)", "256", "512" },
1745 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
1747 // Check that A2:A6 is a formula group.
1748 pFC
= m_pDoc
->GetFormulaCell(aOrgPos
);
1749 CPPUNIT_ASSERT(pFC
);
1750 CPPUNIT_ASSERT_MESSAGE("A2", pFC
->IsSharedTop());
1751 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aOrgPos
.Row(), pFC
->GetSharedTopRow());
1752 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(5), pFC
->GetSharedLength());
1754 // Overwrite and thus unshare formula in A3.
1755 // Check different code paths with different methods.
1756 ScAddress
aPos(aOrgPos
);
1761 // Directly set a different formula cell, which bypasses
1762 // ScDocument::SetString(), mimicking formula input in view.
1764 ScFormulaCell
* pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B4");
1765 ScDocFunc
& rDocFunc
= getDocShell().GetDocFunc();
1766 rDocFunc
.SetFormulaCell( aPos
, pCell
, false);
1770 m_pDoc
->SetString( aPos
, "=B4"); // set formula
1773 m_pDoc
->SetString( aPos
, "x"); // set string
1776 m_pDoc
->SetString( aPos
, "4096"); // set number/numeric
1779 m_pDoc
->SetValue( aPos
, 4096.0); // set numeric
1782 m_pDoc
->SetValues( aPos
, {4096.0}); // set numeric vector
1785 // Set formula cell vector.
1787 ScFormulaCell
* pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B4");
1788 std::vector
<ScFormulaCell
*> aCells
;
1789 aCells
.push_back(pCell
);
1790 m_pDoc
->SetFormulaCells( aPos
, aCells
);
1795 // Check that A2:A3 and A5:A6 are two formula groups.
1797 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1798 CPPUNIT_ASSERT(pFC
);
1799 CPPUNIT_ASSERT_MESSAGE("A2", pFC
->IsSharedTop());
1800 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1801 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1803 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1804 CPPUNIT_ASSERT(pFC
);
1805 CPPUNIT_ASSERT_MESSAGE("A5", pFC
->IsSharedTop());
1806 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1807 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1809 // Check that listeners were set up and formulas are updated when B2:B6
1810 // get new values input (tdf#123736).
1813 m_pDoc
->SetValues( aPos
, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
1816 CPPUNIT_ASSERT_EQUAL(1026.0, m_pDoc
->GetValue(aPos
));
1818 CPPUNIT_ASSERT_EQUAL(2056.0, m_pDoc
->GetValue(aPos
));
1820 if (nRun
!= 2) // if not string
1821 CPPUNIT_ASSERT_EQUAL(4096.0, m_pDoc
->GetValue(aPos
));
1823 CPPUNIT_ASSERT_EQUAL(8320.0, m_pDoc
->GetValue(aPos
));
1825 CPPUNIT_ASSERT_EQUAL(16896.0, m_pDoc
->GetValue(aPos
));
1827 clearRange(m_pDoc
, ScRange( 0,0,0, 2,5,0));
1830 // Check detach/regroup combinations of overlapping when setting formula
1833 // Fixed data in A3:C7, modified formula range A1:A9
1834 const ScAddress
aOrgPos(0,2,0);
1835 ScAddress
aPos( ScAddress::UNINITIALIZED
);
1836 ScFormulaCell
* pCell
;
1837 std::vector
<ScFormulaCell
*> aCells
;
1838 const char* pData2
[][3] = {
1839 { "=SUM(B3:C3)", "1", "2" },
1840 { "=SUM(B4:C4)", "4", "8" },
1841 { "=SUM(B5:C5)", "16", "32" },
1842 { "=SUM(B6:C6)", "64", "128" },
1843 { "=SUM(B7:C7)", "256", "512" },
1846 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
1848 // Add grouping formulas in A1:A2, keep A3:A7
1849 aPos
= ScAddress(0,0,0);
1850 std::vector
<ScFormulaCell
*>().swap( aCells
);
1851 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=SUM(B1:C1)");
1852 aCells
.push_back(pCell
);
1854 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=SUM(B2:C2)");
1855 aCells
.push_back(pCell
);
1857 m_pDoc
->SetFormulaCells( aPos
, aCells
);
1859 // Check it is one formula group.
1860 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1861 CPPUNIT_ASSERT(pFC
);
1862 CPPUNIT_ASSERT_MESSAGE("A1", pFC
->IsSharedTop());
1863 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1864 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(7), pFC
->GetSharedLength());
1866 // Check notification of setting new values.
1867 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
1869 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
1871 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
1873 // Add formulas in A1:A2, keep A3:A7
1874 aPos
= ScAddress(0,0,0);
1875 std::vector
<ScFormulaCell
*>().swap( aCells
);
1876 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B1+C1");
1877 aCells
.push_back(pCell
);
1879 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B2+C2");
1880 aCells
.push_back(pCell
);
1882 m_pDoc
->SetFormulaCells( aPos
, aCells
);
1884 // Check formula groups.
1885 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1886 CPPUNIT_ASSERT(pFC
);
1887 CPPUNIT_ASSERT_MESSAGE("A1", pFC
->IsSharedTop());
1888 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1889 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1891 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1892 CPPUNIT_ASSERT(pFC
);
1893 CPPUNIT_ASSERT_MESSAGE("A3", pFC
->IsSharedTop());
1894 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1895 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(5), pFC
->GetSharedLength());
1897 // Check notification of setting new values.
1898 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
1900 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
1902 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
1904 // Add formula in A2, overwrite A3, keep A4:A7
1905 aPos
= ScAddress(0,1,0);
1906 std::vector
<ScFormulaCell
*>().swap( aCells
);
1907 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B2+C2");
1908 aCells
.push_back(pCell
);
1910 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B3+C3");
1911 aCells
.push_back(pCell
);
1913 m_pDoc
->SetFormulaCells( aPos
, aCells
);
1915 // Check formula groups.
1916 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1917 CPPUNIT_ASSERT(pFC
);
1918 CPPUNIT_ASSERT_MESSAGE("A2", pFC
->IsSharedTop());
1919 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1920 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1922 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1923 CPPUNIT_ASSERT(pFC
);
1924 CPPUNIT_ASSERT_MESSAGE("A4", pFC
->IsSharedTop());
1925 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1926 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(4), pFC
->GetSharedLength());
1928 // Check notification of setting new values.
1929 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
1931 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
1933 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
1935 // Overwrite A3:A4, keep A5:A7
1936 aPos
= ScAddress(0,2,0);
1937 std::vector
<ScFormulaCell
*>().swap( aCells
);
1938 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B3+C3");
1939 aCells
.push_back(pCell
);
1941 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B4+C4");
1942 aCells
.push_back(pCell
);
1944 m_pDoc
->SetFormulaCells( aPos
, aCells
);
1946 // Check formula groups.
1948 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1949 CPPUNIT_ASSERT(pFC
);
1950 CPPUNIT_ASSERT_MESSAGE("A3", pFC
->IsSharedTop());
1951 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1952 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1954 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1955 CPPUNIT_ASSERT(pFC
);
1956 CPPUNIT_ASSERT_MESSAGE("A5", pFC
->IsSharedTop());
1957 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1958 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(3), pFC
->GetSharedLength());
1960 // Check notification of setting new values.
1961 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
1963 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
1965 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
1967 // Keep A3, overwrite A4:A5, keep A6:A7
1968 aPos
= ScAddress(0,3,0);
1969 std::vector
<ScFormulaCell
*>().swap( aCells
);
1970 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B4+C4");
1971 aCells
.push_back(pCell
);
1973 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B5+C5");
1974 aCells
.push_back(pCell
);
1976 m_pDoc
->SetFormulaCells( aPos
, aCells
);
1978 // Check formula groups.
1980 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1981 CPPUNIT_ASSERT(pFC
);
1982 CPPUNIT_ASSERT_MESSAGE("A3", !pFC
->IsSharedTop());
1984 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1985 CPPUNIT_ASSERT(pFC
);
1986 CPPUNIT_ASSERT_MESSAGE("A4", pFC
->IsSharedTop());
1987 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1988 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1990 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1991 CPPUNIT_ASSERT(pFC
);
1992 CPPUNIT_ASSERT_MESSAGE("A6", pFC
->IsSharedTop());
1993 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
1994 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
1996 // Check notification of setting new values.
1997 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
1999 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2001 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
2003 // Keep A3:A4, overwrite A5:A6, keep A7
2004 aPos
= ScAddress(0,4,0);
2005 std::vector
<ScFormulaCell
*>().swap( aCells
);
2006 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B5+C5");
2007 aCells
.push_back(pCell
);
2009 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B6+C6");
2010 aCells
.push_back(pCell
);
2012 m_pDoc
->SetFormulaCells( aPos
, aCells
);
2014 // Check formula groups.
2016 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2017 CPPUNIT_ASSERT(pFC
);
2018 CPPUNIT_ASSERT_MESSAGE("A3", pFC
->IsSharedTop());
2019 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2020 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2022 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2023 CPPUNIT_ASSERT(pFC
);
2024 CPPUNIT_ASSERT_MESSAGE("A5", pFC
->IsSharedTop());
2025 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2026 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2028 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2029 CPPUNIT_ASSERT(pFC
);
2030 CPPUNIT_ASSERT_MESSAGE("A7", !pFC
->IsSharedTop());
2032 // Check notification of setting new values.
2033 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
2035 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2037 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
2039 // Keep A3:A5, overwrite A6:A7
2040 aPos
= ScAddress(0,5,0);
2041 std::vector
<ScFormulaCell
*>().swap( aCells
);
2042 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B6+C6");
2043 aCells
.push_back(pCell
);
2045 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B7+C7");
2046 aCells
.push_back(pCell
);
2048 m_pDoc
->SetFormulaCells( aPos
, aCells
);
2050 // Check formula groups.
2052 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2053 CPPUNIT_ASSERT(pFC
);
2054 CPPUNIT_ASSERT_MESSAGE("A3", pFC
->IsSharedTop());
2055 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2056 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(3), pFC
->GetSharedLength());
2058 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2059 CPPUNIT_ASSERT(pFC
);
2060 CPPUNIT_ASSERT_MESSAGE("A6", pFC
->IsSharedTop());
2061 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2062 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2064 // Check notification of setting new values.
2065 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
2067 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2069 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
2071 // Keep A3:A6, overwrite A7, add A8
2072 aPos
= ScAddress(0,6,0);
2073 std::vector
<ScFormulaCell
*>().swap( aCells
);
2074 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B7+C7");
2075 aCells
.push_back(pCell
);
2077 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B8+C8");
2078 aCells
.push_back(pCell
);
2080 m_pDoc
->SetFormulaCells( aPos
, aCells
);
2082 // Check formula groups.
2084 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2085 CPPUNIT_ASSERT(pFC
);
2086 CPPUNIT_ASSERT_MESSAGE("A3", pFC
->IsSharedTop());
2087 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2088 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(4), pFC
->GetSharedLength());
2090 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2091 CPPUNIT_ASSERT(pFC
);
2092 CPPUNIT_ASSERT_MESSAGE("A7", pFC
->IsSharedTop());
2093 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2094 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2096 // Check notification of setting new values.
2097 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
2099 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2101 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
2103 // Keep A3:A7, add A8:A9
2104 aPos
= ScAddress(0,7,0);
2105 std::vector
<ScFormulaCell
*>().swap( aCells
);
2106 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B8+C8");
2107 aCells
.push_back(pCell
);
2109 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=B9+C9");
2110 aCells
.push_back(pCell
);
2112 m_pDoc
->SetFormulaCells( aPos
, aCells
);
2114 // Check formula groups.
2116 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2117 CPPUNIT_ASSERT(pFC
);
2118 CPPUNIT_ASSERT_MESSAGE("A3", pFC
->IsSharedTop());
2119 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2120 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(5), pFC
->GetSharedLength());
2122 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2123 CPPUNIT_ASSERT(pFC
);
2124 CPPUNIT_ASSERT_MESSAGE("A7", pFC
->IsSharedTop());
2125 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2126 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2128 // Check notification of setting new values.
2129 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
2131 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2133 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
2135 // Keep A3:A7, add grouping formulas in A8:A9
2136 aPos
= ScAddress(0,7,0);
2137 std::vector
<ScFormulaCell
*>().swap( aCells
);
2138 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=SUM(B8:C8)");
2139 aCells
.push_back(pCell
);
2141 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=SUM(B9:C9)");
2142 aCells
.push_back(pCell
);
2144 m_pDoc
->SetFormulaCells( aPos
, aCells
);
2146 // Check it is one formula group.
2148 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2149 CPPUNIT_ASSERT(pFC
);
2150 CPPUNIT_ASSERT_MESSAGE("A1", pFC
->IsSharedTop());
2151 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2152 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(7), pFC
->GetSharedLength());
2154 // Check notification of setting new values.
2155 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
2157 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2159 insertRangeData(m_pDoc
, aOrgPos
, pData2
, SAL_N_ELEMENTS(pData2
));
2161 // Overwrite grouping formulas in A4:A5
2162 aPos
= ScAddress(0,3,0);
2163 std::vector
<ScFormulaCell
*>().swap( aCells
);
2164 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=SUM(B4:C4)");
2165 aCells
.push_back(pCell
);
2167 pCell
= new ScFormulaCell( *m_pDoc
, aPos
, "=SUM(B5:C5)");
2168 aCells
.push_back(pCell
);
2170 m_pDoc
->SetFormulaCells( aPos
, aCells
);
2172 // Check it is one formula group.
2174 pFC
= m_pDoc
->GetFormulaCell(aPos
);
2175 CPPUNIT_ASSERT(pFC
);
2176 CPPUNIT_ASSERT_MESSAGE("A1", pFC
->IsSharedTop());
2177 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos
.Row(), pFC
->GetSharedTopRow());
2178 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW
>(5), pFC
->GetSharedLength());
2180 // Check notification of setting new values.
2181 CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc
, aOrgPos
));
2183 clearRange(m_pDoc
, ScRange( 0,0,0, 2,8,0));
2186 m_pDoc
->DeleteTab(0);
2189 void Test::testSharedFormulaListenerDeleteArea()
2191 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2193 m_pDoc
->InsertTab(0, "Test0");
2194 m_pDoc
->InsertTab(1, "Test1");
2196 const char* pData0
[][3] = {
2197 { "", "", "=Test1.C1" },
2198 { "", "", "=Test1.C2" }
2200 const char* pData1
[][3] = {
2201 { "=Test0.A1", "=Test0.B1", "=SUM(A1:B1)" },
2202 { "=Test0.A2", "=Test0.B2", "=SUM(A2:B2)" },
2205 insertRangeData(m_pDoc
, ScAddress(0,0,0), pData0
, SAL_N_ELEMENTS(pData0
));
2206 insertRangeData(m_pDoc
, ScAddress(0,0,1), pData1
, SAL_N_ELEMENTS(pData1
));
2208 // Check that Test1.A1:A2 and Test1.B1:B2 are formula groups.
2209 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,0,1));
2210 CPPUNIT_ASSERT(pFC
);
2211 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
2212 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
2214 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,0,1));
2215 CPPUNIT_ASSERT(pFC
);
2216 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
2217 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
2219 m_pDoc
->SetValue(ScAddress(0,1,0), 1.0); // change value of Test0.A2
2220 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0); // change value of Test0.B2
2221 // Test0.C2 should be recalculated.
2222 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
2225 clearRange(m_pDoc
, ScRange(1,1,0));
2226 // Test0.C2 should be recalculated.
2227 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
2229 m_pDoc
->DeleteTab(1);
2230 m_pDoc
->DeleteTab(0);
2233 void Test::testSharedFormulaUpdateOnReplacement()
2235 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2237 m_pDoc
->InsertTab(0, "Test");
2239 const char* pData
[][1] = {
2241 { "=SUM($A$1:$A1)" },
2242 { "=SUM($A$1:$A2)" },
2243 { "=SUM($A$1:$A3)" },
2244 { "=SUM($A$1:$A4)" },
2245 { "=SUM($A$1:$A5)" },
2246 { "=SUM($A$1:$A6)" },
2247 { "=SUM($A$1:$A7)" }
2250 insertRangeData(m_pDoc
, ScAddress(0,0,0), pData
, SAL_N_ELEMENTS(pData
));
2252 // Check that A2:A8 is a formula group.
2253 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,1,0));
2254 CPPUNIT_ASSERT(pFC
);
2255 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
2256 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(7), pFC
->GetSharedLength());
2258 { // Check initial results.
2259 ScAddress
aPos(0,0,0);
2260 const double fResult
[] = { 1.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 };
2261 for (SCROW nRow
= 1; nRow
< 8; ++nRow
)
2264 CPPUNIT_ASSERT_EQUAL( fResult
[nRow
], m_pDoc
->GetValue( aPos
));
2268 // Set up an undo object for deleting A4.
2269 ScRange
aUndoRange(0,3,0,0,3,0);
2270 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2271 aMark
.SelectOneTable(0);
2272 aMark
.SetMultiMarkArea(aUndoRange
);
2273 ScDocumentUniquePtr
pUndoDoc(new ScDocument(SCDOCMODE_UNDO
));
2274 pUndoDoc
->InitUndo(*m_pDoc
, 0, 0);
2275 m_pDoc
->CopyToDocument(aUndoRange
, InsertDeleteFlags::CONTENTS
, false, *pUndoDoc
, &aMark
);
2276 ScUndoDeleteContents
aUndo(&getDocShell(), aMark
, aUndoRange
, std::move(pUndoDoc
), false, InsertDeleteFlags::CONTENTS
, true);
2279 clearRange(m_pDoc
, aUndoRange
);
2281 // Check that A2:A3 and A5:A8 are formula groups.
2282 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,1,0));
2283 CPPUNIT_ASSERT(pFC
);
2284 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
2285 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
2286 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,4,0));
2287 CPPUNIT_ASSERT(pFC
);
2288 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedTopRow());
2289 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
2291 { // Check results of A4 deleted.
2292 ScAddress
aPos(0,0,0);
2293 const double fResult
[] = { 1.0, 1.0, 2.0, 0.0, 4.0, 8.0, 16.0, 32.0 };
2294 for (SCROW nRow
= 1; nRow
< 8; ++nRow
)
2297 CPPUNIT_ASSERT_EQUAL( fResult
[nRow
], m_pDoc
->GetValue( aPos
));
2304 // Check that A2:A8 is a formula group.
2305 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,1,0));
2306 CPPUNIT_ASSERT(pFC
);
2307 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
2308 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(7), pFC
->GetSharedLength());
2310 { // Check initial results.
2311 ScAddress
aPos(0,0,0);
2312 const double fResult
[] = { 1.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 };
2313 for (SCROW nRow
= 1; nRow
< 8; ++nRow
)
2316 CPPUNIT_ASSERT_EQUAL( fResult
[nRow
], m_pDoc
->GetValue( aPos
));
2320 // Delete A4 using selection.
2321 m_pDoc
->DeleteSelection(InsertDeleteFlags::ALL
, aMark
);
2323 // Check that A2:A3 and A5:A8 are formula groups.
2324 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,1,0));
2325 CPPUNIT_ASSERT(pFC
);
2326 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
2327 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
2328 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,4,0));
2329 CPPUNIT_ASSERT(pFC
);
2330 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedTopRow());
2331 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
2333 { // Check results of A4 deleted.
2334 ScAddress
aPos(0,0,0);
2335 const double fResult
[] = { 1.0, 1.0, 2.0, 0.0, 4.0, 8.0, 16.0, 32.0 };
2336 for (SCROW nRow
= 1; nRow
< 8; ++nRow
)
2339 CPPUNIT_ASSERT_EQUAL( fResult
[nRow
], m_pDoc
->GetValue( aPos
));
2346 // Check that A2:A8 is a formula group.
2347 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,1,0));
2348 CPPUNIT_ASSERT(pFC
);
2349 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
2350 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(7), pFC
->GetSharedLength());
2352 { // Check initial results.
2353 ScAddress
aPos(0,0,0);
2354 const double fResult
[] = { 1.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 };
2355 for (SCROW nRow
= 1; nRow
< 8; ++nRow
)
2358 CPPUNIT_ASSERT_EQUAL( fResult
[nRow
], m_pDoc
->GetValue( aPos
));
2362 // Replace A4 with 0.
2363 m_pDoc
->SetString( ScAddress(0,3,0), "0");
2365 // Check that A2:A3 and A5:A8 are formula groups.
2366 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,1,0));
2367 CPPUNIT_ASSERT(pFC
);
2368 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
2369 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
2370 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,4,0));
2371 CPPUNIT_ASSERT(pFC
);
2372 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedTopRow());
2373 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(4), pFC
->GetSharedLength());
2375 { // Check results of A4 set to zero.
2376 ScAddress
aPos(0,0,0);
2377 const double fResult
[] = { 1.0, 1.0, 2.0, 0.0, 4.0, 8.0, 16.0, 32.0 };
2378 for (SCROW nRow
= 1; nRow
< 8; ++nRow
)
2381 CPPUNIT_ASSERT_EQUAL( fResult
[nRow
], m_pDoc
->GetValue( aPos
));
2385 m_pDoc
->DeleteTab(0);
2388 void Test::testSharedFormulaDeleteTopCell()
2390 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2392 m_pDoc
->InsertTab(0, "Test");
2394 const char* pData
[][2] = {
2395 { "=SUM(B$1:B$2)", "1" },
2396 { "=SUM(B$1:B$2)", "2" }
2399 insertRangeData( m_pDoc
, ScAddress(0,0,0), pData
, SAL_N_ELEMENTS(pData
));
2401 // Check that A1:A2 is a formula group.
2402 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell( ScAddress(0,0,0));
2403 CPPUNIT_ASSERT(pFC
);
2404 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
2405 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
2407 // Check results A1:A2.
2408 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc
->GetValue( ScAddress(0,0,0)));
2409 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc
->GetValue( ScAddress(0,1,0)));
2412 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2413 aMark
.SelectOneTable(0);
2414 getDocShell().GetDocFunc().DeleteCell( ScAddress(0,0,0), aMark
, InsertDeleteFlags::CONTENTS
, false);
2416 CPPUNIT_ASSERT(!m_pDoc
->GetFormulaCell( ScAddress(0,0,0)));
2419 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc
->GetValue( ScAddress(0,1,0)));
2421 // Replace B1 with 4.
2422 m_pDoc
->SetString( ScAddress(1,0,0), "4");
2425 CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc
->GetValue( ScAddress(0,1,0)));
2427 m_pDoc
->DeleteTab(0);
2430 void Test::testSharedFormulaCutCopyMoveIntoRef()
2432 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2434 // tdf#123714 case 1
2436 m_pDoc
->InsertTab(0, "Test");
2439 std::vector
<std::vector
<const char*>> aData
= {
2444 const ScAddress
aOrgPos(0,0,0);
2445 insertRangeData( m_pDoc
, aOrgPos
, aData
);
2447 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2448 aMark
.SelectOneTable(0);
2450 // Set up clip document.
2451 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
2452 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
2453 // Cut C1:C2 to clipboard.
2454 cutToClip( getDocShell(), ScRange(2,0,0, 2,1,0), &aClipDoc
, false);
2457 ScRange
aPasteRange(1,0,0, 1,1,0);
2458 aMark
.SetMarkArea(aPasteRange
);
2459 m_pDoc
->CopyFromClip( aPasteRange
, aMark
, InsertDeleteFlags::CONTENTS
, nullptr, &aClipDoc
);
2461 // Check data in A1:A2 after Paste.
2462 ScAddress
aPos(aOrgPos
);
2463 CPPUNIT_ASSERT_EQUAL_MESSAGE("A1", 1.0, m_pDoc
->GetValue(aPos
));
2465 CPPUNIT_ASSERT_EQUAL_MESSAGE("A2", 1.0, m_pDoc
->GetValue(aPos
));
2467 m_pDoc
->DeleteTab(0);
2470 // tdf#123714 case 2
2472 m_pDoc
->InsertTab(0, "Test");
2475 std::vector
<std::vector
<const char*>> aData
= {
2476 { "1", "2", "=SUM(A1:B1)" },
2477 { "4", "8", "=SUM(A2:B2)" },
2478 { "16", "32", "=SUM(A3:B3)" },
2479 { "64", "128", "=SUM(A4:B4)" },
2481 const ScAddress
aOrgPos(0,0,0);
2482 insertRangeData( m_pDoc
, aOrgPos
, aData
);
2485 // Check results in C1:C4
2486 const double fVec0
[] = { 3.0, 12.0, 48.0, 192.0 };
2487 aPos
= ScAddress(2,0,0);
2488 for (SCROW i
=0; i
< 4; ++i
)
2490 CPPUNIT_ASSERT_EQUAL( fVec0
[i
], m_pDoc
->GetValue(aPos
));
2494 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2495 aMark
.SelectOneTable(0);
2497 // Set up clip document.
2498 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
2499 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
2500 // Cut B1:B2 to clipboard.
2501 cutToClip( getDocShell(), ScRange(1,0,0, 1,1,0), &aClipDoc
, false);
2503 // Check results in C1:C4 after Cut.
2504 const double fVec1
[] = { 1.0, 4.0, 48.0, 192.0 };
2505 aPos
= ScAddress(2,0,0);
2506 for (SCROW i
=0; i
< 4; ++i
)
2508 CPPUNIT_ASSERT_EQUAL( fVec1
[i
], m_pDoc
->GetValue(aPos
));
2513 ScRange
aPasteRange(1,2,0, 1,3,0);
2514 aMark
.SetMarkArea(aPasteRange
);
2515 m_pDoc
->CopyFromClip( aPasteRange
, aMark
, InsertDeleteFlags::CONTENTS
, nullptr, &aClipDoc
);
2517 // Check results in C1:C4 after Paste.
2518 const double fVec2
[] = { 1.0, 4.0, 18.0, 72.0 };
2519 aPos
= ScAddress(2,0,0);
2520 for (SCROW i
=0; i
< 4; ++i
)
2522 CPPUNIT_ASSERT_EQUAL( fVec2
[i
], m_pDoc
->GetValue(aPos
));
2527 aPasteRange
= ScRange(1,0,0, 1,1,0);
2528 aMark
.SetMarkArea(aPasteRange
);
2529 m_pDoc
->CopyFromClip( aPasteRange
, aMark
, InsertDeleteFlags::CONTENTS
, nullptr, &aClipDoc
);
2531 // Check results in C1:C4 after Paste.
2532 const double fVec3
[] = { 3.0, 12.0, 18.0, 72.0 };
2533 aPos
= ScAddress(2,0,0);
2534 for (SCROW i
=0; i
< 4; ++i
)
2536 CPPUNIT_ASSERT_EQUAL( fVec3
[i
], m_pDoc
->GetValue(aPos
));
2540 m_pDoc
->DeleteTab(0);
2545 void Test::testSharedFormulaCutCopyMoveWithRef()
2547 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2549 m_pDoc
->InsertTab(0, "Test");
2552 std::vector
<std::vector
<const char*>> aData
= {
2553 { "", "", "=SUM(A1:B1)" },
2554 { "", "", "=SUM(A2:B2)" },
2555 { "1", "2", "=SUM(A3:B3)" },
2556 { "4", "8", "=SUM(A4:B4)" }
2558 const ScAddress
aOrgPos(0,0,0);
2559 insertRangeData( m_pDoc
, aOrgPos
, aData
);
2561 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2562 aMark
.SelectOneTable(0);
2564 ScAddress
aPos( ScAddress::UNINITIALIZED
);
2566 // Check results in C1:C4
2567 const double fVec0
[] = { 0.0, 0.0, 3.0, 12.0 };
2568 aPos
= ScAddress(2,0,0);
2569 for (SCROW i
=0; i
< 4; ++i
)
2571 CPPUNIT_ASSERT_EQUAL( fVec0
[i
], m_pDoc
->GetValue(aPos
));
2575 // Set up clip document.
2576 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
2577 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
2578 // Cut A3:B3 to clipboard.
2579 cutToClip( getDocShell(), ScRange(0,2,0, 1,2,0), &aClipDoc
, false);
2581 // Check results in C1:C4 after Cut.
2582 const double fVec1
[] = { 0.0, 0.0, 0.0, 12.0 };
2583 aPos
= ScAddress(2,0,0);
2584 for (SCROW i
=0; i
< 4; ++i
)
2586 CPPUNIT_ASSERT_EQUAL( fVec1
[i
], m_pDoc
->GetValue(aPos
));
2591 ScRange
aPasteRange(0,0,0, 1,0,0);
2592 aMark
.SetMarkArea(aPasteRange
);
2593 m_pDoc
->CopyFromClip( aPasteRange
, aMark
, InsertDeleteFlags::CONTENTS
, nullptr, &aClipDoc
);
2595 // Check results in C1:C4 after Paste.
2596 const double fVec2
[] = { 3.0, 0.0, 3.0, 12.0 };
2597 aPos
= ScAddress(2,0,0);
2598 for (SCROW i
=0; i
< 4; ++i
)
2600 CPPUNIT_ASSERT_EQUAL( fVec2
[i
], m_pDoc
->GetValue(aPos
));
2604 // Check formulas in C1:C4 after Paste.
2605 const std::u16string_view sForm
[] = { u
"=SUM(A1:B1)", u
"=SUM(A2:B2)", u
"=SUM(A1:B1)", u
"=SUM(A4:B4)" };
2606 for (SCROW i
=0; i
< 4; ++i
)
2609 m_pDoc
->GetFormula( 2,i
,0, aFormula
);
2610 CPPUNIT_ASSERT_EQUAL( OUString(sForm
[i
]), aFormula
);
2613 m_pDoc
->DeleteTab(0);
2617 void Test::testSharedFormulaCutCopyMoveWithinRun()
2619 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2621 m_pDoc
->InsertTab(0, "Test");
2624 const std::vector
<std::vector
<const char*>> aData
= {
2625 { "2200", "", "=SUM(C$3:C3)-SUM(D$3:D3)" },
2626 { "", "", "=SUM(C$3:C4)-SUM(D$3:D4)" },
2627 { "", "1900", "=SUM(C$3:C5)-SUM(D$3:D5)" },
2628 { "", "", "=SUM(C$3:C6)-SUM(D$3:D6)" },
2629 { "1600", "", "=SUM(C$3:C7)-SUM(D$3:D7)" },
2630 { "", "1000", "=SUM(C$3:C8)-SUM(D$3:D8)" },
2631 { "", "", "=SUM(C$3:C9)-SUM(D$3:D9)" }
2633 const ScAddress
aOrgPos(2,2,0);
2634 insertRangeData( m_pDoc
, aOrgPos
, aData
);
2636 // Check that E3:E9 is a formula group.
2637 const ScAddress
aFormulaPos(4,2,0);
2638 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell( aFormulaPos
);
2639 CPPUNIT_ASSERT(pFC
);
2640 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos
.Row(), pFC
->GetSharedTopRow());
2641 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW
>(7), pFC
->GetSharedLength());
2643 ScAddress
aPos( ScAddress::UNINITIALIZED
);
2645 // Check results in E3:E9
2646 const double fVec0
[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 900.0, 900.0 };
2647 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec0
), aData
.size());
2649 for (size_t i
=0; i
< SAL_N_ELEMENTS(fVec0
); ++i
)
2651 CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9", fVec0
[i
], m_pDoc
->GetValue(aPos
));
2655 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2656 aMark
.SelectOneTable(0);
2658 // Set up clip document.
2659 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
2660 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
2661 // Cut A8:D8 to clipboard.
2662 cutToClip( getDocShell(), ScRange(0,7,0, 3,7,0), &aClipDoc
, false);
2664 // Check results in E3:E9 after Cut.
2665 const double fVec1
[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 1900.0, 1900.0 };
2666 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec1
), aData
.size());
2668 for (size_t i
=0; i
< SAL_N_ELEMENTS(fVec1
); ++i
)
2670 CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Cut.", fVec1
[i
], m_pDoc
->GetValue(aPos
));
2675 ScRange
aPasteRange(0,3,0, 3,3,0);
2676 aMark
.SetMarkArea(aPasteRange
);
2677 m_pDoc
->CopyFromClip( aPasteRange
, aMark
, InsertDeleteFlags::CONTENTS
, nullptr, &aClipDoc
);
2679 // Check results in E3:E9 after Paste.
2680 const double fVec2
[] = { 2200.0, 1200.0, -700.0, -700.0, 900.0, 900.0, 900.0 };
2681 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec2
), aData
.size());
2683 for (size_t i
=0; i
< SAL_N_ELEMENTS(fVec2
); ++i
)
2685 CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Paste.", fVec2
[i
], m_pDoc
->GetValue(aPos
));
2689 m_pDoc
->DeleteTab(0);
2693 void Test::testSharedFormulaInsertShift()
2695 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
2697 m_pDoc
->InsertTab(0, "Test");
2700 const std::vector
<std::vector
<const char*>> aData
= {
2701 { "1", "2", "=SUM(A1:B1)" },
2702 { "4", "8", "=SUM(A2:B2)" }
2704 const ScAddress
aOrgPos(0,0,0);
2705 insertRangeData( m_pDoc
, aOrgPos
, aData
);
2708 // Check that C1:C2 is a formula group.
2709 const ScAddress
aFormulaPos(2,0,0);
2710 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell( aFormulaPos
);
2711 CPPUNIT_ASSERT(pFC
);
2712 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos
.Row(), pFC
->GetSharedTopRow());
2713 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2717 // Check results in C1:C2
2718 ScAddress
aPos( aOrgPos
);
2720 CPPUNIT_ASSERT_EQUAL_MESSAGE( "C1", 3.0, m_pDoc
->GetValue(aPos
));
2722 CPPUNIT_ASSERT_EQUAL_MESSAGE( "C2", 12.0, m_pDoc
->GetValue(aPos
));
2725 const bool bSuccess
= m_pDoc
->InsertCol( 0, 0, 1, 0, 2, 1);
2726 CPPUNIT_ASSERT_MESSAGE( "InsertCol", bSuccess
);
2729 // Check that D1:D2 is a formula group.
2730 const ScAddress
aFormulaPos(3,0,0);
2731 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell( aFormulaPos
);
2732 CPPUNIT_ASSERT(pFC
);
2733 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos
.Row(), pFC
->GetSharedTopRow());
2734 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW
>(2), pFC
->GetSharedLength());
2738 // Modify values in B1:B2
2739 ScAddress
aPos( aOrgPos
);
2741 m_pDoc
->SetValue(aPos
, 16.0);
2743 m_pDoc
->SetValue(aPos
, 32.0);
2747 // Check results in D1:D2
2748 ScAddress
aPos( aOrgPos
);
2750 CPPUNIT_ASSERT_EQUAL_MESSAGE( "D1", 17.0, m_pDoc
->GetValue(aPos
));
2752 CPPUNIT_ASSERT_EQUAL_MESSAGE( "D2", 36.0, m_pDoc
->GetValue(aPos
));
2755 m_pDoc
->DeleteTab(0);
2758 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */