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/.
10 #include "helper/debughelper.hxx"
11 #include "helper/qahelper.hxx"
13 #include <svl/asiancfg.hxx>
15 #include <simpleformulacalc.hxx>
16 #include <stringutil.hxx>
17 #include <scmatrix.hxx>
18 #include <scitems.hxx>
19 #include <reffind.hxx>
20 #include <clipparam.hxx>
21 #include <undoblk.hxx>
22 #include <undotab.hxx>
25 #include <reftokenhelper.hxx>
26 #include <userdat.hxx>
27 #include <refdata.hxx>
29 #include <docfunc.hxx>
30 #include <funcdesc.hxx>
31 #include <globstr.hrc>
32 #include <scresid.hxx>
34 #include <columniterator.hxx>
35 #include <scopetools.hxx>
36 #include <dociter.hxx>
37 #include <edittextiterator.hxx>
38 #include <editutil.hxx>
39 #include <asciiopt.hxx>
41 #include <docpool.hxx>
42 #include <globalnames.hxx>
43 #include <columnspanset.hxx>
45 #include <editable.hxx>
46 #include <tabprotection.hxx>
47 #include <undomanager.hxx>
49 #include <formula/IFunctionDescription.hxx>
51 #include <editeng/borderline.hxx>
52 #include <editeng/brushitem.hxx>
53 #include <editeng/eeitem.hxx>
54 #include <editeng/wghtitem.hxx>
55 #include <editeng/postitem.hxx>
56 #include <editeng/lineitem.hxx>
58 #include <svx/svdpage.hxx>
59 #include <svx/svdocirc.hxx>
60 #include <svx/svdopath.hxx>
61 #include <svx/svdocapt.hxx>
62 #include <svl/numformat.hxx>
63 #include <svl/srchitem.hxx>
64 #include <svl/sharedstringpool.hxx>
65 #include <unotools/collatorwrapper.hxx>
66 #include <sfx2/IDocumentModelAccessor.hxx>
68 #include <sfx2/sfxsids.hrc>
86 class Test
: public ScUcalcTestBase
89 void checkPrecisionAsShown(OUString
& rCode
, double fValue
, double fExpectedRoundVal
);
91 /** Get a separate new ScDocShell with ScDocument that suits unit test needs. */
92 void getNewDocShell(ScDocShellRef
& rDocShellRef
);
94 bool checkHorizontalIterator(ScDocument
& rDoc
, const std::vector
<std::vector
<const char*>>& rData
,
95 const HoriIterCheck
* pChecks
, size_t nCheckCount
);
98 void Test::getNewDocShell( ScDocShellRef
& rDocShellRef
)
100 rDocShellRef
= new ScDocShell(
101 SfxModelFlags::EMBEDDED_OBJECT
|
102 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS
|
103 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY
);
105 rDocShellRef
->DoInitUnitTest();
108 CPPUNIT_TEST_FIXTURE(Test
, testCollator
)
110 sal_Int32 nRes
= ScGlobal::GetCollator().compareString("A", "B");
111 CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes
!= 0);
114 CPPUNIT_TEST_FIXTURE(Test
, testSharedStringPool
)
116 m_pDoc
->InsertTab(0, "foo");
118 svl::SharedStringPool
& rPool
= m_pDoc
->GetSharedStringPool();
119 size_t extraCount
= rPool
.getCount(); // internal items such as SharedString::getEmptyString()
120 size_t extraCountIgnoreCase
= rPool
.getCountIgnoreCase();
122 // Strings that are identical.
123 m_pDoc
->SetString(ScAddress(0,0,0), "Andy"); // A1
124 m_pDoc
->SetString(ScAddress(0,1,0), "Andy"); // A2
125 m_pDoc
->SetString(ScAddress(0,2,0), "Bruce"); // A3
126 m_pDoc
->SetString(ScAddress(0,3,0), "andy"); // A4
127 m_pDoc
->SetString(ScAddress(0,4,0), "BRUCE"); // A5
130 // These two shared string objects must go out of scope before the purge test.
131 svl::SharedString aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
132 svl::SharedString aSS2
= m_pDoc
->GetSharedString(ScAddress(0,1,0));
133 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS1
.isValid());
134 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS2
.isValid());
135 CPPUNIT_ASSERT_EQUAL(aSS1
.getData(), aSS2
.getData());
137 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,2,0));
138 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
140 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,3,0));
141 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
143 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,4,0));
144 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
146 // A3 and A5 should differ but should be equal case-insensitively.
147 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,2,0));
148 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,4,0));
149 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
150 CPPUNIT_ASSERT_EQUAL_MESSAGE("They must be equal when cases are ignored.", aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
152 // A2 and A4 should be equal when ignoring cases.
153 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,1,0));
154 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,3,0));
155 CPPUNIT_ASSERT_EQUAL_MESSAGE("They must be equal when cases are ignored.", aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
158 // Check the string counts after purging. Purging shouldn't remove any strings in this case.
160 CPPUNIT_ASSERT_EQUAL(5+extraCount
, rPool
.getCount());
161 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, rPool
.getCountIgnoreCase());
164 clearRange(m_pDoc
, ScAddress(0,0,0));
166 clearRange(m_pDoc
, ScAddress(0,1,0));
168 clearRange(m_pDoc
, ScAddress(0,2,0));
170 clearRange(m_pDoc
, ScAddress(0,3,0));
171 // Clear A5 and the pool should be completely empty.
172 clearRange(m_pDoc
, ScAddress(0,4,0));
174 CPPUNIT_ASSERT_EQUAL(extraCount
, rPool
.getCount());
175 CPPUNIT_ASSERT_EQUAL(extraCountIgnoreCase
, rPool
.getCountIgnoreCase());
177 // Now, compare string and edit text cells.
178 m_pDoc
->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
179 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
180 rEE
.SetTextCurrentDefaults("Andy and Bruce");
183 aSel
.nStartPara
= aSel
.nEndPara
= 0;
187 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
190 SvxWeightItem
aWeight(WEIGHT_BOLD
, EE_CHAR_WEIGHT
);
191 aItemSet
.Put(aWeight
);
192 rEE
.QuickSetAttribs(aItemSet
, aSel
);
196 // Set 'Bruce' italic.
197 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
198 SvxPostureItem
aItalic(ITALIC_NORMAL
, EE_CHAR_ITALIC
);
199 aItemSet
.Put(aItalic
);
202 rEE
.QuickSetAttribs(aItemSet
, aSel
);
205 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject()); // B1
207 // These two should be equal.
208 svl::SharedString aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
209 svl::SharedString aSS2
= m_pDoc
->GetSharedString(ScAddress(1,0,0));
210 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1
.isValid());
211 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
212 CPPUNIT_ASSERT_EQUAL(aSS1
.getData(), aSS2
.getData());
214 rEE
.SetTextCurrentDefaults("ANDY and BRUCE");
215 m_pDoc
->SetEditText(ScAddress(2,0,0), rEE
.CreateTextObject()); // C1
216 aSS2
= m_pDoc
->GetSharedString(ScAddress(2,0,0));
217 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
218 CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", aSS1
.getData() != aSS2
.getData());
220 // But they should be considered equal when cases are ignored.
221 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
222 aSS2
= m_pDoc
->GetSharedString(ScAddress(2,0,0));
223 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1
.isValid());
224 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
225 CPPUNIT_ASSERT_EQUAL(aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
227 m_pDoc
->DeleteTab(0);
230 CPPUNIT_TEST_FIXTURE(Test
, testSharedStringPoolUndoDoc
)
234 bool check( const ScDocument
& rSrcDoc
, ScDocument
& rCopyDoc
)
236 // Copy A1:A4 to the undo document.
237 for (SCROW i
= 0; i
<= 4; ++i
)
239 ScAddress
aPos(0,i
,0);
240 rCopyDoc
.SetString(aPos
, rSrcDoc
.GetString(aPos
));
243 // String values in A1:A4 should have identical hash.
244 for (SCROW i
= 0; i
<= 4; ++i
)
246 ScAddress
aPos(0,i
,0);
247 svl::SharedString aSS1
= rSrcDoc
.GetSharedString(aPos
);
248 svl::SharedString aSS2
= rCopyDoc
.GetSharedString(aPos
);
249 if (aSS1
.getDataIgnoreCase() != aSS2
.getDataIgnoreCase())
251 cerr
<< "String hash values are not equal at row " << (i
+1)
252 << " for string '" << aSS1
.getString() << "'" << endl
;
262 m_pDoc
->InsertTab(0, "Test");
264 m_pDoc
->SetString(ScAddress(0,0,0), "Header");
265 m_pDoc
->SetString(ScAddress(0,1,0), "A1");
266 m_pDoc
->SetString(ScAddress(0,2,0), "A2");
267 m_pDoc
->SetString(ScAddress(0,3,0), "A3");
269 ScDocument
aUndoDoc(SCDOCMODE_UNDO
);
270 aUndoDoc
.InitUndo(*m_pDoc
, 0, 0);
272 bool bSuccess
= aTest
.check(*m_pDoc
, aUndoDoc
);
273 CPPUNIT_ASSERT_MESSAGE("Check failed with undo document.", bSuccess
);
275 // Test the clip document as well.
276 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
277 aClipDoc
.ResetClip(m_pDoc
, static_cast<SCTAB
>(0));
279 bSuccess
= aTest
.check(*m_pDoc
, aClipDoc
);
280 CPPUNIT_ASSERT_MESSAGE("Check failed with clip document.", bSuccess
);
282 m_pDoc
->DeleteTab(0);
285 CPPUNIT_TEST_FIXTURE(Test
, testRangeList
)
287 m_pDoc
->InsertTab(0, "foo");
290 aRL
.push_back(ScRange(1,1,0,3,10,0));
291 CPPUNIT_ASSERT_EQUAL_MESSAGE("List should have one range.", size_t(1), aRL
.size());
292 const ScRange
* p
= &aRL
[0];
293 CPPUNIT_ASSERT_MESSAGE("Failed to get the range object.", p
);
294 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong range.", ScAddress(1,1,0), p
->aStart
);
295 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong range.", ScAddress(3,10,0), p
->aEnd
);
297 // TODO: Add more tests here.
299 m_pDoc
->DeleteTab(0);
302 CPPUNIT_TEST_FIXTURE(Test
, testMarkData
)
304 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
306 // Empty mark. Nothing is selected.
307 std::vector
<sc::ColRowSpan
> aSpans
= aMarkData
.GetMarkedRowSpans();
308 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans
.empty());
309 aSpans
= aMarkData
.GetMarkedColSpans();
310 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans
.empty());
313 aMarkData
.SetMarkArea(ScRange(1,2,0,5,6,0));
314 aSpans
= aMarkData
.GetMarkedRowSpans();
315 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected row span.", size_t(1), aSpans
.size());
316 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
317 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(6), aSpans
[0].mnEnd
);
319 aSpans
= aMarkData
.GetMarkedColSpans();
320 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
321 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(1), aSpans
[0].mnStart
);
322 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
325 aMarkData
.SetMultiMarkArea(ScRange(0,10,0,1,12,0));
326 aSpans
= aMarkData
.GetMarkedRowSpans();
327 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 2 selected row spans.", size_t(2), aSpans
.size());
328 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
329 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(6), aSpans
[0].mnEnd
);
330 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(10), aSpans
[1].mnStart
);
331 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(12), aSpans
[1].mnEnd
);
333 aSpans
= aMarkData
.GetMarkedColSpans();
334 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
335 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(0), aSpans
[0].mnStart
);
336 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
339 aMarkData
.SetMultiMarkArea(ScRange(2,7,0,2,9,0));
340 aSpans
= aMarkData
.GetMarkedRowSpans();
341 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected row span.", size_t(1), aSpans
.size());
342 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
343 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(12), aSpans
[0].mnEnd
);
345 aSpans
= aMarkData
.GetMarkedColSpans();
346 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
347 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(0), aSpans
[0].mnStart
);
348 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
351 CPPUNIT_TEST_FIXTURE(Test
, testInput
)
354 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
355 m_pDoc
->InsertTab (0, "foo"));
358 m_pDoc
->SetString(0, 0, 0, "'10.5");
359 test
= m_pDoc
->GetString(0, 0, 0);
360 bool bTest
= test
== "10.5";
361 CPPUNIT_ASSERT_MESSAGE("String number should have the first apostrophe stripped.", bTest
);
362 m_pDoc
->SetString(0, 0, 0, "'apple'");
363 test
= m_pDoc
->GetString(0, 0, 0);
364 bTest
= test
== "apple'";
365 CPPUNIT_ASSERT_MESSAGE("Text content should have the first apostrophe stripped.", bTest
);
367 // Customized string handling policy.
368 ScSetStringParam aParam
;
369 aParam
.setTextInput();
370 m_pDoc
->SetString(0, 0, 0, "000123", &aParam
);
371 test
= m_pDoc
->GetString(0, 0, 0);
372 CPPUNIT_ASSERT_EQUAL_MESSAGE("Text content should have been treated as string, not number.", OUString("000123"), test
);
374 m_pDoc
->DeleteTab(0);
377 CPPUNIT_TEST_FIXTURE(Test
, testColumnIterator
) // tdf#118620
379 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
380 m_pDoc
->InsertTab (0, "foo"));
382 m_pDoc
->SetString(0, 0, 0, "'10.5");
383 m_pDoc
->SetString(0, m_pDoc
->MaxRow()-5, 0, "42.0");
384 std::optional
<sc::ColumnIterator
> it
= m_pDoc
->GetColumnIterator(0, 0, m_pDoc
->MaxRow() - 10, m_pDoc
->MaxRow());
385 while (it
->hasCell())
391 m_pDoc
->DeleteTab(0);
394 CPPUNIT_TEST_FIXTURE(Test
, testTdf66613
)
396 // Create different print ranges and col/row repetitions for two tabs
397 const SCTAB nFirstTab
= 0;
398 CPPUNIT_ASSERT(m_pDoc
->InsertTab(nFirstTab
, "FirstPrintRange"));
399 ScRange
aFirstPrintRange(0, 0, nFirstTab
, 2, 2, nFirstTab
);
400 m_pDoc
->AddPrintRange(nFirstTab
, aFirstPrintRange
);
401 ScRange
aFirstRepeatColRange(0, 0, nFirstTab
, 0, 0, nFirstTab
);
402 m_pDoc
->SetRepeatColRange(nFirstTab
, aFirstRepeatColRange
);
403 ScRange
aFirstRepeatRowRange(1, 1, nFirstTab
, 1, 1, nFirstTab
);
404 m_pDoc
->SetRepeatRowRange(nFirstTab
, aFirstRepeatRowRange
);
406 const SCTAB nSecondTab
= 1;
407 CPPUNIT_ASSERT(m_pDoc
->InsertTab(nSecondTab
, "SecondPrintRange"));
408 ScRange
aSecondPrintRange(0, 0, nSecondTab
, 3, 3, nSecondTab
);
409 m_pDoc
->AddPrintRange(nSecondTab
, aSecondPrintRange
);
410 ScRange
aSecondRepeatColRange(1, 1, nSecondTab
, 1, 1, nSecondTab
);
411 m_pDoc
->SetRepeatColRange(nSecondTab
, aSecondRepeatColRange
);
412 ScRange
aSecondRepeatRowRange(2, 2, nSecondTab
, 2, 2, nSecondTab
);
413 m_pDoc
->SetRepeatRowRange(nSecondTab
, aSecondRepeatRowRange
);
415 // Transfer generated tabs to a new document with different order
416 ScDocument aScDocument
;
417 aScDocument
.TransferTab(*m_pDoc
, nSecondTab
, nFirstTab
);
418 aScDocument
.TransferTab(*m_pDoc
, nFirstTab
, nSecondTab
);
420 // Check the number of print ranges in both documents
421 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), m_pDoc
->GetPrintRangeCount(nFirstTab
));
422 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), m_pDoc
->GetPrintRangeCount(nSecondTab
));
423 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), aScDocument
.GetPrintRangeCount(nFirstTab
));
424 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), aScDocument
.GetPrintRangeCount(nSecondTab
));
426 // Check the print ranges and col/row repetitions in both documents
427 CPPUNIT_ASSERT_EQUAL(aFirstPrintRange
, *m_pDoc
->GetPrintRange(nFirstTab
, 0));
428 CPPUNIT_ASSERT_EQUAL(aFirstRepeatColRange
, *m_pDoc
->GetRepeatColRange(nFirstTab
));
429 CPPUNIT_ASSERT_EQUAL(aFirstRepeatRowRange
, *m_pDoc
->GetRepeatRowRange(nFirstTab
));
430 CPPUNIT_ASSERT_EQUAL(aSecondPrintRange
, *m_pDoc
->GetPrintRange(nSecondTab
, 0));
431 CPPUNIT_ASSERT_EQUAL(aSecondRepeatColRange
, *m_pDoc
->GetRepeatColRange(nSecondTab
));
432 CPPUNIT_ASSERT_EQUAL(aSecondRepeatRowRange
, *m_pDoc
->GetRepeatRowRange(nSecondTab
));
434 // Tabs have to be adjusted since the order of the tabs is inverted in the new document
435 std::vector
<ScRange
*> aScRanges
436 = { &aFirstPrintRange
, &aFirstRepeatColRange
, &aFirstRepeatRowRange
,
437 &aSecondPrintRange
, &aSecondRepeatColRange
, &aSecondRepeatRowRange
};
438 for (size_t i
= 0; i
< aScRanges
.size(); i
++)
440 const SCTAB nTab
= i
>= 3 ? nFirstTab
: nSecondTab
;
441 aScRanges
[i
]->aStart
.SetTab(nTab
);
442 aScRanges
[i
]->aEnd
.SetTab(nTab
);
445 // Without the fix in place, no print ranges and col/row repetitions would be present
446 CPPUNIT_ASSERT_EQUAL(aFirstPrintRange
, *aScDocument
.GetPrintRange(nSecondTab
, 0));
447 CPPUNIT_ASSERT_EQUAL(aFirstRepeatColRange
, *aScDocument
.GetRepeatColRange(nSecondTab
));
448 CPPUNIT_ASSERT_EQUAL(aFirstRepeatRowRange
, *aScDocument
.GetRepeatRowRange(nSecondTab
));
449 CPPUNIT_ASSERT_EQUAL(aSecondPrintRange
, *aScDocument
.GetPrintRange(nFirstTab
, 0));
450 CPPUNIT_ASSERT_EQUAL(aSecondRepeatColRange
, *aScDocument
.GetRepeatColRange(nFirstTab
));
451 CPPUNIT_ASSERT_EQUAL(aSecondRepeatRowRange
, *aScDocument
.GetRepeatRowRange(nFirstTab
));
453 m_pDoc
->DeleteTab(nFirstTab
);
454 m_pDoc
->DeleteTab(nSecondTab
);
457 CPPUNIT_TEST_FIXTURE(Test
, testTdf113027
)
459 // Insert some sheets including a whitespace in their name and switch the grammar to R1C1
460 CPPUNIT_ASSERT(m_pDoc
->InsertTab(0, "Sheet 1"));
461 CPPUNIT_ASSERT(m_pDoc
->InsertTab(1, "Sheet 2"));
462 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
464 // Add a formula containing a remote reference, i.e., to another sheet
465 const ScAddress
aScAddress(0, 0, 0);
466 static constexpr OUString aFormula
= u
"='Sheet 2'!RC"_ustr
;
467 m_pDoc
->SetString(aScAddress
, aFormula
);
469 // Switch from relative to absolute cell reference
470 ScRefFinder
aFinder(aFormula
, aScAddress
, *m_pDoc
, m_pDoc
->GetAddressConvention());
471 aFinder
.ToggleRel(0, aFormula
.getLength());
473 // Without the fix in place, this test would have failed with
474 // - Expected: ='Sheet 2'!R1C1
475 // - Actual : ='Sheet 2'!RC
476 // i.e. the cell reference was not changed from relative to absolute
477 CPPUNIT_ASSERT_EQUAL(OUString("='Sheet 2'!R1C1"), aFinder
.GetText());
479 m_pDoc
->DeleteTab(0);
480 m_pDoc
->DeleteTab(1);
483 CPPUNIT_TEST_FIXTURE(Test
, testTdf90698
)
485 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
486 m_pDoc
->SetString(ScAddress(0,0,0), "=(1;2)");
488 // Without the fix in place, this would have failed with
489 // - Expected: =(1;2)
491 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
492 CPPUNIT_ASSERT_EQUAL(OUString("=(1;2)"), aFormula
);
494 m_pDoc
->DeleteTab(0);
497 CPPUNIT_TEST_FIXTURE(Test
, testTdf114406
)
499 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
500 m_pDoc
->SetString(ScAddress(0,0,0), "5");
501 m_pDoc
->SetString(ScAddress(1,0,0), "=A1/100%");
503 // Without the fix in place, this would have failed with
504 // - Expected: =A1/100%
506 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
507 CPPUNIT_ASSERT_EQUAL(OUString("=A1/100%"), aFormula
);
509 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
511 m_pDoc
->DeleteTab(0);
514 CPPUNIT_TEST_FIXTURE(Test
, testTdf93951
)
516 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
517 m_pDoc
->SetString(ScAddress(0,0,0), u
"=2*§*2"_ustr
);
519 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
521 // Without the fix in place, this test would have failed with
522 // - Expected: =2*§*2
524 CPPUNIT_ASSERT_EQUAL(u
"=2*§*2"_ustr
, aFormula
);
526 m_pDoc
->DeleteTab(0);
529 CPPUNIT_TEST_FIXTURE(Test
, testTdf134490
)
531 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
533 m_pDoc
->SetString(ScAddress(0,0,0), "--1");
534 m_pDoc
->SetString(ScAddress(0,1,0), "---1");
535 m_pDoc
->SetString(ScAddress(0,2,0), "+-1");
536 m_pDoc
->SetString(ScAddress(0,3,0), "+--1");
538 // Without the fix in place, this test would have failed with
541 CPPUNIT_ASSERT_EQUAL(OUString("--1"), m_pDoc
->GetString(ScAddress(0,0,0)));
542 CPPUNIT_ASSERT_EQUAL(OUString("---1"), m_pDoc
->GetString(ScAddress(0,1,0)));
543 CPPUNIT_ASSERT_EQUAL(OUString("+-1"), m_pDoc
->GetString(ScAddress(0,2,0)));
544 CPPUNIT_ASSERT_EQUAL(OUString("+--1"), m_pDoc
->GetString(ScAddress(0,3,0)));
546 m_pDoc
->DeleteTab(0);
549 CPPUNIT_TEST_FIXTURE(Test
, testTdf135249
)
551 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
553 m_pDoc
->SetString(ScAddress(0,0,0), "1:60");
554 m_pDoc
->SetString(ScAddress(0,1,0), "1:123");
555 m_pDoc
->SetString(ScAddress(0,2,0), "1:1:123");
556 m_pDoc
->SetString(ScAddress(0,3,0), "0:123");
557 m_pDoc
->SetString(ScAddress(0,4,0), "0:0:123");
558 m_pDoc
->SetString(ScAddress(0,5,0), "0:123:59");
560 // These are not valid duration inputs
561 CPPUNIT_ASSERT_EQUAL(OUString("1:60"), m_pDoc
->GetString(ScAddress(0,0,0)));
562 CPPUNIT_ASSERT_EQUAL(OUString("1:123"), m_pDoc
->GetString(ScAddress(0,1,0)));
563 CPPUNIT_ASSERT_EQUAL(OUString("1:1:123"), m_pDoc
->GetString(ScAddress(0,2,0)));
565 // These are valid duration inputs
566 // Without the fix in place, this test would have failed with
567 // - Expected: 02:03:00 AM
569 CPPUNIT_ASSERT_EQUAL(OUString("02:03:00 AM"), m_pDoc
->GetString(ScAddress(0,3,0)));
570 CPPUNIT_ASSERT_EQUAL(OUString("12:02:03 AM"), m_pDoc
->GetString(ScAddress(0,4,0)));
571 CPPUNIT_ASSERT_EQUAL(OUString("02:03:59 AM"), m_pDoc
->GetString(ScAddress(0,5,0)));
573 m_pDoc
->DeleteTab(0);
576 CPPUNIT_TEST_FIXTURE(Test
, testDocStatistics
)
578 SCTAB nStartTabs
= m_pDoc
->GetTableCount();
579 m_pDoc
->InsertTab(0, "Sheet1");
580 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
581 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
582 m_pDoc
->InsertTab(1, "Sheet2");
583 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
584 static_cast<SCTAB
>(nStartTabs
+2), m_pDoc
->GetTableCount());
586 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(0), m_pDoc
->GetCellCount());
587 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0);
588 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetCellCount());
589 m_pDoc
->SetValue(ScAddress(2,2,0), 2.5);
590 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetCellCount());
591 m_pDoc
->SetString(ScAddress(1,1,1), "Test");
592 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(3), m_pDoc
->GetCellCount());
594 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(0), m_pDoc
->GetFormulaGroupCount());
595 m_pDoc
->SetString(ScAddress(3,0,1), "=A1");
596 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
597 m_pDoc
->SetString(ScAddress(3,1,1), "=A2");
598 m_pDoc
->SetString(ScAddress(3,2,1), "=A3");
599 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
600 m_pDoc
->SetString(ScAddress(3,3,1), "=A5");
601 m_pDoc
->SetString(ScAddress(3,4,1), "=A6");
602 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetFormulaGroupCount());
603 m_pDoc
->SetString(ScAddress(3,1,1), "=A3");
604 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(4), m_pDoc
->GetFormulaGroupCount());
606 m_pDoc
->DeleteTab(1);
607 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to decrement sheet count.",
608 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
609 m_pDoc
->DeleteTab(0); // This may fail in case there is only one sheet in the document.
612 CPPUNIT_TEST_FIXTURE(Test
, testRowForHeight
)
614 m_pDoc
->InsertTab(0, "Sheet1");
615 m_pDoc
->SetRowHeightRange( 0, 9, 0, 100);
616 m_pDoc
->SetRowHeightRange(10, 19, 0, 200);
617 m_pDoc
->SetRowHeightRange(20, 29, 0, 300);
620 m_pDoc
->SetRowHidden(3, 5, 0, true);
621 m_pDoc
->SetRowHidden(8, 12, 0, true);
629 std::vector
<Check
> aChecks
= {
640 for (const Check
& rCheck
: aChecks
)
642 SCROW nRow
= m_pDoc
->GetRowForHeight(0, rCheck
.nHeight
);
643 CPPUNIT_ASSERT_EQUAL(rCheck
.nRow
, nRow
);
647 CPPUNIT_TEST_FIXTURE(Test
, testDataEntries
)
650 * The 'data entries' data is a list of strings used for suggestions as
651 * the user types in new cell value.
653 m_pDoc
->InsertTab(0, "Test");
655 m_pDoc
->SetString(ScAddress(0,5,0), "Andy");
656 m_pDoc
->SetString(ScAddress(0,6,0), "Bruce");
657 m_pDoc
->SetString(ScAddress(0,7,0), "Charlie");
658 m_pDoc
->SetString(ScAddress(0,10,0), "Andy");
660 std::vector
<ScTypedStrData
> aEntries
;
661 m_pDoc
->GetDataEntries(0, 0, 0, aEntries
); // Try at the very top.
663 // Entries are supposed to be sorted in ascending order, and are all unique.
664 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries
.size());
665 std::vector
<ScTypedStrData
>::const_iterator it
= aEntries
.begin();
666 CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it
->GetString());
668 CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it
->GetString());
670 CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it
->GetString());
672 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", bool(it
== aEntries
.end()));
675 m_pDoc
->GetDataEntries(0, m_pDoc
->MaxRow(), 0, aEntries
); // Try at the very bottom.
676 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries
.size());
678 // Make sure we get the same set of suggestions.
679 it
= aEntries
.begin();
680 CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it
->GetString());
682 CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it
->GetString());
684 CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it
->GetString());
686 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", bool(it
== aEntries
.end()));
688 m_pDoc
->DeleteTab(0);
691 CPPUNIT_TEST_FIXTURE(Test
, testSelectionFunction
)
694 * Selection function is responsible for displaying quick calculation
695 * results in the status bar.
697 m_pDoc
->InsertTab(0, "Test");
699 // Insert values into B2:B4.
700 m_pDoc
->SetString(ScAddress(1,1,0), "=1"); // formula
701 m_pDoc
->SetValue(ScAddress(1,2,0), 2.0);
702 m_pDoc
->SetValue(ScAddress(1,3,0), 3.0);
704 // Insert strings into B5:B8.
705 m_pDoc
->SetString(ScAddress(1,4,0), "A");
706 m_pDoc
->SetString(ScAddress(1,5,0), "B");
707 m_pDoc
->SetString(ScAddress(1,6,0), "=\"C\""); // formula
708 m_pDoc
->SetString(ScAddress(1,7,0), "D");
710 // Insert values into D2:D4.
711 m_pDoc
->SetValue(ScAddress(3,1,0), 4.0);
712 m_pDoc
->SetValue(ScAddress(3,2,0), 5.0);
713 m_pDoc
->SetValue(ScAddress(3,3,0), 6.0);
715 // Insert edit text into D5.
716 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
717 rEE
.SetTextCurrentDefaults("Rich Text");
718 m_pDoc
->SetEditText(ScAddress(3,4,0), rEE
.CreateTextObject());
720 // Insert Another string into D6.
721 m_pDoc
->SetString(ScAddress(3,5,0), "E");
723 // Select B2:B8 & D2:D8 disjoint region.
725 aRanges
.push_back(ScRange(1,1,0,1,7,0)); // B2:B8
726 aRanges
.push_back(ScRange(3,1,0,3,7,0)); // D2:D8
727 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
728 aMark
.MarkFromRangeList(aRanges
, true);
732 ScSubTotalFunc meFunc
;
737 static const Check aChecks
[] =
739 { SUBTOTAL_FUNC_AVE
, 3.5 },
740 { SUBTOTAL_FUNC_CNT2
, 12.0 },
741 { SUBTOTAL_FUNC_CNT
, 6.0 },
742 { SUBTOTAL_FUNC_MAX
, 6.0 },
743 { SUBTOTAL_FUNC_MIN
, 1.0 },
744 { SUBTOTAL_FUNC_SUM
, 21.0 },
745 { SUBTOTAL_FUNC_SELECTION_COUNT
, 14.0 }
748 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
751 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, ScAddress(), aMark
, fRes
);
752 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
753 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
757 // Hide rows 4 and 6 and check the results again.
759 m_pDoc
->SetRowHidden(3, 3, 0, true);
760 m_pDoc
->SetRowHidden(5, 5, 0, true);
761 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc
->RowHidden(3, 0));
762 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc
->RowHidden(5, 0));
765 static const Check aChecks
[] =
767 { SUBTOTAL_FUNC_AVE
, 3.0 },
768 { SUBTOTAL_FUNC_CNT2
, 8.0 },
769 { SUBTOTAL_FUNC_CNT
, 4.0 },
770 { SUBTOTAL_FUNC_MAX
, 5.0 },
771 { SUBTOTAL_FUNC_MIN
, 1.0 },
772 { SUBTOTAL_FUNC_SUM
, 12.0 },
773 { SUBTOTAL_FUNC_SELECTION_COUNT
, 10.0 }
776 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
779 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, ScAddress(), aMark
, fRes
);
780 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
781 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
785 // Make sure that when no selection is present, use the current cursor position.
786 ScMarkData
aEmpty(m_pDoc
->GetSheetLimits());
789 // D3 (numeric cell containing 5.)
790 ScAddress
aPos(3, 2, 0);
792 static const Check aChecks
[] =
794 { SUBTOTAL_FUNC_AVE
, 5.0 },
795 { SUBTOTAL_FUNC_CNT2
, 1.0 },
796 { SUBTOTAL_FUNC_CNT
, 1.0 },
797 { SUBTOTAL_FUNC_MAX
, 5.0 },
798 { SUBTOTAL_FUNC_MIN
, 5.0 },
799 { SUBTOTAL_FUNC_SUM
, 5.0 },
800 { SUBTOTAL_FUNC_SELECTION_COUNT
, 1.0 }
803 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
806 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, aPos
, aEmpty
, fRes
);
807 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
808 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
813 // B7 (string formula cell containing ="C".)
814 ScAddress
aPos(1, 6, 0);
816 static const Check aChecks
[] =
818 { SUBTOTAL_FUNC_CNT2
, 1.0 },
819 { SUBTOTAL_FUNC_SELECTION_COUNT
, 1.0 }
822 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
825 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, aPos
, aEmpty
, fRes
);
826 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
827 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
831 // Calculate function across selected sheets.
832 clearSheet(m_pDoc
, 0);
833 m_pDoc
->InsertTab(1, "Test2");
834 m_pDoc
->InsertTab(2, "Test3");
836 // Set values at B2 and C3 on each sheet.
837 m_pDoc
->SetValue(ScAddress(1,1,0), 1.0);
838 m_pDoc
->SetValue(ScAddress(2,2,0), 2.0);
839 m_pDoc
->SetValue(ScAddress(1,1,1), 4.0);
840 m_pDoc
->SetValue(ScAddress(2,2,1), 8.0);
841 m_pDoc
->SetValue(ScAddress(1,1,2), 16.0);
842 m_pDoc
->SetValue(ScAddress(2,2,2), 32.0);
844 // Mark B2 and C3 on first sheet.
846 aRanges
.push_back(ScRange(1,1,0)); // B2
847 aRanges
.push_back(ScRange(2,2,0)); // C3
848 aMark
.MarkFromRangeList(aRanges
, true);
849 // Additionally select third sheet.
850 aMark
.SelectTable(2, true);
854 bool bRes
= m_pDoc
->GetSelectionFunction( SUBTOTAL_FUNC_SUM
, ScAddress(), aMark
, fRes
);
855 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
856 CPPUNIT_ASSERT_EQUAL_MESSAGE("1+2+16+32=", 51.0, fRes
);
859 m_pDoc
->DeleteTab(2);
860 m_pDoc
->DeleteTab(1);
861 m_pDoc
->DeleteTab(0);
864 CPPUNIT_TEST_FIXTURE(Test
, testMarkedCellIteration
)
866 m_pDoc
->InsertTab(0, "Test");
868 // Insert cells to A1, A5, B2 and C3.
869 m_pDoc
->SetString(ScAddress(0,0,0), "California");
870 m_pDoc
->SetValue(ScAddress(0,4,0), 1.2);
871 m_pDoc
->SetEditText(ScAddress(1,1,0), "Boston");
872 m_pDoc
->SetFormula(ScAddress(2,2,0), "=SUM(1,2,3)", m_pDoc
->GetGrammar());
875 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
876 aMarkData
.SetMarkArea(ScRange(0,0,0,2,4,0));
877 aMarkData
.MarkToMulti(); // TODO : we shouldn't have to do this.
885 const std::vector
<Check
> aChecks
= {
892 SCROW nRow
= -1; // Start from the imaginary row before A1.
895 for (const Check
& rCheck
: aChecks
)
897 bool bFound
= m_pDoc
->GetNextMarkedCell(nCol
, nRow
, 0, aMarkData
);
900 std::ostringstream os
;
901 os
<< ScAddress(rCheck
.mnCol
, rCheck
.mnRow
, 0).GetColRowString() << " was expected, but not found.";
902 CPPUNIT_FAIL(os
.str());
905 CPPUNIT_ASSERT_EQUAL(rCheck
.mnRow
, nRow
);
906 CPPUNIT_ASSERT_EQUAL(rCheck
.mnCol
, nCol
);
909 // No more marked cells on this sheet.
910 bool bFound
= m_pDoc
->GetNextMarkedCell(nCol
, nRow
, 0, aMarkData
);
911 CPPUNIT_ASSERT(!bFound
);
913 m_pDoc
->DeleteTab(0);
916 CPPUNIT_TEST_FIXTURE(Test
, testCopyToDocument
)
918 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, "src"));
920 // We need a drawing layer in order to create caption objects.
921 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
923 m_pDoc
->SetString(0, 0, 0, "Header");
924 m_pDoc
->SetString(0, 1, 0, "1");
925 m_pDoc
->SetString(0, 2, 0, "2");
926 m_pDoc
->SetString(0, 3, 0, "3");
927 m_pDoc
->SetString(0, 4, 0, "=4/2");
931 ScAddress
aAdrA1 (0, 0, 0); // numerical cell content
932 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
933 pNote
->SetText(aAdrA1
, "Hello world in A1");
935 // Copy statically to another document.
937 ScDocShellRef xDocSh2
;
938 getNewDocShell(xDocSh2
);
939 ScDocument
* pDestDoc
= &xDocSh2
->GetDocument();
940 pDestDoc
->InsertTab(0, "src");
941 pDestDoc
->InitDrawLayer(xDocSh2
.get()); // for note caption objects
943 m_pDoc
->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, *pDestDoc
); // Copy A2:A4
944 m_pDoc
->CopyStaticToDocument(ScAddress(0,0,0), 0, *pDestDoc
); // Copy A1
945 m_pDoc
->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, *pDestDoc
); // Copy A5:A8
947 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,0,0), pDestDoc
->GetString(0,0,0));
948 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,1,0), pDestDoc
->GetString(0,1,0));
949 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,2,0), pDestDoc
->GetString(0,2,0));
950 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,3,0), pDestDoc
->GetString(0,3,0));
951 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,4,0), pDestDoc
->GetString(0,4,0));
954 CPPUNIT_ASSERT_MESSAGE("There should be a note in A1 destDocument", pDestDoc
->HasNote(ScAddress(0, 0, 0)));
955 CPPUNIT_ASSERT_EQUAL_MESSAGE("The notes content should be the same on both documents",
956 m_pDoc
->GetNote(ScAddress(0, 0, 0))->GetText(), pDestDoc
->GetNote(ScAddress(0, 0, 0))->GetText());
958 pDestDoc
->DeleteTab(0);
962 m_pDoc
->DeleteTab(0);
965 bool Test::checkHorizontalIterator(ScDocument
& rDoc
, const std::vector
<std::vector
<const char*>>& rData
, const HoriIterCheck
* pChecks
, size_t nCheckCount
)
967 ScAddress
aPos(0,0,0);
968 insertRangeData(&rDoc
, aPos
, rData
);
969 ScHorizontalCellIterator
aIter(rDoc
, 0, 0, 0, 1, rData
.size() - 1);
974 for (ScRefCellValue
* pCell
= aIter
.GetNext(nCol
, nRow
); pCell
; pCell
= aIter
.GetNext(nCol
, nRow
), ++i
)
976 if (i
>= nCheckCount
)
978 cerr
<< "hit invalid check " << i
<< " of " << nCheckCount
<< endl
;
979 CPPUNIT_FAIL("Iterator claims there is more data than there should be.");
983 if (pChecks
[i
].nCol
!= nCol
)
985 cerr
<< "Column mismatch " << pChecks
[i
].nCol
<< " vs. " << nCol
<< endl
;
989 if (pChecks
[i
].nRow
!= nRow
)
991 cerr
<< "Row mismatch " << pChecks
[i
].nRow
<< " vs. " << nRow
<< endl
;
995 if (OUString::createFromAscii(pChecks
[i
].pVal
) != pCell
->getString(&rDoc
))
997 cerr
<< "String mismatch " << pChecks
[i
].pVal
<< " vs. " <<
998 pCell
->getString(&rDoc
) << endl
;
1006 CPPUNIT_TEST_FIXTURE(Test
, testHorizontalIterator
)
1008 m_pDoc
->InsertTab(0, "test");
1011 // Raw data - mixed types
1012 std::vector
<std::vector
<const char*>> aData
= {
1019 static const HoriIterCheck aChecks
[] = {
1030 bool bRes
= checkHorizontalIterator(
1031 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1034 CPPUNIT_FAIL("Failed on test mixed.");
1038 // Raw data - 'hole' data
1039 std::vector
<std::vector
<const char*>> aData
= {
1045 static const HoriIterCheck aChecks
[] = {
1053 bool bRes
= checkHorizontalIterator(
1054 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1057 CPPUNIT_FAIL("Failed on test hole.");
1062 std::vector
<std::vector
<const char*>> aData
= {
1064 { nullptr, nullptr },
1071 { nullptr, nullptr },
1074 static const HoriIterCheck aChecks
[] = {
1086 bool bRes
= checkHorizontalIterator(
1087 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1090 CPPUNIT_FAIL("Failed on test holy.");
1095 std::vector
<std::vector
<const char*>> aData
= {
1096 { nullptr, nullptr },
1097 { nullptr, nullptr },
1098 { nullptr, nullptr },
1101 bool bRes
= checkHorizontalIterator(
1102 *m_pDoc
, aData
, nullptr, 0);
1105 CPPUNIT_FAIL("Failed on test degenerate.");
1110 std::vector
<std::vector
<const char*>> aData
= {
1111 { nullptr, nullptr },
1112 { nullptr, nullptr },
1116 static const HoriIterCheck aChecks
[] = {
1120 bool bRes
= checkHorizontalIterator(
1121 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1124 CPPUNIT_FAIL("Failed on test at end.");
1129 std::vector
<std::vector
<const char*>> aData
= {
1130 { nullptr, nullptr },
1131 { nullptr, nullptr },
1134 { nullptr, nullptr },
1137 static const HoriIterCheck aChecks
[] = {
1142 bool bRes
= checkHorizontalIterator(
1143 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1146 CPPUNIT_FAIL("Failed on test in middle.");
1149 m_pDoc
->DeleteTab(0);
1152 CPPUNIT_TEST_FIXTURE(Test
, testValueIterator
)
1154 m_pDoc
->InsertTab(0, "Test");
1156 // Turn on "precision as shown" option.
1157 ScDocOptions aOpt
= m_pDoc
->GetDocOptions();
1158 aOpt
.SetCalcAsShown(true);
1159 m_pDoc
->SetDocOptions(aOpt
);
1161 ScInterpreterContext
aContext(*m_pDoc
, m_pDoc
->GetFormatTable());
1163 // Purely horizontal data layout with numeric data.
1164 for (SCCOL i
= 1; i
<= 3; ++i
)
1165 m_pDoc
->SetValue(ScAddress(i
,2,0), i
);
1168 const double aChecks
[] = { 1.0, 2.0, 3.0 };
1169 size_t const nCheckLen
= SAL_N_ELEMENTS(aChecks
);
1170 ScValueIterator
aIter(aContext
, ScRange(1,2,0,3,2,0));
1172 size_t nCheckPos
= 0;
1175 for (bHas
= aIter
.GetFirst(fVal
, nErr
); bHas
; bHas
= aIter
.GetNext(fVal
, nErr
), ++nCheckPos
)
1177 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos
< nCheckLen
);
1178 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
], fVal
);
1179 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(nErr
));
1183 m_pDoc
->DeleteTab(0);
1186 CPPUNIT_TEST_FIXTURE(Test
, testHorizontalAttrIterator
)
1188 m_pDoc
->InsertTab(0, "Test");
1190 // Set the background color of B2:C3,D2,E3,C4:D4,B5:D5 to blue
1191 ScPatternAttr
aCellBackColor(m_pDoc
->GetPool());
1192 aCellBackColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
1193 m_pDoc
->ApplyPatternAreaTab(1, 1, 2, 2, 0, aCellBackColor
);
1194 m_pDoc
->ApplyPatternAreaTab(3, 1, 3, 1, 0, aCellBackColor
);
1195 m_pDoc
->ApplyPatternAreaTab(4, 2, 4, 2, 0, aCellBackColor
);
1196 m_pDoc
->ApplyPatternAreaTab(2, 3, 3, 3, 0, aCellBackColor
);
1197 m_pDoc
->ApplyPatternAreaTab(1, 4, 4, 4, 0, aCellBackColor
);
1199 // some numeric data
1200 for (SCCOL i
= 1; i
<= 4; ++i
)
1201 for (SCROW j
= 1; j
<= 4; ++j
)
1202 m_pDoc
->SetValue(ScAddress(i
,j
,0), i
*10+j
);
1205 const int aChecks
[][3] = { {1, 3, 1}, {1, 2, 2}, {4, 4, 2}, {2, 3, 3}, {1, 4, 4} };
1206 const size_t nCheckLen
= SAL_N_ELEMENTS(aChecks
);
1208 ScHorizontalAttrIterator
aIter(*m_pDoc
, 0, 0, 0, 5, 5);
1211 size_t nCheckPos
= 0;
1212 for (const ScPatternAttr
* pAttr
= aIter
.GetNext(nCol1
, nCol2
, nRow
); pAttr
; pAttr
= aIter
.GetNext(nCol1
, nCol2
, nRow
))
1214 if (SfxPoolItem::areSame( pAttr
, m_pDoc
->GetDefPattern()))
1216 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos
< nCheckLen
);
1217 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][0], static_cast<int>(nCol1
));
1218 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][1], static_cast<int>(nCol2
));
1219 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][2], static_cast<int>(nRow
));
1224 m_pDoc
->DeleteTab(0);
1227 CPPUNIT_TEST_FIXTURE(Test
, testIteratorsUnallocatedColumnsAttributes
)
1229 m_pDoc
->InsertTab(0, "Tab1");
1231 // Set values in first two columns, to ensure allocation of those columns.
1232 m_pDoc
->SetValue(ScAddress(0,1,0), 1);
1233 m_pDoc
->SetValue(ScAddress(1,1,0), 2);
1234 constexpr SCCOL allocatedColsCount
= 2;
1235 assert( allocatedColsCount
>= INITIALCOLCOUNT
);
1236 CPPUNIT_ASSERT_EQUAL(allocatedColsCount
, m_pDoc
->GetAllocatedColumnsCount(0));
1238 // Make entire second row and third row bold.
1239 ScPatternAttr
boldAttr(m_pDoc
->GetPool());
1240 boldAttr
.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD
, ATTR_FONT_WEIGHT
));
1241 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 2, 0, boldAttr
);
1243 // That shouldn't need allocating more columns, just changing the default attribute.
1244 CPPUNIT_ASSERT_EQUAL(allocatedColsCount
, m_pDoc
->GetAllocatedColumnsCount(0));
1246 const ScPatternAttr
* pattern
= m_pDoc
->GetPattern(m_pDoc
->MaxCol(), 1, 0);
1247 pattern
->fillFontOnly(aFont
);
1248 CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD
, aFont
.GetWeight());
1251 ScDocAttrIterator
docit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1254 CPPUNIT_ASSERT_EQUAL( pattern
, docit
.GetNext( col1
, row1
, row2
));
1255 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1256 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1257 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1258 CPPUNIT_ASSERT_EQUAL( pattern
, docit
.GetNext( col1
, row1
, row2
));
1259 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col1
);
1260 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1261 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1262 CPPUNIT_ASSERT( docit
.GetNext( col1
, row1
, row2
) == nullptr );
1264 ScAttrRectIterator
rectit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1265 CPPUNIT_ASSERT_EQUAL( pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1266 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1267 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1268 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1269 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1270 CPPUNIT_ASSERT( rectit
.GetNext( col1
, col2
, row1
, row2
) == nullptr );
1272 ScHorizontalAttrIterator
horit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1273 CPPUNIT_ASSERT_EQUAL( pattern
, horit
.GetNext( col1
, col2
, row1
));
1274 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1275 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1276 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1277 CPPUNIT_ASSERT_EQUAL( pattern
, horit
.GetNext( col1
, col2
, row1
));
1278 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1279 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1280 CPPUNIT_ASSERT_EQUAL( SCROW(2), row1
);
1281 CPPUNIT_ASSERT( horit
.GetNext( col1
, col2
, row1
) == nullptr );
1283 m_pDoc
->DeleteTab(0);
1286 CPPUNIT_TEST_FIXTURE(Test
, testIteratorsDefPattern
)
1288 m_pDoc
->InsertTab(0, "Tab1");
1290 // The default pattern is the default style, which can be edited by the user.
1291 // As such iterators should not ignore it by default, because it might contain
1292 // some attributes set.
1294 // Set cells as bold, default allocated, bold, default unallocated.
1295 SCCOL firstCol
= 100;
1296 SCCOL lastCol
= 103;
1297 ScPatternAttr
boldAttr(m_pDoc
->GetPool());
1298 boldAttr
.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD
, ATTR_FONT_WEIGHT
));
1299 m_pDoc
->ApplyPattern(100, 0, 0, boldAttr
);
1300 m_pDoc
->ApplyPattern(102, 0, 0, boldAttr
);
1302 CPPUNIT_ASSERT_EQUAL(SCCOL(102 + 1), m_pDoc
->GetAllocatedColumnsCount(0));
1303 const ScPatternAttr
* pattern
= m_pDoc
->GetPattern(100, 0, 0);
1304 const ScPatternAttr
* defPattern
= m_pDoc
->GetDefPattern();
1305 CPPUNIT_ASSERT(!SfxPoolItem::areSame(pattern
, defPattern
));
1306 CPPUNIT_ASSERT_EQUAL(pattern
, m_pDoc
->GetPattern(102, 0, 0));
1307 CPPUNIT_ASSERT_EQUAL(defPattern
, m_pDoc
->GetPattern(101, 0, 0));
1308 CPPUNIT_ASSERT_EQUAL(defPattern
, m_pDoc
->GetPattern(103, 0, 0));
1311 ScDocAttrIterator
docit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1314 CPPUNIT_ASSERT_EQUAL(pattern
, docit
.GetNext( col1
, row1
, row2
));
1315 CPPUNIT_ASSERT_EQUAL(defPattern
, docit
.GetNext( col1
, row1
, row2
));
1316 CPPUNIT_ASSERT_EQUAL(pattern
, docit
.GetNext( col1
, row1
, row2
));
1317 CPPUNIT_ASSERT_EQUAL(defPattern
, docit
.GetNext( col1
, row1
, row2
));
1318 CPPUNIT_ASSERT(docit
.GetNext( col1
, row1
, row2
) == nullptr );
1320 ScAttrRectIterator
rectit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1321 CPPUNIT_ASSERT_EQUAL(pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1322 CPPUNIT_ASSERT_EQUAL(defPattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1323 CPPUNIT_ASSERT_EQUAL(pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1324 CPPUNIT_ASSERT_EQUAL(defPattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1325 CPPUNIT_ASSERT(rectit
.GetNext( col1
, col2
, row1
, row2
) == nullptr );
1327 ScHorizontalAttrIterator
horit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1328 CPPUNIT_ASSERT_EQUAL(pattern
, horit
.GetNext( col1
, col2
, row1
));
1329 CPPUNIT_ASSERT_EQUAL(defPattern
, horit
.GetNext( col1
, col2
, row1
));
1330 CPPUNIT_ASSERT_EQUAL(pattern
, horit
.GetNext( col1
, col2
, row1
));
1331 CPPUNIT_ASSERT_EQUAL(defPattern
, horit
.GetNext( col1
, col2
, row1
));
1332 CPPUNIT_ASSERT(horit
.GetNext( col1
, col2
, row1
) == nullptr );
1334 m_pDoc
->DeleteTab(0);
1337 CPPUNIT_TEST_FIXTURE(Test
, testLastChangedColFlagsWidth
)
1339 m_pDoc
->InsertTab(0, "Tab1");
1341 constexpr SCCOL firstChangedCol
= 100;
1342 assert( firstChangedCol
> m_pDoc
->GetAllocatedColumnsCount(0));
1343 CPPUNIT_ASSERT_EQUAL(INITIALCOLCOUNT
, m_pDoc
->GetAllocatedColumnsCount(0));
1344 for( SCCOL col
= firstChangedCol
; col
<= m_pDoc
->MaxCol(); ++col
)
1345 m_pDoc
->SetColWidth( col
, 0, 10 );
1347 // That shouldn't need allocating more columns, just changing column flags.
1348 CPPUNIT_ASSERT_EQUAL(INITIALCOLCOUNT
, m_pDoc
->GetAllocatedColumnsCount(0));
1349 // But the flags are changed.
1350 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), m_pDoc
->GetLastChangedColFlagsWidth(0));
1352 m_pDoc
->DeleteTab(0);
1357 bool broadcasterShifted(const ScDocument
& rDoc
, const ScAddress
& rFrom
, const ScAddress
& rTo
)
1359 const SvtBroadcaster
* pBC
= rDoc
.GetBroadcaster(rFrom
);
1362 cerr
<< "Broadcaster shouldn't be here." << endl
;
1366 pBC
= rDoc
.GetBroadcaster(rTo
);
1369 cerr
<< "Broadcaster should be here." << endl
;
1375 formula::FormulaToken
* getSingleRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
)
1377 ScFormulaCell
* pFC
= rDoc
.GetFormulaCell(rPos
);
1380 cerr
<< "Formula cell expected, but not found." << endl
;
1384 ScTokenArray
* pTokens
= pFC
->GetCode();
1387 cerr
<< "Token array is not present." << endl
;
1391 formula::FormulaToken
* pToken
= pTokens
->FirstToken();
1392 if (!pToken
|| pToken
->GetType() != formula::svSingleRef
)
1394 cerr
<< "Not a single reference token." << endl
;
1401 bool checkRelativeRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
, SCCOL nRelCol
, SCROW nRelRow
)
1403 formula::FormulaToken
* pToken
= getSingleRefToken(rDoc
, rPos
);
1407 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
1408 if (!rRef
.IsColRel() || rRef
.Col() != nRelCol
)
1410 cerr
<< "Unexpected relative column address." << endl
;
1414 if (!rRef
.IsRowRel() || rRef
.Row() != nRelRow
)
1416 cerr
<< "Unexpected relative row address." << endl
;
1423 bool checkDeletedRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
)
1425 formula::FormulaToken
* pToken
= getSingleRefToken(rDoc
, rPos
);
1429 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
1430 if (!rRef
.IsDeleted())
1432 cerr
<< "Deleted reference is expected, but it's still a valid reference." << endl
;
1441 CPPUNIT_TEST_FIXTURE(Test
, testCellBroadcaster
)
1444 * More direct test for cell broadcaster management, used to track formula
1447 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, "foo"));
1449 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calculation.
1450 m_pDoc
->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1451 double val
= m_pDoc
->GetValue(ScAddress(1,0,0)); // A1 is empty, so the result should be 0.
1452 CPPUNIT_ASSERT_EQUAL(0.0, val
);
1454 const SvtBroadcaster
* pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1455 CPPUNIT_ASSERT_MESSAGE("Cell A1 should have a broadcaster.", pBC
);
1457 // Change the value of A1 and make sure that B1 follows.
1458 m_pDoc
->SetValue(ScAddress(0,0,0), 1.23);
1459 val
= m_pDoc
->GetValue(ScAddress(1,0,0));
1460 CPPUNIT_ASSERT_EQUAL(1.23, val
);
1462 // Move column A down 5 cells. Make sure B1 now references A6, not A1.
1463 m_pDoc
->InsertRow(0, 0, 0, 0, 0, 5);
1464 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1465 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 5));
1467 // Make sure the broadcaster has also moved.
1468 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1469 broadcasterShifted(*m_pDoc
, ScAddress(0,0,0), ScAddress(0,5,0)));
1471 // Set new value to A6 and make sure B1 gets updated.
1472 m_pDoc
->SetValue(ScAddress(0,5,0), 45.6);
1473 val
= m_pDoc
->GetValue(ScAddress(1,0,0));
1474 CPPUNIT_ASSERT_EQUAL(45.6, val
);
1476 // Move column A up 3 cells, and make sure B1 now references A3, not A6.
1477 m_pDoc
->DeleteRow(0, 0, 0, 0, 0, 3);
1478 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1479 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 2));
1481 // The broadcaster should also have been relocated from A6 to A3.
1482 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1483 broadcasterShifted(*m_pDoc
, ScAddress(0,5,0), ScAddress(0,2,0)));
1485 // Insert cells over A1:A10 and shift cells to right.
1486 m_pDoc
->InsertCol(ScRange(0, 0, 0, 0, 10, 0));
1487 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1488 checkRelativeRefToken(*m_pDoc
, ScAddress(2,0,0), -1, 2));
1489 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1490 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(1,2,0)));
1492 // Delete formula in C2, which should remove the broadcaster in B3.
1493 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,2,0));
1494 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should still exist.", pBC
);
1495 clearRange(m_pDoc
, ScAddress(2,0,0));
1496 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(2,0,0))); // C2 should be empty.
1497 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,2,0));
1498 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should have been removed.", !pBC
);
1500 // Clear everything and start over.
1501 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1503 m_pDoc
->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1504 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1505 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", pBC
);
1507 // While column A is still empty, move column A down 2 cells. This should
1508 // move the broadcaster from A1 to A3.
1509 m_pDoc
->InsertRow(0, 0, 0, 0, 0, 2);
1510 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1511 broadcasterShifted(*m_pDoc
, ScAddress(0,0,0), ScAddress(0,2,0)));
1513 // Move it back while column A is still empty.
1514 m_pDoc
->DeleteRow(0, 0, 0, 0, 0, 2);
1515 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1516 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(0,0,0)));
1518 // Clear everything again
1519 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1521 // B1:B3 depends on A1:A3
1522 m_pDoc
->SetString(ScAddress(1,0,0), "=A1");
1523 m_pDoc
->SetString(ScAddress(1,1,0), "=A2");
1524 m_pDoc
->SetString(ScAddress(1,2,0), "=A3");
1525 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1526 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 0));
1527 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1528 checkRelativeRefToken(*m_pDoc
, ScAddress(1,1,0), -1, 0));
1529 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B3 failed.",
1530 checkRelativeRefToken(*m_pDoc
, ScAddress(1,2,0), -1, 0));
1531 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1532 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A2.", m_pDoc
->GetBroadcaster(ScAddress(0,1,0)));
1533 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A3.", m_pDoc
->GetBroadcaster(ScAddress(0,2,0)));
1535 // Insert Rows at row 2, down 5 rows.
1536 m_pDoc
->InsertRow(0, 0, 0, 0, 1, 5);
1537 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1538 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1539 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 0));
1541 // Broadcasters in A2 and A3 should shift down by 5 rows.
1542 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1543 broadcasterShifted(*m_pDoc
, ScAddress(0,1,0), ScAddress(0,6,0)));
1544 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1545 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(0,7,0)));
1547 // B2 and B3 should reference shifted cells.
1548 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1549 checkRelativeRefToken(*m_pDoc
, ScAddress(1,1,0), -1, 5));
1550 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1551 checkRelativeRefToken(*m_pDoc
, ScAddress(1,2,0), -1, 5));
1553 // Delete cells with broadcasters.
1554 m_pDoc
->DeleteRow(0, 0, 0, 0, 4, 6);
1555 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A7.", !m_pDoc
->GetBroadcaster(ScAddress(0,6,0)));
1556 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A8.", !m_pDoc
->GetBroadcaster(ScAddress(0,7,0)));
1558 // References in B2 and B3 should be invalid.
1559 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B2 failed.",
1560 checkDeletedRefToken(*m_pDoc
, ScAddress(1,1,0)));
1561 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B3 failed.",
1562 checkDeletedRefToken(*m_pDoc
, ScAddress(1,2,0)));
1564 // Clear everything again
1565 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1568 // Switch to R1C1 to make it easier to input relative references in multiple cells.
1569 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1571 // Have B1:B20 reference A1:A20.
1573 for (SCROW i
= 0; i
< 20; ++i
)
1575 m_pDoc
->SetValue(ScAddress(0,i
,0), val
++);
1576 m_pDoc
->SetString(ScAddress(1,i
,0), "=RC[-1]");
1580 // Ensure that the formula cells show correct values, and the referenced
1581 // cells have broadcasters.
1583 for (SCROW i
= 0; i
< 20; ++i
, ++val
)
1585 CPPUNIT_ASSERT_EQUAL(val
, m_pDoc
->GetValue(ScAddress(1,i
,0)));
1586 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,i
,0));
1587 CPPUNIT_ASSERT_MESSAGE("Broadcast should exist here.", pBC
);
1590 // Delete formula cells in B2:B19.
1591 clearRange(m_pDoc
, ScRange(1,1,0,1,18,0));
1592 // Ensure that A2:A19 no longer have broadcasters, but A1 and A20 still do.
1593 CPPUNIT_ASSERT_MESSAGE("A1 should still have broadcaster.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1594 CPPUNIT_ASSERT_MESSAGE("A20 should still have broadcaster.", m_pDoc
->GetBroadcaster(ScAddress(0,19,0)));
1595 for (SCROW i
= 1; i
<= 18; ++i
)
1597 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,i
,0));
1598 CPPUNIT_ASSERT_MESSAGE("Broadcaster should have been deleted.", !pBC
);
1601 // Clear everything again
1602 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1604 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0);
1605 m_pDoc
->SetString(ScAddress(1,0,0), "=A1");
1606 m_pDoc
->SetString(ScAddress(2,0,0), "=B1");
1607 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(0,0,0));
1608 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(1,0,0));
1609 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(2,0,0));
1611 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1612 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1613 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,0,0));
1614 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1616 // Change the value of A1 and make sure everyone follows suit.
1617 m_pDoc
->SetValue(ScAddress(0,0,0), 3.5);
1618 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(0,0,0));
1619 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(1,0,0));
1620 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(2,0,0));
1622 // Insert a column at column B.
1623 m_pDoc
->InsertCol(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0));
1624 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1625 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1626 pBC
= m_pDoc
->GetBroadcaster(ScAddress(2,0,0));
1627 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1629 // Change the value of A1 again.
1630 m_pDoc
->SetValue(ScAddress(0,0,0), 5.5);
1631 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(0,0,0));
1632 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(2,0,0));
1633 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(3,0,0));
1635 m_pDoc
->DeleteTab(0);
1638 CPPUNIT_TEST_FIXTURE(Test
, testFuncParam
)
1641 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
1642 m_pDoc
->InsertTab (0, "foo"));
1644 // First, the normal case, with no missing parameters.
1645 m_pDoc
->SetString(0, 0, 0, "=AVERAGE(1;2;3)");
1646 m_pDoc
->CalcFormulaTree(false, false);
1647 double val
= m_pDoc
->GetValue(0, 0, 0);
1648 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 2.0, val
);
1650 // Now function with missing parameters. Missing values should be treated
1652 m_pDoc
->SetString(0, 0, 0, "=AVERAGE(1;;;)");
1653 m_pDoc
->CalcFormulaTree(false, false);
1654 val
= m_pDoc
->GetValue(0, 0, 0);
1655 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 0.25, val
);
1657 // Conversion of string to numeric argument.
1658 m_pDoc
->SetString(0, 0, 0, "=\"\"+3"); // empty string
1659 m_pDoc
->SetString(0, 1, 0, "=\" \"+3"); // only blank
1660 m_pDoc
->SetString(0, 2, 0, "=\" 4 \"+3"); // number in blanks
1661 m_pDoc
->SetString(0, 3, 0, "=\" x \"+3"); // non-numeric
1662 m_pDoc
->SetString(0, 4, 0, "=\"4.4\"+3"); // locale dependent
1665 ScCalcConfig aConfig
;
1667 // With "Convert also locale dependent" and "Empty string as zero"=True option.
1668 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::LOCALE
;
1669 aConfig
.mbEmptyStringAsZero
= true;
1670 m_pDoc
->SetCalcConfig(aConfig
);
1672 val
= m_pDoc
->GetValue(0, 0, 0);
1673 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1674 val
= m_pDoc
->GetValue(0, 1, 0);
1675 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1676 val
= m_pDoc
->GetValue(0, 2, 0);
1677 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1678 aVal
= m_pDoc
->GetString( 0, 3, 0);
1679 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1680 val
= m_pDoc
->GetValue(0, 4, 0);
1681 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.4, val
);
1683 // With "Convert also locale dependent" and "Empty string as zero"=False option.
1684 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::LOCALE
;
1685 aConfig
.mbEmptyStringAsZero
= false;
1686 m_pDoc
->SetCalcConfig(aConfig
);
1688 aVal
= m_pDoc
->GetString( 0, 0, 0);
1689 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1690 aVal
= m_pDoc
->GetString( 0, 1, 0);
1691 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1692 val
= m_pDoc
->GetValue(0, 2, 0);
1693 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1694 aVal
= m_pDoc
->GetString( 0, 3, 0);
1695 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1696 val
= m_pDoc
->GetValue(0, 4, 0);
1697 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.4, val
);
1699 // With "Convert only unambiguous" and "Empty string as zero"=True option.
1700 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
1701 aConfig
.mbEmptyStringAsZero
= true;
1702 m_pDoc
->SetCalcConfig(aConfig
);
1704 val
= m_pDoc
->GetValue(0, 0, 0);
1705 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1706 val
= m_pDoc
->GetValue(0, 1, 0);
1707 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1708 val
= m_pDoc
->GetValue(0, 2, 0);
1709 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1710 aVal
= m_pDoc
->GetString( 0, 3, 0);
1711 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1712 aVal
= m_pDoc
->GetString( 0, 4, 0);
1713 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1715 // With "Convert only unambiguous" and "Empty string as zero"=False option.
1716 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
1717 aConfig
.mbEmptyStringAsZero
= false;
1718 m_pDoc
->SetCalcConfig(aConfig
);
1720 aVal
= m_pDoc
->GetString( 0, 0, 0);
1721 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1722 aVal
= m_pDoc
->GetString( 0, 1, 0);
1723 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1724 m_pDoc
->GetValue(0, 2, 0);
1725 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1726 aVal
= m_pDoc
->GetString( 0, 3, 0);
1727 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1728 aVal
= m_pDoc
->GetString( 0, 4, 0);
1729 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1731 // With "Treat as zero" ("Empty string as zero" is ignored).
1732 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::ZERO
;
1733 aConfig
.mbEmptyStringAsZero
= true;
1734 m_pDoc
->SetCalcConfig(aConfig
);
1736 val
= m_pDoc
->GetValue(0, 0, 0);
1737 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1738 val
= m_pDoc
->GetValue(0, 1, 0);
1739 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1740 val
= m_pDoc
->GetValue(0, 2, 0);
1741 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1742 val
= m_pDoc
->GetValue(0, 3, 0);
1743 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1744 val
= m_pDoc
->GetValue(0, 4, 0);
1745 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1747 // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
1748 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::ILLEGAL
;
1749 aConfig
.mbEmptyStringAsZero
= false;
1750 m_pDoc
->SetCalcConfig(aConfig
);
1752 aVal
= m_pDoc
->GetString( 0, 0, 0);
1753 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1754 aVal
= m_pDoc
->GetString( 0, 1, 0);
1755 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1756 aVal
= m_pDoc
->GetString( 0, 2, 0);
1757 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1758 aVal
= m_pDoc
->GetString( 0, 3, 0);
1759 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1760 aVal
= m_pDoc
->GetString( 0, 4, 0);
1761 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1763 m_pDoc
->DeleteTab(0);
1766 CPPUNIT_TEST_FIXTURE(Test
, testNamedRange
)
1768 static const RangeNameDef aNames
[] = {
1769 { "Divisor", "$Sheet1.$A$1:$A$1048576", 1 },
1770 { "MyRange1", "$Sheet1.$A$1:$A$100", 2 },
1771 { "MyRange2", "$Sheet1.$B$1:$B$100", 3 },
1772 { "MyRange3", "$Sheet1.$C$1:$C$100", 4 }
1775 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, "Sheet1"));
1777 m_pDoc
->SetValue (0, 0, 0, 101);
1779 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
1780 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), aNames
, aNames
+ SAL_N_ELEMENTS(aNames
));
1781 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess
);
1782 m_pDoc
->SetRangeName(std::move(pNames
));
1784 ScRangeName
* pNewRanges
= m_pDoc
->GetRangeName();
1785 CPPUNIT_ASSERT(pNewRanges
);
1787 // Make sure the index lookup does the right thing.
1788 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
)
1790 const ScRangeData
* p
= pNewRanges
->findByIndex(aNames
[i
].mnIndex
);
1791 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed.", p
);
1792 OUString aName
= p
->GetName();
1793 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved.", aName
.equalsAscii(aNames
[i
].mpName
));
1796 // Test usage in formula expression.
1797 m_pDoc
->SetString (1, 0, 0, "=A1/Divisor");
1800 double result
= m_pDoc
->GetValue (1, 0, 0);
1801 ASSERT_DOUBLES_EQUAL_MESSAGE ("calculation failed", 1.0, result
);
1803 // Test copy-ability of range names.
1804 std::unique_ptr
<ScRangeName
> pCopiedRanges(new ScRangeName(*pNewRanges
));
1805 m_pDoc
->SetRangeName(std::move(pCopiedRanges
));
1806 // Make sure the index lookup still works.
1807 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
)
1809 const ScRangeData
* p
= m_pDoc
->GetRangeName()->findByIndex(aNames
[i
].mnIndex
);
1810 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed with the copied instance.", p
);
1811 OUString aName
= p
->GetName();
1812 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved with the copied instance.", aName
.equalsAscii(aNames
[i
].mpName
));
1815 // Test using another-sheet-local name, scope Sheet1.
1816 ScRangeData
* pLocal1
= new ScRangeData( *m_pDoc
, "local1", ScAddress(0,0,0));
1817 ScRangeData
* pLocal2
= new ScRangeData( *m_pDoc
, "local2", "$Sheet1.$A$1");
1818 ScRangeData
* pLocal3
= new ScRangeData( *m_pDoc
, "local3", "Sheet1.$A$1");
1819 ScRangeData
* pLocal4
= new ScRangeData( *m_pDoc
, "local4", "$A$1"); // implicit relative sheet reference
1820 std::unique_ptr
<ScRangeName
> pLocalRangeName1(new ScRangeName
);
1821 pLocalRangeName1
->insert(pLocal1
);
1822 pLocalRangeName1
->insert(pLocal2
);
1823 pLocalRangeName1
->insert(pLocal3
);
1824 pLocalRangeName1
->insert(pLocal4
);
1825 m_pDoc
->SetRangeName(0, std::move(pLocalRangeName1
));
1827 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (1, "Sheet2"));
1829 // Use other-sheet-local name of Sheet1 on Sheet2.
1830 ScAddress
aPos(1,0,1);
1831 OUString
aFormula("=Sheet1.local1+Sheet1.local2+Sheet1.local3+Sheet1.local4");
1832 m_pDoc
->SetString(aPos
, aFormula
);
1833 OUString aString
= m_pDoc
->GetFormula(1,0,1);
1834 CPPUNIT_ASSERT_EQUAL_MESSAGE("formula string should be equal", aFormula
, aString
);
1835 double fValue
= m_pDoc
->GetValue(aPos
);
1836 ASSERT_DOUBLES_EQUAL_MESSAGE("value should be 4 times Sheet1.A1", 404.0, fValue
);
1838 m_pDoc
->DeleteTab(1);
1839 m_pDoc
->SetRangeName(0,nullptr); // Delete the names.
1840 m_pDoc
->SetRangeName(nullptr); // Delete the names.
1841 m_pDoc
->DeleteTab(0);
1844 CPPUNIT_TEST_FIXTURE(Test
, testInsertNameList
)
1846 m_pDoc
->InsertTab(0, "Test");
1848 static const RangeNameDef aNames
[] = {
1849 { "MyRange1", "$Test.$A$1:$A$100", 1 },
1850 { "MyRange2", "$Test.$B$1:$B$100", 2 },
1851 { "MyRange3", "$Test.$C$1:$C$100", 3 }
1854 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
1855 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), aNames
, aNames
+ SAL_N_ELEMENTS(aNames
));
1856 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess
);
1857 m_pDoc
->SetRangeName(std::move(pNames
));
1859 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
1860 ScAddress
aPos(1,1,0);
1861 rDocFunc
.InsertNameList(aPos
, true);
1863 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
, aPos
.IncRow())
1865 OUString aName
= m_pDoc
->GetString(aPos
);
1866 CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(aNames
[i
].mpName
), aName
);
1867 ScAddress aExprPos
= aPos
;
1869 OUString aExpr
= m_pDoc
->GetString(aExprPos
);
1870 OUString aExpected
= "=" + OUString::createFromAscii(aNames
[i
].mpExpr
);
1871 CPPUNIT_ASSERT_EQUAL(aExpected
, aExpr
);
1874 m_pDoc
->DeleteTab(0);
1877 CPPUNIT_TEST_FIXTURE(Test
, testCSV
)
1879 const int English
= 0, European
= 1;
1881 const char *pStr
; int eSep
; bool bResult
; double nValue
;
1883 { "foo", English
, false, 0.0 },
1884 { "1.0", English
, true, 1.0 },
1885 { "1,0", English
, false, 0.0 },
1886 { "1.0", European
, false, 0.0 },
1887 { "1.000", European
, true, 1000.0 },
1888 { "1,000", European
, true, 1.0 },
1889 { "1.000", English
, true, 1.0 },
1890 { "1,000", English
, true, 1000.0 },
1891 { " 1.0", English
, true, 1.0 },
1892 { " 1.0 ", English
, true, 1.0 },
1893 { "1.0 ", European
, false, 0.0 },
1894 { "1.000", European
, true, 1000.0 },
1895 { "1137.999", English
, true, 1137.999 },
1896 { "1.000.00", European
, false, 0.0 },
1897 { "+,123", English
, false, 0.0 },
1898 { "-,123", English
, false, 0.0 }
1900 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aTests
); i
++) {
1901 OUString
aStr(aTests
[i
].pStr
, strlen (aTests
[i
].pStr
), RTL_TEXTENCODING_UTF8
);
1902 double nValue
= 0.0;
1903 bool bResult
= ScStringUtil::parseSimpleNumber
1904 (aStr
, aTests
[i
].eSep
== English
? '.' : ',',
1905 aTests
[i
].eSep
== English
? ',' : '.',
1908 CPPUNIT_ASSERT_EQUAL_MESSAGE ("CSV numeric detection failure", aTests
[i
].bResult
, bResult
);
1909 CPPUNIT_ASSERT_EQUAL_MESSAGE ("CSV numeric value failure", aTests
[i
].nValue
, nValue
);
1913 template<typename Evaluator
>
1914 static void checkMatrixElements(const ScMatrix
& rMat
)
1917 rMat
.GetDimensions(nC
, nR
);
1919 for (SCSIZE i
= 0; i
< nC
; ++i
)
1921 for (SCSIZE j
= 0; j
< nR
; ++j
)
1923 aEval(i
, j
, rMat
.Get(i
, j
));
1930 struct AllZeroMatrix
1932 void operator() (SCSIZE
/*nCol*/, SCSIZE
/*nRow*/, const ScMatrixValue
& rVal
) const
1934 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of numeric type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
1935 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be zero", 0.0, rVal
.fVal
);
1939 struct PartiallyFilledZeroMatrix
1941 void operator() (SCSIZE nCol
, SCSIZE nRow
, const ScMatrixValue
& rVal
) const
1943 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of numeric type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
1944 if (1 <= nCol
&& nCol
<= 2 && 2 <= nRow
&& nRow
<= 8)
1946 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be 3.0", 3.0, rVal
.fVal
);
1950 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be zero", 0.0, rVal
.fVal
);
1955 struct AllEmptyMatrix
1957 void operator() (SCSIZE
/*nCol*/, SCSIZE
/*nRow*/, const ScMatrixValue
& rVal
) const
1959 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty type", int(ScMatValType::Empty
), static_cast<int>(rVal
.nType
));
1960 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
1964 struct PartiallyFilledEmptyMatrix
1966 void operator() (SCSIZE nCol
, SCSIZE nRow
, const ScMatrixValue
& rVal
) const
1968 if (nCol
== 1 && nRow
== 1)
1970 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of boolean type", int(ScMatValType::Boolean
), static_cast<int>(rVal
.nType
));
1971 ASSERT_DOUBLES_EQUAL_MESSAGE("element value is not what is expected", 1.0, rVal
.fVal
);
1973 else if (nCol
== 4 && nRow
== 5)
1975 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of value type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
1976 ASSERT_DOUBLES_EQUAL_MESSAGE("element value is not what is expected", -12.5, rVal
.fVal
);
1978 else if (nCol
== 8 && nRow
== 2)
1980 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of value type", int(ScMatValType::String
), static_cast<int>(rVal
.nType
));
1981 CPPUNIT_ASSERT_EQUAL_MESSAGE("element value is not what is expected", OUString("Test"), rVal
.aStr
.getString());
1983 else if (nCol
== 8 && nRow
== 11)
1985 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty path type", int(ScMatValType::EmptyPath
), static_cast<int>(rVal
.nType
));
1986 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
1990 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty type", int(ScMatValType::Empty
), static_cast<int>(rVal
.nType
));
1991 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
1998 CPPUNIT_TEST_FIXTURE(Test
, testMatrix
)
2000 svl::SharedStringPool
& rPool
= m_pDoc
->GetSharedStringPool();
2001 ScMatrixRef pMat
, pMat2
;
2003 // First, test the zero matrix type.
2004 pMat
= new ScMatrix(0, 0, 0.0);
2006 pMat
->GetDimensions(nC
, nR
);
2007 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix is not empty", SCSIZE(0), nC
);
2008 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix is not empty", SCSIZE(0), nR
);
2009 pMat
->Resize(4, 10, 0.0);
2010 pMat
->GetDimensions(nC
, nR
);
2011 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(4), nC
);
2012 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(10), nR
);
2013 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
2015 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
2018 // Resizing into a larger matrix should fill the void space with zeros.
2019 checkMatrixElements
<AllZeroMatrix
>(*pMat
);
2021 pMat
->FillDouble(3.0, 1, 2, 2, 8);
2022 checkMatrixElements
<PartiallyFilledZeroMatrix
>(*pMat
);
2023 CPPUNIT_ASSERT_MESSAGE("matrix is expected to be numeric", pMat
->IsNumeric());
2024 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
2026 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
2028 pMat
->FillDouble(5.0, 0, 0, nC
-1, nR
-1);
2029 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
2031 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
2034 // Test the AND and OR evaluations.
2035 pMat
= new ScMatrix(2, 2, 0.0);
2037 // Only some of the elements are non-zero.
2038 pMat
->PutBoolean(true, 0, 0);
2039 pMat
->PutDouble(1.0, 1, 1);
2040 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat
->Or());
2041 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", !pMat
->And());
2043 // All of the elements are non-zero.
2044 pMat
->PutBoolean(true, 0, 1);
2045 pMat
->PutDouble(2.3, 1, 0);
2046 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat
->Or());
2047 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", pMat
->And());
2049 // Now test the empty matrix type.
2050 pMat
= new ScMatrix(10, 20);
2051 pMat
->GetDimensions(nC
, nR
);
2052 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(10), nC
);
2053 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(20), nR
);
2054 checkMatrixElements
<AllEmptyMatrix
>(*pMat
);
2056 pMat
->PutBoolean(true, 1, 1);
2057 pMat
->PutDouble(-12.5, 4, 5);
2058 pMat
->PutString(rPool
.intern("Test"), 8, 2);
2059 pMat
->PutEmptyPath(8, 11);
2060 checkMatrixElements
<PartiallyFilledEmptyMatrix
>(*pMat
);
2063 pMat
= new ScMatrix(0, 0);
2064 pMat
->Resize(2, 2, 1.5);
2065 pMat
->PutEmpty(1, 1);
2067 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(0, 0));
2068 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(0, 1));
2069 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(1, 0));
2070 CPPUNIT_ASSERT_MESSAGE("PutEmpty() call failed.", pMat
->IsEmpty(1, 1));
2072 // Max and min values.
2073 pMat
= new ScMatrix(2, 2, 0.0);
2074 pMat
->PutDouble(-10, 0, 0);
2075 pMat
->PutDouble(-12, 0, 1);
2076 pMat
->PutDouble(-8, 1, 0);
2077 pMat
->PutDouble(-25, 1, 1);
2078 CPPUNIT_ASSERT_EQUAL(-25.0, pMat
->GetMinValue(false));
2079 CPPUNIT_ASSERT_EQUAL(-8.0, pMat
->GetMaxValue(false));
2080 pMat
->PutString(rPool
.intern("Test"), 0, 0);
2081 CPPUNIT_ASSERT_EQUAL(0.0, pMat
->GetMaxValue(true)); // text as zero.
2082 CPPUNIT_ASSERT_EQUAL(-8.0, pMat
->GetMaxValue(false)); // ignore text.
2083 pMat
->PutBoolean(true, 0, 0);
2084 CPPUNIT_ASSERT_EQUAL(1.0, pMat
->GetMaxValue(false));
2085 pMat
= new ScMatrix(2, 2, 10.0);
2086 pMat
->PutBoolean(false, 0, 0);
2087 pMat
->PutDouble(12.5, 1, 1);
2088 CPPUNIT_ASSERT_EQUAL(0.0, pMat
->GetMinValue(false));
2089 CPPUNIT_ASSERT_EQUAL(12.5, pMat
->GetMaxValue(false));
2091 // Convert matrix into a linear double array. String elements become NaN
2092 // and empty elements become 0.
2093 pMat
= new ScMatrix(3, 3);
2094 pMat
->PutDouble(2.5, 0, 0);
2095 pMat
->PutDouble(1.2, 0, 1);
2096 pMat
->PutString(rPool
.intern("A"), 1, 1);
2097 pMat
->PutDouble(2.3, 2, 1);
2098 pMat
->PutDouble(-20, 2, 2);
2100 static const double fNaN
= std::numeric_limits
<double>::quiet_NaN();
2102 std::vector
<double> aDoubles
;
2103 pMat
->GetDoubleArray(aDoubles
);
2106 const double pChecks
[] = { 2.5, 1.2, 0, 0, fNaN
, 0, 0, 2.3, -20 };
2107 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks
), aDoubles
.size());
2108 for (size_t i
= 0, n
= aDoubles
.size(); i
< n
; ++i
)
2110 if (std::isnan(pChecks
[i
]))
2111 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", std::isnan(aDoubles
[i
]));
2113 CPPUNIT_ASSERT_EQUAL(pChecks
[i
], aDoubles
[i
]);
2117 pMat2
= new ScMatrix(3, 3, 10.0);
2118 pMat2
->PutString(rPool
.intern("B"), 1, 0);
2119 pMat2
->MergeDoubleArrayMultiply(aDoubles
);
2122 const double pChecks
[] = { 25, 12, 0, fNaN
, fNaN
, 0, 0, 23, -200 };
2123 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks
), aDoubles
.size());
2124 for (size_t i
= 0, n
= aDoubles
.size(); i
< n
; ++i
)
2126 if (std::isnan(pChecks
[i
]))
2127 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", std::isnan(aDoubles
[i
]));
2129 CPPUNIT_ASSERT_EQUAL(pChecks
[i
], aDoubles
[i
]);
2134 CPPUNIT_TEST_FIXTURE(Test
, testMatrixComparisonWithErrors
)
2136 m_pDoc
->InsertTab(0, "foo");
2138 // Insert the source values in A1:A2.
2139 m_pDoc
->SetString(0, 0, 0, "=1/0");
2140 m_pDoc
->SetValue( 0, 1, 0, 1.0);
2142 // Create a matrix formula in B3:B4 referencing A1:A2 and doing a greater
2143 // than comparison on it's values. Error value must be propagated.
2144 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2145 aMark
.SelectOneTable(0);
2146 m_pDoc
->InsertMatrixFormula(1, 2, 1, 3, aMark
, "=A1:A2>0");
2148 CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc
->GetString(0,0,0));
2149 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue( 0,1,0));
2150 CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc
->GetString(1,2,0));
2151 CPPUNIT_ASSERT_EQUAL(OUString("TRUE"), m_pDoc
->GetString(1,3,0));
2153 m_pDoc
->DeleteTab(0);
2156 CPPUNIT_TEST_FIXTURE(Test
, testMatrixConditionalBooleanResult
)
2158 m_pDoc
->InsertTab(0, "foo");
2160 // Create matrix formulas in A1:B1,A2:B2,A3:B3,A4:B4 producing mixed
2161 // boolean and numeric results in an unformatted area.
2162 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2163 aMark
.SelectOneTable(0);
2164 m_pDoc
->InsertMatrixFormula( 0,0, 1,0, aMark
, "=IF({1;0};TRUE();42)"); // {TRUE,42}
2165 m_pDoc
->InsertMatrixFormula( 0,1, 1,1, aMark
, "=IF({0;1};TRUE();42)"); // {42,1} aim for {42,TRUE}
2166 m_pDoc
->InsertMatrixFormula( 0,2, 1,2, aMark
, "=IF({1;0};42;FALSE())"); // {42,0} aim for {42,FALSE}
2167 m_pDoc
->InsertMatrixFormula( 0,3, 1,3, aMark
, "=IF({0;1};42;FALSE())"); // {FALSE,42}
2169 CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc
->GetString(0,0,0));
2170 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(1,0,0));
2171 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(0,1,0));
2172 //CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc->GetString(1,1,0)); // not yet
2173 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(0,2,0));
2174 //CPPUNIT_ASSERT_EQUAL( OUString("FALSE"), m_pDoc->GetString(1,2,0)); // not yet
2175 CPPUNIT_ASSERT_EQUAL( OUString("FALSE"), m_pDoc
->GetString(0,3,0));
2176 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(1,3,0));
2178 m_pDoc
->DeleteTab(0);
2181 CPPUNIT_TEST_FIXTURE(Test
, testEnterMixedMatrix
)
2183 m_pDoc
->InsertTab(0, "foo");
2185 // Insert the source values in A1:B2.
2186 m_pDoc
->SetString(0, 0, 0, "A");
2187 m_pDoc
->SetString(1, 0, 0, "B");
2189 m_pDoc
->SetValue(0, 1, 0, val
);
2191 m_pDoc
->SetValue(1, 1, 0, val
);
2193 // Create a matrix range in A4:B5 referencing A1:B2.
2194 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2195 aMark
.SelectOneTable(0);
2196 m_pDoc
->InsertMatrixFormula(0, 3, 1, 4, aMark
, "=A1:B2");
2198 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,0,0), m_pDoc
->GetString(0,3,0));
2199 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(1,0,0), m_pDoc
->GetString(1,3,0));
2200 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetValue(0,1,0), m_pDoc
->GetValue(0,4,0));
2201 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetValue(1,1,0), m_pDoc
->GetValue(1,4,0));
2203 m_pDoc
->DeleteTab(0);
2206 CPPUNIT_TEST_FIXTURE(Test
, testMatrixEditable
)
2208 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2210 m_pDoc
->InsertTab(0, "Test");
2213 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
2214 m_pDoc
->SetValue(ScAddress(1,0,0), 2.0);
2216 // A2 is a normal formula.
2217 m_pDoc
->SetString(ScAddress(0,1,0), "=5");
2219 // A3:A4 is a matrix.
2220 ScRange
aMatRange(0,2,0,0,3,0);
2221 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2222 aMark
.SetMarkArea(aMatRange
);
2223 m_pDoc
->InsertMatrixFormula(0, 2, 0, 3, aMark
, "=TRANSPOSE(A1:B1)");
2225 // Check their values.
2226 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
2227 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
2228 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
2230 // Make sure A3:A4 is a matrix.
2231 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,2,0));
2232 CPPUNIT_ASSERT(pFC
);
2233 CPPUNIT_ASSERT_EQUAL_MESSAGE("A3 should be matrix origin.",
2234 ScMatrixMode::Formula
, pFC
->GetMatrixFlag());
2236 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,3,0));
2237 CPPUNIT_ASSERT(pFC
);
2238 CPPUNIT_ASSERT_EQUAL_MESSAGE("A4 should be matrix reference.",
2239 ScMatrixMode::Reference
, pFC
->GetMatrixFlag());
2241 // Check to make sure A3:A4 combined is editable.
2242 ScEditableTester aTester
;
2243 aTester
.TestSelection(*m_pDoc
, aMark
);
2244 CPPUNIT_ASSERT(aTester
.IsEditable());
2246 m_pDoc
->DeleteTab(0);
2249 CPPUNIT_TEST_FIXTURE(Test
, testCellCopy
)
2251 m_pDoc
->InsertTab(0, "TestTab");
2252 ScAddress
aSrc(0,0,0);
2253 ScAddress
aDest(0,1,0);
2254 OUString
aStr("please copy me");
2255 m_pDoc
->SetString(aSrc
, "please copy me");
2256 CPPUNIT_ASSERT_EQUAL(aStr
, m_pDoc
->GetString(aSrc
));
2257 // copy to self - why not ?
2258 m_pDoc
->CopyCellToDocument(aSrc
,aDest
,*m_pDoc
);
2259 CPPUNIT_ASSERT_EQUAL(aStr
, m_pDoc
->GetString(aDest
));
2262 CPPUNIT_TEST_FIXTURE(Test
, testSheetCopy
)
2264 m_pDoc
->InsertTab(0, "TestTab");
2265 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
2266 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
2268 // We need a drawing layer in order to create caption objects.
2269 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
2271 // Insert text in A1.
2272 m_pDoc
->SetString(ScAddress(0,0,0), "copy me");
2274 // Insert edit cells in B1:B3.
2275 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
2276 rEE
.SetTextCurrentDefaults("Edit 1");
2277 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject());
2278 rEE
.SetTextCurrentDefaults("Edit 2");
2279 m_pDoc
->SetEditText(ScAddress(1,1,0), rEE
.CreateTextObject());
2280 rEE
.SetTextCurrentDefaults("Edit 3");
2281 m_pDoc
->SetEditText(ScAddress(1,2,0), rEE
.CreateTextObject());
2284 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2285 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2286 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2287 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2290 ScAddress
aAdrA1 (0,2,0); // empty cell content.
2291 ScPostIt
*pNoteA1
= m_pDoc
->GetOrCreateNote(aAdrA1
);
2292 pNoteA1
->SetText(aAdrA1
, "Hello world in A3");
2294 // Copy and test the result.
2295 m_pDoc
->CopyTab(0, 1);
2296 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.",
2297 static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2299 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2300 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden
);
2301 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", SCROW(0), nRow1
);
2302 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", m_pDoc
->MaxRow(), nRow2
);
2303 CPPUNIT_ASSERT_MESSAGE("There should be note on A3 in new sheet", m_pDoc
->HasNote(ScAddress(0,2,1)));
2304 CPPUNIT_ASSERT_EQUAL(OUString("copy me"), m_pDoc
->GetString(ScAddress(0,0,1)));
2306 // Check the copied edit cells.
2307 const EditTextObject
* pEditObj
= m_pDoc
->GetEditText(ScAddress(1,0,1));
2308 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B1.", pEditObj
);
2309 CPPUNIT_ASSERT_EQUAL(OUString("Edit 1"), pEditObj
->GetText(0));
2310 pEditObj
= m_pDoc
->GetEditText(ScAddress(1,1,1));
2311 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B2.", pEditObj
);
2312 CPPUNIT_ASSERT_EQUAL(OUString("Edit 2"), pEditObj
->GetText(0));
2313 pEditObj
= m_pDoc
->GetEditText(ScAddress(1,2,1));
2314 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B3.", pEditObj
);
2315 CPPUNIT_ASSERT_EQUAL(OUString("Edit 3"), pEditObj
->GetText(0));
2317 m_pDoc
->DeleteTab(1);
2319 m_pDoc
->SetRowHidden(5, 10, 0, true);
2320 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2321 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2322 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2323 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2324 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
2325 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2326 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2327 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2328 bHidden
= m_pDoc
->RowHidden(11, 0, &nRow1
, &nRow2
);
2329 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2330 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2331 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2333 // Copy the sheet once again.
2334 m_pDoc
->CopyTab(0, 1);
2335 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.",
2336 static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2337 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2338 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2339 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2340 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2341 bHidden
= m_pDoc
->RowHidden(5, 1, &nRow1
, &nRow2
);
2342 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2343 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2344 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2345 bHidden
= m_pDoc
->RowHidden(11, 1, &nRow1
, &nRow2
);
2346 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2347 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2348 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2349 m_pDoc
->DeleteTab(1);
2350 m_pDoc
->DeleteTab(0);
2353 CPPUNIT_TEST_FIXTURE(Test
, testSheetMove
)
2355 m_pDoc
->InsertTab(0, "TestTab1");
2356 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.", static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
2358 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2359 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2360 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2361 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2363 //test if inserting before another sheet works
2364 m_pDoc
->InsertTab(0, "TestTab2");
2365 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have two sheets", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2366 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2367 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2368 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2369 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2371 // Move and test the result.
2372 m_pDoc
->MoveTab(0, 1);
2373 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2374 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2375 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden
);
2376 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", SCROW(0), nRow1
);
2377 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", m_pDoc
->MaxRow(), nRow2
);
2379 m_pDoc
->GetName(0, aName
);
2380 CPPUNIT_ASSERT_EQUAL_MESSAGE( "sheets should have changed places", OUString("TestTab1"), aName
);
2382 m_pDoc
->SetRowHidden(5, 10, 0, true);
2383 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2384 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2385 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2386 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2387 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
2388 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2389 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2390 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2391 bHidden
= m_pDoc
->RowHidden(11, 0, &nRow1
, &nRow2
);
2392 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2393 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2394 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2396 // Move the sheet once again.
2397 m_pDoc
->MoveTab(1, 0);
2398 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2399 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2400 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2401 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2402 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2403 bHidden
= m_pDoc
->RowHidden(5, 1, &nRow1
, &nRow2
);
2404 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2405 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2406 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2407 bHidden
= m_pDoc
->RowHidden(11, 1, &nRow1
, &nRow2
);
2408 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2409 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2410 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2411 m_pDoc
->GetName(0, aName
);
2412 CPPUNIT_ASSERT_EQUAL_MESSAGE( "sheets should have changed places", OUString("TestTab2"), aName
);
2413 m_pDoc
->DeleteTab(1);
2414 m_pDoc
->DeleteTab(0);
2417 CPPUNIT_TEST_FIXTURE(Test
, testDataArea
)
2419 m_pDoc
->InsertTab(0, "Data");
2421 // Totally empty sheet should be rightfully considered empty in all accounts.
2422 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc
->IsPrintEmpty(0, 0, 100, 100, 0));
2423 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2425 // Now, set borders in some cells...
2426 ::editeng::SvxBorderLine
aLine(nullptr, 50, SvxBorderLineStyle::SOLID
);
2427 SvxBoxItem
aBorderItem(ATTR_BORDER
);
2428 aBorderItem
.SetLine(&aLine
, SvxBoxItemLine::LEFT
);
2429 aBorderItem
.SetLine(&aLine
, SvxBoxItemLine::RIGHT
);
2430 for (SCROW i
= 0; i
< 100; ++i
)
2431 // Set borders from row 1 to 100.
2432 m_pDoc
->ApplyAttr(0, i
, 0, aBorderItem
);
2434 // Now the sheet is considered non-empty for printing purposes, but still
2435 // be empty in all the other cases.
2436 CPPUNIT_ASSERT_MESSAGE("Empty sheet with borders should be printable.",
2437 !m_pDoc
->IsPrintEmpty(0, 0, 0, 100, 100));
2438 CPPUNIT_ASSERT_MESSAGE("But it should still be considered empty in all the other cases.",
2439 m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2441 // Adding a real cell content should turn the block non-empty.
2442 m_pDoc
->SetString(0, 0, 0, "Some text");
2443 CPPUNIT_ASSERT_MESSAGE("Now the block should not be empty with a real cell content.",
2444 !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2446 // TODO: Add more tests for normal data area calculation.
2448 m_pDoc
->DeleteTab(0);
2451 CPPUNIT_TEST_FIXTURE(Test
, testStreamValid
)
2454 * Make sure the sheet streams are invalidated properly.
2456 m_pDoc
->InsertTab(0, "Sheet1");
2457 m_pDoc
->InsertTab(1, "Sheet2");
2458 m_pDoc
->InsertTab(2, "Sheet3");
2459 m_pDoc
->InsertTab(3, "Sheet4");
2460 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", static_cast<SCTAB
>(4), m_pDoc
->GetTableCount());
2466 // Put values into Sheet1.
2467 m_pDoc
->SetString(0, 0, 0, a1
);
2468 m_pDoc
->SetString(0, 1, 0, a2
);
2469 test
= m_pDoc
->GetString(0, 0, 0);
2470 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet1.A1", test
, a1
);
2471 test
= m_pDoc
->GetString(0, 1, 0);
2472 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet1.A2", test
, a2
);
2474 // Put formulas into Sheet2 to Sheet4 to reference values from Sheet1.
2475 m_pDoc
->SetString(0, 0, 1, "=Sheet1.A1");
2476 m_pDoc
->SetString(0, 1, 1, "=Sheet1.A2");
2477 m_pDoc
->SetString(0, 0, 2, "=Sheet1.A1");
2478 m_pDoc
->SetString(0, 0, 3, "=Sheet1.A2");
2480 test
= m_pDoc
->GetString(0, 0, 1);
2481 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet2.A1", test
, a1
);
2482 test
= m_pDoc
->GetString(0, 1, 1);
2483 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet2.A2", test
, a2
);
2484 test
= m_pDoc
->GetString(0, 0, 2);
2485 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet3.A1", test
, a1
);
2486 test
= m_pDoc
->GetString(0, 0, 3);
2487 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet3.A1", test
, a2
);
2489 // Set all sheet streams valid after all the initial cell values are in
2490 // place. In reality we need to have real XML streams stored in order to
2491 // claim they are valid, but we are just testing the flag values here.
2492 m_pDoc
->SetStreamValid(0, true);
2493 m_pDoc
->SetStreamValid(1, true);
2494 m_pDoc
->SetStreamValid(2, true);
2495 m_pDoc
->SetStreamValid(3, true);
2496 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(0));
2497 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(1));
2498 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(2));
2499 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(3));
2501 // Now, insert a new row at row 2 position on Sheet1. This will move cell
2502 // A2 downward but cell A1 remains unmoved.
2503 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 2);
2504 test
= m_pDoc
->GetString(0, 0, 0);
2505 CPPUNIT_ASSERT_EQUAL_MESSAGE("Cell A1 should not have moved.", test
, a1
);
2506 test
= m_pDoc
->GetString(0, 3, 0);
2507 CPPUNIT_ASSERT_EQUAL_MESSAGE("the old cell A2 should now be at A4.", test
, a2
);
2508 ScRefCellValue aCell
;
2509 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
2510 CPPUNIT_ASSERT_MESSAGE("Cell A2 should be empty.", aCell
.isEmpty());
2511 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
2512 CPPUNIT_ASSERT_MESSAGE("Cell A3 should be empty.", aCell
.isEmpty());
2514 // After the move, Sheet1, Sheet2, and Sheet4 should have their stream
2515 // invalidated, whereas Sheet3's stream should still be valid.
2516 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(0));
2517 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(1));
2518 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(3));
2519 CPPUNIT_ASSERT_MESSAGE("Stream should still be valid.", m_pDoc
->IsStreamValid(2));
2521 m_pDoc
->DeleteTab(3);
2522 m_pDoc
->DeleteTab(2);
2523 m_pDoc
->DeleteTab(1);
2524 m_pDoc
->DeleteTab(0);
2527 CPPUNIT_TEST_FIXTURE(Test
, testFunctionLists
)
2530 * Test built-in cell functions to make sure their categories and order
2533 const char* aDataBase
[] = {
2549 const char* aDateTime
[] = {
2583 const char* aFinancial
[] = {
2613 const char* aInformation
[] = {
2636 const char* aLogical
[] = {
2651 const char* aMathematical
[] = {
2729 const char* aArray
[] = {
2748 const char* aStatistical
[] = {
2801 "FORECAST.ETS.MULT",
2802 "FORECAST.ETS.PI.ADD",
2803 "FORECAST.ETS.PI.MULT",
2804 "FORECAST.ETS.SEASONALITY",
2805 "FORECAST.ETS.STAT.ADD",
2806 "FORECAST.ETS.STAT.MULT",
2903 const char* aSpreadsheet
[] = {
2934 const char* aText
[] = {
2986 const char* Category
; const char** Functions
;
2988 { "Database", aDataBase
},
2989 { "Date&Time", aDateTime
},
2990 { "Financial", aFinancial
},
2991 { "Information", aInformation
},
2992 { "Logical", aLogical
},
2993 { "Mathematical", aMathematical
},
2994 { "Array", aArray
},
2995 { "Statistical", aStatistical
},
2996 { "Spreadsheet", aSpreadsheet
},
2998 { "Add-in", nullptr },
2999 { nullptr, nullptr }
3002 ScFunctionMgr
* pFuncMgr
= ScGlobal::GetStarCalcFunctionMgr();
3003 sal_uInt32 n
= pFuncMgr
->getCount();
3004 for (sal_uInt32 i
= 0; i
< n
; ++i
)
3006 const formula::IFunctionCategory
* pCat
= pFuncMgr
->getCategory(i
);
3007 CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat
->getName().equalsAscii(aTests
[i
].Category
));
3008 sal_uInt32 nFuncCount
= pCat
->getCount();
3009 for (sal_uInt32 j
= 0; j
< nFuncCount
; ++j
)
3011 const formula::IFunctionDescription
* pFunc
= pCat
->getFunction(j
);
3012 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests
[i
].Functions
[j
]), pFunc
->getFunctionName());
3017 CPPUNIT_TEST_FIXTURE(Test
, testGraphicsInGroup
)
3019 m_pDoc
->InsertTab(0, "TestTab");
3020 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
3021 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
3023 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3024 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
3025 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
3026 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
3028 m_pDoc
->InitDrawLayer();
3029 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
3030 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
3031 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3032 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
3036 tools::Rectangle
aOrigRect(2,2,100,100);
3037 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aOrigRect
);
3038 pPage
->InsertObject(pObj
.get());
3039 const tools::Rectangle
&rNewRect
= pObj
->GetLogicRect();
3040 CPPUNIT_ASSERT_EQUAL_MESSAGE("must have equal position and size",
3041 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3043 ScDrawLayer::SetPageAnchored(*pObj
);
3045 //Use a range of rows guaranteed to include all of the square
3046 m_pDoc
->ShowRows(0, 100, 0, false);
3047 m_pDoc
->SetDrawPageSize(0);
3048 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3049 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3050 m_pDoc
->ShowRows(0, 100, 0, true);
3051 m_pDoc
->SetDrawPageSize(0);
3052 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3053 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3055 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
3056 CPPUNIT_ASSERT_EQUAL_MESSAGE("That shouldn't change size or positioning",
3057 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3059 m_pDoc
->ShowRows(0, 100, 0, false);
3060 m_pDoc
->SetDrawPageSize(0);
3062 CPPUNIT_ASSERT_EQUAL_MESSAGE("Hiding should not change the logic rectangle",
3063 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3064 CPPUNIT_ASSERT_MESSAGE("Hiding should make invisible", !pObj
->IsVisible());
3066 m_pDoc
->ShowRows(0, 100, 0, true);
3067 m_pDoc
->SetDrawPageSize(0);
3068 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when cell anchored",
3069 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3070 CPPUNIT_ASSERT_MESSAGE("Show should make visible", pObj
->IsVisible());
3075 tools::Rectangle
aOrigRect(10,10,210,210); // 200 x 200
3076 rtl::Reference
<SdrCircObj
> pObj
= new SdrCircObj(*pDrawLayer
, SdrCircKind::Full
, aOrigRect
);
3077 pPage
->InsertObject(pObj
.get());
3078 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3079 CPPUNIT_ASSERT_EQUAL_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
3080 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3082 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3083 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell anchored. Not good.",
3084 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3086 // Insert 2 rows at the top. This should push the circle object down.
3087 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3088 m_pDoc
->SetDrawPageSize(0);
3090 // Make sure the size of the circle is still identical.
3091 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of the circle has changed, but shouldn't!",
3092 aOrigRect
.GetSize(), rNewRect
.GetSize());
3094 // Delete 2 rows at the top. This should bring the circle object to its original position.
3095 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3096 m_pDoc
->SetDrawPageSize(0);
3097 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to move back to its original position.",
3098 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3103 basegfx::B2DPolygon aTempPoly
;
3104 Point
aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
3105 tools::Rectangle
aOrigRect(10,200,110,300); // 100 x 100
3106 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
3107 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
3108 rtl::Reference
<SdrPathObj
> pObj
= new SdrPathObj(*pDrawLayer
, SdrObjKind::Line
, basegfx::B2DPolyPolygon(aTempPoly
));
3109 pObj
->NbcSetLogicRect(aOrigRect
);
3110 pPage
->InsertObject(pObj
.get());
3111 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3112 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size differ.",
3113 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3115 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3116 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell-anchored. Not good.",
3117 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3119 // Insert 2 rows at the top and delete them immediately.
3120 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3121 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3122 m_pDoc
->SetDrawPageSize(0);
3123 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of a line object changed after row insertion and removal.",
3124 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3126 sal_Int32 n
= pObj
->GetPointCount();
3127 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 2 points in a line object.", static_cast<sal_Int32
>(2), n
);
3128 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3129 aStartPos
, pObj
->GetPoint(0));
3130 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3131 aEndPos
, pObj
->GetPoint(1));
3134 m_pDoc
->DeleteTab(0);
3137 CPPUNIT_TEST_FIXTURE(Test
, testGraphicsOnSheetMove
)
3139 m_pDoc
->InsertTab(0, "Tab1");
3140 m_pDoc
->InsertTab(1, "Tab2");
3141 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 2 sheets to begin with", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
3143 m_pDoc
->InitDrawLayer();
3144 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
3145 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
3146 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3147 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
3149 // Insert an object.
3150 tools::Rectangle
aObjRect(2,2,100,100);
3151 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
3152 pPage
->InsertObject(pObj
.get());
3153 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3155 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", static_cast<size_t>(1), pPage
->GetObjCount());
3157 const ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
3158 CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData
);
3159 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3160 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3162 pPage
= pDrawLayer
->GetPage(1);
3163 CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage
);
3164 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", static_cast<size_t>(0), pPage
->GetObjCount());
3166 // Insert a new sheet at left-end, and make sure the object has moved to
3168 m_pDoc
->InsertTab(0, "NewTab");
3169 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", static_cast<SCTAB
>(3), m_pDoc
->GetTableCount());
3170 pPage
= pDrawLayer
->GetPage(0);
3171 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3172 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3173 pPage
= pDrawLayer
->GetPage(1);
3174 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3175 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3176 pPage
= pDrawLayer
->GetPage(2);
3177 CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage
);
3178 CPPUNIT_ASSERT_EQUAL_MESSAGE("3rd sheet should have no object.", size_t(0), pPage
->GetObjCount());
3180 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3181 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3183 // Now, delete the sheet that just got inserted. The object should be back
3184 // on the 1st sheet.
3185 m_pDoc
->DeleteTab(0);
3186 pPage
= pDrawLayer
->GetPage(0);
3187 CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage
);
3188 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have one object.", size_t(1), pPage
->GetObjCount());
3189 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size and position of the object shouldn't change.",
3190 aObjRect
, pObj
->GetLogicRect());
3192 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3193 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3195 // Move the 1st sheet to the last position.
3196 m_pDoc
->MoveTab(0, 1);
3197 pPage
= pDrawLayer
->GetPage(0);
3198 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3199 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3200 pPage
= pDrawLayer
->GetPage(1);
3201 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3202 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3203 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3204 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3206 // Copy the 2nd sheet, which has one drawing object to the last position.
3207 m_pDoc
->CopyTab(1, 2);
3208 pPage
= pDrawLayer
->GetPage(2);
3209 CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage
);
3210 CPPUNIT_ASSERT_EQUAL_MESSAGE("Copied sheet should have one object.", size_t(1), pPage
->GetObjCount());
3211 pObj
= pPage
->GetObj(0);
3212 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj
);
3213 pData
= ScDrawLayer::GetObjData(pObj
.get());
3214 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
3215 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maStart
.Tab());
3216 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maEnd
.Tab());
3218 m_pDoc
->DeleteTab(2);
3219 m_pDoc
->DeleteTab(1);
3220 m_pDoc
->DeleteTab(0);
3223 CPPUNIT_TEST_FIXTURE(Test
, testToggleRefFlag
)
3226 * Test toggling relative/absolute flag of cell and cell range references.
3227 * This corresponds with hitting Shift-F4 while the cursor is on a formula
3230 // In this test, there is no need to insert formula string into a cell in
3231 // the document, as ScRefFinder does not depend on the content of the
3232 // document except for the sheet names.
3234 m_pDoc
->InsertTab(0, "Test");
3237 // Calc A1: basic 2D reference
3239 OUString
aFormula("=B100");
3240 ScAddress
aPos(1, 5, 0);
3241 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3244 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3246 // column relative / row relative -> column absolute / row absolute
3247 aFinder
.ToggleRel(0, aFormula
.getLength());
3248 aFormula
= aFinder
.GetText();
3249 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=$B$100"), aFormula
);
3251 // column absolute / row absolute -> column relative / row absolute
3252 aFinder
.ToggleRel(0, aFormula
.getLength());
3253 aFormula
= aFinder
.GetText();
3254 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=B$100"), aFormula
);
3256 // column relative / row absolute -> column absolute / row relative
3257 aFinder
.ToggleRel(0, aFormula
.getLength());
3258 aFormula
= aFinder
.GetText();
3259 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=$B100"), aFormula
);
3261 // column absolute / row relative -> column relative / row relative
3262 aFinder
.ToggleRel(0, aFormula
.getLength());
3263 aFormula
= aFinder
.GetText();
3264 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=B100"), aFormula
);
3268 // Excel R1C1: basic 2D reference
3270 OUString
aFormula("=R2C1");
3271 ScAddress
aPos(3, 5, 0);
3272 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3275 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3277 // column absolute / row absolute -> column relative / row absolute
3278 aFinder
.ToggleRel(0, aFormula
.getLength());
3279 aFormula
= aFinder
.GetText();
3280 CPPUNIT_ASSERT_EQUAL(OUString("=R2C[-3]"), aFormula
);
3282 // column relative / row absolute - > column absolute / row relative
3283 aFinder
.ToggleRel(0, aFormula
.getLength());
3284 aFormula
= aFinder
.GetText();
3285 CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C1"), aFormula
);
3287 // column absolute / row relative -> column relative / row relative
3288 aFinder
.ToggleRel(0, aFormula
.getLength());
3289 aFormula
= aFinder
.GetText();
3290 CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C[-3]"), aFormula
);
3292 // column relative / row relative -> column absolute / row absolute
3293 aFinder
.ToggleRel(0, aFormula
.getLength());
3294 aFormula
= aFinder
.GetText();
3295 CPPUNIT_ASSERT_EQUAL(OUString("=R2C1"), aFormula
);
3299 // Excel R1C1: Selection at the end of the formula string and does not
3300 // overlap the formula string at all (inspired by fdo#39135).
3301 OUString
aFormula("=R1C1");
3302 ScAddress
aPos(1, 1, 0);
3303 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3306 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3308 // Make the column relative.
3309 sal_Int32 n
= aFormula
.getLength();
3310 aFinder
.ToggleRel(n
, n
);
3311 aFormula
= aFinder
.GetText();
3312 CPPUNIT_ASSERT_EQUAL(OUString("=R1C[-1]"), aFormula
);
3314 // Make the row relative.
3315 n
= aFormula
.getLength();
3316 aFinder
.ToggleRel(n
, n
);
3317 aFormula
= aFinder
.GetText();
3318 CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C1"), aFormula
);
3320 // Make both relative.
3321 n
= aFormula
.getLength();
3322 aFinder
.ToggleRel(n
, n
);
3323 aFormula
= aFinder
.GetText();
3324 CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C[-1]"), aFormula
);
3326 // Back to the original.
3327 n
= aFormula
.getLength();
3328 aFinder
.ToggleRel(n
, n
);
3329 aFormula
= aFinder
.GetText();
3330 CPPUNIT_ASSERT_EQUAL(OUString("=R1C1"), aFormula
);
3335 OUString
aFormula("=A1+4");
3336 ScAddress
aPos(1, 1, 0);
3337 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3340 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3342 // Set the cursor over the 'A1' part and toggle.
3343 aFinder
.ToggleRel(2, 2);
3344 aFormula
= aFinder
.GetText();
3345 CPPUNIT_ASSERT_EQUAL(OUString("=$A$1+4"), aFormula
);
3347 aFinder
.ToggleRel(2, 2);
3348 aFormula
= aFinder
.GetText();
3349 CPPUNIT_ASSERT_EQUAL(OUString("=A$1+4"), aFormula
);
3351 aFinder
.ToggleRel(2, 2);
3352 aFormula
= aFinder
.GetText();
3353 CPPUNIT_ASSERT_EQUAL(OUString("=$A1+4"), aFormula
);
3355 aFinder
.ToggleRel(2, 2);
3356 aFormula
= aFinder
.GetText();
3357 CPPUNIT_ASSERT_EQUAL(OUString("=A1+4"), aFormula
);
3360 // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
3361 // partial selection within formula string.
3363 m_pDoc
->DeleteTab(0);
3366 CPPUNIT_TEST_FIXTURE(Test
, testAutofilter
)
3368 m_pDoc
->InsertTab( 0, "Test" );
3370 // cell contents (0 = empty cell)
3371 const char* aData
[][3] = {
3372 { "C1", "C2", "C3" },
3374 { "1", "2", nullptr },
3379 SCCOL nCols
= SAL_N_ELEMENTS(aData
[0]);
3380 SCROW nRows
= SAL_N_ELEMENTS(aData
);
3383 for (SCROW i
= 0; i
< nRows
; ++i
)
3384 for (SCCOL j
= 0; j
< nCols
; ++j
)
3386 m_pDoc
->SetString(j
, i
, 0, OUString::createFromAscii(aData
[i
][j
]));
3388 ScDBData
* pDBData
= new ScDBData("NONAME", 0, 0, 0, nCols
-1, nRows
-1);
3389 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3391 pDBData
->SetAutoFilter(true);
3393 pDBData
->GetArea(aRange
);
3394 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3395 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3396 aRange
.aStart
.Tab(), ScMF::Auto
);
3398 //create the query param
3399 ScQueryParam aParam
;
3400 pDBData
->GetQueryParam(aParam
);
3401 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3402 rEntry
.bDoQuery
= true;
3404 rEntry
.eOp
= SC_EQUAL
;
3405 rEntry
.GetQueryItem().mfVal
= 0;
3406 // add queryParam to database range.
3407 pDBData
->SetQueryParam(aParam
);
3409 // perform the query.
3410 m_pDoc
->Query(0, aParam
, true);
3414 bool bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3415 CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden
);
3416 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(2), nRow1
);
3417 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(3), nRow2
);
3419 // Remove filtering.
3421 m_pDoc
->Query(0, aParam
, true);
3422 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3423 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden
);
3424 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3425 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3427 // Filter for non-empty cells by column C.
3428 rEntry
.bDoQuery
= true;
3430 rEntry
.SetQueryByNonEmpty();
3431 m_pDoc
->Query(0, aParam
, true);
3433 // only row 3 should be hidden. The rest should be visible.
3434 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3435 CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden
);
3436 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(0), nRow1
);
3437 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(1), nRow2
);
3438 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3439 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden
);
3440 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow1
);
3441 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow2
);
3442 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3443 CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden
);
3444 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", SCROW(3), nRow1
);
3445 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", m_pDoc
->MaxRow(), nRow2
);
3447 // Now, filter for empty cells by column C.
3448 rEntry
.SetQueryByEmpty();
3449 m_pDoc
->Query(0, aParam
, true);
3451 // Now, only row 1 and 3, and 6 and down should be visible.
3452 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3453 CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden
);
3454 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow1
);
3455 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow2
);
3456 bHidden
= m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
);
3457 CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden
);
3458 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow1
);
3459 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow2
);
3460 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3461 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden
);
3462 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow1
);
3463 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow2
);
3464 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3465 CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden
);
3466 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(3), nRow1
);
3467 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(4), nRow2
);
3468 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
3469 CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden
);
3470 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", SCROW(5), nRow1
);
3471 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", m_pDoc
->MaxRow(), nRow2
);
3473 m_pDoc
->DeleteTab(0);
3476 CPPUNIT_TEST_FIXTURE(Test
, testAutoFilterTimeValue
)
3478 m_pDoc
->InsertTab(0, "Test");
3480 m_pDoc
->SetString(ScAddress(0,0,0), "Hours");
3481 m_pDoc
->SetValue(ScAddress(0,1,0), 72.3604166666671);
3482 m_pDoc
->SetValue(ScAddress(0,2,0), 265);
3484 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 0, 2);
3485 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3487 // Apply the "hour:minute:second" format to A2:A3.
3488 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3489 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_TIME_HH_MMSS
, LANGUAGE_ENGLISH_US
);
3490 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3491 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3492 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3494 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 2, 0, aNewAttrs
); // apply it to A2:A3.
3496 printRange(m_pDoc
, ScRange(0,0,0,0,2,0), "Data"); // A1:A3
3498 // Make sure the hour:minute:second format is really applied.
3499 CPPUNIT_ASSERT_EQUAL(OUString("1736:39:00"), m_pDoc
->GetString(ScAddress(0,1,0))); // A2
3500 CPPUNIT_ASSERT_EQUAL(OUString("6360:00:00"), m_pDoc
->GetString(ScAddress(0,2,0))); // A3
3502 // Filter by the A2 value. Only A1 and A2 should be visible.
3503 ScQueryParam aParam
;
3504 pDBData
->GetQueryParam(aParam
);
3505 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3506 rEntry
.bDoQuery
= true;
3508 rEntry
.eOp
= SC_EQUAL
;
3509 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern("1736:39:00");
3510 rEntry
.GetQueryItem().meType
= ScQueryEntry::ByString
;
3512 pDBData
->SetQueryParam(aParam
);
3514 // perform the query.
3515 m_pDoc
->Query(0, aParam
, true);
3517 // A1:A2 should be visible while A3 should be filtered out.
3518 CPPUNIT_ASSERT_MESSAGE("A1 should be visible.", !m_pDoc
->RowFiltered(0,0));
3519 CPPUNIT_ASSERT_MESSAGE("A2 should be visible.", !m_pDoc
->RowFiltered(1,0));
3520 CPPUNIT_ASSERT_MESSAGE("A3 should be filtered out.", m_pDoc
->RowFiltered(2,0));
3522 m_pDoc
->DeleteTab(0);
3525 CPPUNIT_TEST_FIXTURE(Test
, testAutofilterOptimizations
)
3527 m_pDoc
->InsertTab( 0, "Test" );
3529 constexpr SCCOL nCols
= 4;
3530 constexpr SCROW nRows
= 200;
3531 m_pDoc
->SetString(0, 0, 0, "Column1");
3532 m_pDoc
->SetString(1, 0, 0, "Column2");
3533 m_pDoc
->SetString(2, 0, 0, "Column3");
3534 m_pDoc
->SetString(3, 0, 0, "Column4");
3536 // Fill 1st column with 0-199, 2nd with 1-200, 3rd with "1000"-"1199", 4th with "1001-1200"
3537 // (the pairs are off by one to each other to check filtering out a value filters out
3538 // only the relevant column).
3539 for(SCROW i
= 0; i
< nRows
; ++i
)
3541 m_pDoc
->SetValue(0, i
+ 1, 0, i
);
3542 m_pDoc
->SetValue(1, i
+ 1, 0, i
+1);
3543 m_pDoc
->SetString(2, i
+ 1, 0, "val" + OUString::number(i
+1000));
3544 m_pDoc
->SetString(3, i
+ 1, 0, "val" + OUString::number(i
+1000+1));
3547 ScDBData
* pDBData
= new ScDBData("NONAME", 0, 0, 0, nCols
, nRows
);
3548 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3550 pDBData
->SetAutoFilter(true);
3552 pDBData
->GetArea(aRange
);
3553 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3554 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3555 aRange
.aStart
.Tab(), ScMF::Auto
);
3557 //create the query param
3558 ScQueryParam aParam
;
3559 pDBData
->GetQueryParam(aParam
);
3560 ScQueryEntry
& rEntry0
= aParam
.GetEntry(0);
3561 rEntry0
.bDoQuery
= true;
3563 rEntry0
.eOp
= SC_EQUAL
;
3564 rEntry0
.GetQueryItems().resize(nRows
);
3565 ScQueryEntry
& rEntry1
= aParam
.GetEntry(1);
3566 rEntry1
.bDoQuery
= true;
3568 rEntry1
.eOp
= SC_EQUAL
;
3569 rEntry1
.GetQueryItems().resize(nRows
);
3570 ScQueryEntry
& rEntry2
= aParam
.GetEntry(2);
3571 rEntry2
.bDoQuery
= true;
3573 rEntry2
.eOp
= SC_EQUAL
;
3574 rEntry2
.GetQueryItems().resize(nRows
);
3575 ScQueryEntry
& rEntry3
= aParam
.GetEntry(3);
3576 rEntry3
.bDoQuery
= true;
3578 rEntry3
.eOp
= SC_EQUAL
;
3579 rEntry3
.GetQueryItems().resize(nRows
);
3580 // Set up autofilter to select all values except one in each column.
3581 // This should only filter out 2nd, 3rd, 6th and 7th rows.
3582 for( int i
= 0; i
< nRows
; ++i
)
3585 rEntry0
.GetQueryItems()[i
].mfVal
= i
;
3587 rEntry1
.GetQueryItems()[i
].mfVal
= i
+ 1;
3590 rEntry2
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000));
3591 rEntry2
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3595 rEntry3
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000+1));
3596 rEntry3
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3599 // add queryParam to database range.
3600 pDBData
->SetQueryParam(aParam
);
3602 // perform the query.
3603 m_pDoc
->Query(0, aParam
, true);
3605 // check that only rows with filtered out values are hidden, and not rows that share
3606 // a value in a different column
3608 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
));
3609 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden", m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
));
3610 CPPUNIT_ASSERT_MESSAGE("row 4 should be hidden", m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
));
3611 CPPUNIT_ASSERT_MESSAGE("row 5 should be visible", !m_pDoc
->RowHidden(4, 0, &nRow1
, &nRow2
));
3612 CPPUNIT_ASSERT_MESSAGE("row 6 should be visible", !m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
));
3613 CPPUNIT_ASSERT_MESSAGE("row 7 should be hidden", m_pDoc
->RowHidden(6, 0, &nRow1
, &nRow2
));
3614 CPPUNIT_ASSERT_MESSAGE("row 8 should be hidden", m_pDoc
->RowHidden(7, 0, &nRow1
, &nRow2
));
3615 CPPUNIT_ASSERT_MESSAGE("row 9 should be visible", !m_pDoc
->RowHidden(8, 0, &nRow1
, &nRow2
));
3617 // Remove filtering.
3621 m_pDoc
->Query(0, aParam
, true);
3622 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
));
3623 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3624 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3626 m_pDoc
->DeleteTab(0);
3629 CPPUNIT_TEST_FIXTURE(Test
, testTdf76441
)
3631 m_pDoc
->InsertTab(0, "Test");
3633 // The result will be different depending on whether the format is set before
3634 // or after inserting the string
3636 OUString aCode
= "MM:SS";
3637 sal_Int32 nCheckPos
;
3638 SvNumFormatType nType
;
3640 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3641 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3643 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3644 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3645 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3647 // First insert the string, then the format
3648 m_pDoc
->SetString(ScAddress(0,0,0), "01:20");
3650 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3652 CPPUNIT_ASSERT_EQUAL(OUString("20:00"), m_pDoc
->GetString(ScAddress(0,0,0)));
3656 // First set the format, then insert the string
3657 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3659 m_pDoc
->SetString(ScAddress(0,1,0), "01:20");
3661 // Without the fix in place, this test would have failed with
3662 // - Expected: 01:20
3664 CPPUNIT_ASSERT_EQUAL(OUString("01:20"), m_pDoc
->GetString(ScAddress(0,1,0)));
3667 m_pDoc
->DeleteTab(0);
3670 CPPUNIT_TEST_FIXTURE(Test
, testTdf76836
)
3672 m_pDoc
->InsertTab(0, "Test");
3674 OUString aCode
= "\"192.168.0.\"@";
3675 sal_Int32 nCheckPos
;
3676 SvNumFormatType nType
;
3678 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3679 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3681 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3682 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3683 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3685 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3686 m_pDoc
->SetValue(0,0,0, 10.0);
3688 // Without the fix in place, this test would have failed with
3690 // - Actual : 192.168.0.10
3691 CPPUNIT_ASSERT_EQUAL(OUString("10"), m_pDoc
->GetString(ScAddress(0,0,0)));
3693 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3694 m_pDoc
->SetString(ScAddress(0,1,0), "10");
3695 CPPUNIT_ASSERT_EQUAL(OUString("192.168.0.10"), m_pDoc
->GetString(ScAddress(0,1,0)));
3697 m_pDoc
->DeleteTab(0);
3700 CPPUNIT_TEST_FIXTURE(Test
, testTdf142186
)
3702 m_pDoc
->InsertTab(0, "Test");
3704 // The result will be different depending on whether the format is set before
3705 // or after inserting the string
3707 OUString aCode
= "0\".\"0";
3708 sal_Int32 nCheckPos
;
3709 SvNumFormatType nType
;
3711 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3712 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3714 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3715 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3716 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3718 // First insert the string, then the format
3719 m_pDoc
->SetString(ScAddress(0,0,0), "123.45");
3721 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3723 CPPUNIT_ASSERT_EQUAL(OUString("12.3"), m_pDoc
->GetString(ScAddress(0,0,0)));
3727 // First set the format, then insert the string
3728 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3730 m_pDoc
->SetString(ScAddress(0,1,0), "123.45");
3732 // Without the fix in place, this test would have failed with
3734 // - Actual : 1234.5
3735 CPPUNIT_ASSERT_EQUAL(OUString("12.3"), m_pDoc
->GetString(ScAddress(0,1,0)));
3738 m_pDoc
->DeleteTab(0);
3741 CPPUNIT_TEST_FIXTURE(Test
, testTdf137063
)
3743 m_pDoc
->InsertTab(0, "Test");
3745 m_pDoc
->SetValue(0,0,0, 0.000000006);
3746 m_pDoc
->SetValue(0,1,0, 0.0000000006);
3748 // Without the fix in place, this test would have failed with
3749 // - Expected: 0.000000006
3751 CPPUNIT_ASSERT_EQUAL(OUString("0.000000006"), m_pDoc
->GetString(ScAddress(0,0,0)));
3752 CPPUNIT_ASSERT_EQUAL(OUString("6E-10"), m_pDoc
->GetString(ScAddress(0,1,0)));
3754 m_pDoc
->DeleteTab(0);
3757 CPPUNIT_TEST_FIXTURE(Test
, testTdf126342
)
3759 m_pDoc
->InsertTab(0, "Test");
3761 OUString aCode
= "YYYY-MM-DD";
3762 sal_Int32 nCheckPos
;
3763 SvNumFormatType nType
;
3765 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3766 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3768 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3769 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3770 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3771 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3773 m_pDoc
->SetString(ScAddress(0,0,0), "11/7/19");
3775 CPPUNIT_ASSERT_EQUAL(OUString("2019-11-07"), m_pDoc
->GetString(ScAddress(0,0,0)));
3777 // Overwrite the existing date with the exact same input
3778 m_pDoc
->SetString(ScAddress(0,0,0), "11/7/19");
3780 // Without the fix in place, this test would have failed with
3781 // - Expected: 2019-11-07
3782 // - Actual : 2011-07-19
3783 CPPUNIT_ASSERT_EQUAL(OUString("2019-11-07"), m_pDoc
->GetString(ScAddress(0,0,0)));
3785 m_pDoc
->DeleteTab(0);
3788 CPPUNIT_TEST_FIXTURE(Test
, testAdvancedFilter
)
3790 m_pDoc
->InsertTab(0, "Test");
3792 // cell contents (nullptr = empty cell)
3793 std::vector
<std::vector
<const char*>> aData
= {
3794 { "Value", "Tag" }, // A1:B11
3806 { "Value", "Tag" }, // A13:B14
3811 for (size_t nRow
= 0; nRow
< aData
.size(); ++nRow
)
3813 const std::vector
<const char*>& rRowData
= aData
[nRow
];
3814 for (size_t nCol
= 0; nCol
< rRowData
.size(); ++nCol
)
3816 const char* pCell
= rRowData
[nCol
];
3818 m_pDoc
->SetString(nCol
, nRow
, 0, OUString::createFromAscii(pCell
));
3822 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 1, 10);
3823 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3825 ScRange
aDataRange(0,0,0,1,10,0);
3826 ScRange
aFilterRuleRange(0,12,0,1,13,0);
3828 printRange(m_pDoc
, aDataRange
, "Data");
3829 printRange(m_pDoc
, aFilterRuleRange
, "Filter Rule");
3831 ScQueryParam aQueryParam
;
3832 aQueryParam
.bHasHeader
= true;
3833 aQueryParam
.nCol1
= aDataRange
.aStart
.Col();
3834 aQueryParam
.nRow1
= aDataRange
.aStart
.Row();
3835 aQueryParam
.nCol2
= aDataRange
.aEnd
.Col();
3836 aQueryParam
.nRow2
= aDataRange
.aEnd
.Row();
3837 aQueryParam
.nTab
= aDataRange
.aStart
.Tab();
3839 bool bGood
= m_pDoc
->CreateQueryParam(aFilterRuleRange
, aQueryParam
);
3840 CPPUNIT_ASSERT_MESSAGE("failed to create query param.", bGood
);
3842 // First entry is for the 'Value' field, and is greater than 5.
3843 ScQueryEntry aEntry
= aQueryParam
.GetEntry(0);
3844 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
3845 CPPUNIT_ASSERT_EQUAL(SCCOLROW(0), aEntry
.nField
);
3846 CPPUNIT_ASSERT_EQUAL(SC_GREATER
, aEntry
.eOp
);
3848 ScQueryEntry::QueryItemsType aItems
= aEntry
.GetQueryItems();
3849 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
3850 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByValue
, aItems
[0].meType
);
3851 CPPUNIT_ASSERT_EQUAL(5.0, aItems
[0].mfVal
);
3853 // Second entry is for the 'Tag' field, and is == 'R'.
3854 aEntry
= aQueryParam
.GetEntry(1);
3855 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
3856 CPPUNIT_ASSERT_EQUAL(SCCOLROW(1), aEntry
.nField
);
3857 CPPUNIT_ASSERT_EQUAL(SC_EQUAL
, aEntry
.eOp
);
3859 aItems
= aEntry
.GetQueryItems();
3860 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
3861 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByString
, aItems
[0].meType
);
3862 CPPUNIT_ASSERT_EQUAL(OUString("R"), aItems
[0].maString
.getString());
3864 // perform the query.
3865 m_pDoc
->Query(0, aQueryParam
, true);
3867 // Only rows 1,8-10 should be visible.
3868 bool bFiltered
= m_pDoc
->RowFiltered(0, 0);
3869 CPPUNIT_ASSERT_MESSAGE("row 1 (header row) should be visible", !bFiltered
);
3871 SCROW nRow1
= -1, nRow2
= -1;
3872 bFiltered
= m_pDoc
->RowFiltered(1, 0, &nRow1
, &nRow2
);
3873 CPPUNIT_ASSERT_MESSAGE("rows 2-7 should be filtered out.", bFiltered
);
3874 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(1), nRow1
);
3875 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(6), nRow2
);
3877 bFiltered
= m_pDoc
->RowFiltered(7, 0, &nRow1
, &nRow2
);
3878 CPPUNIT_ASSERT_MESSAGE("rows 8-10 should be visible.", !bFiltered
);
3879 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(7), nRow1
);
3880 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(9), nRow2
);
3882 m_pDoc
->DeleteTab(0);
3885 CPPUNIT_TEST_FIXTURE(Test
, testDateFilterContains
)
3887 m_pDoc
->InsertTab(0, "Test");
3889 constexpr SCCOL nCols
= 1;
3890 constexpr SCROW nRows
= 5;
3891 m_pDoc
->SetString(0, 0, 0, "Date");
3892 m_pDoc
->SetString(0, 1, 0, "1/2/2021");
3893 m_pDoc
->SetString(0, 2, 0, "2/1/1999");
3894 m_pDoc
->SetString(0, 3, 0, "2/1/1997");
3895 m_pDoc
->SetString(0, 4, 0, "3/3/2001");
3896 m_pDoc
->SetString(0, 5, 0, "3/3/1996");
3898 // Set the fields as dates.
3899 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3900 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_DATE_DIN_YYMMDD
, LANGUAGE_ENGLISH_US
);
3901 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3902 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3903 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3904 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 5, 0, aNewAttrs
); // apply it to A1:A6
3906 ScDBData
* pDBData
= new ScDBData("NONAME", 0, 0, 0, nCols
, nRows
);
3907 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3909 pDBData
->SetAutoFilter(true);
3911 pDBData
->GetArea(aRange
);
3912 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3913 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3914 aRange
.aStart
.Tab(), ScMF::Auto
);
3916 //create the query param
3917 ScQueryParam aParam
;
3918 pDBData
->GetQueryParam(aParam
);
3919 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3920 rEntry
.bDoQuery
= true;
3922 rEntry
.eOp
= SC_CONTAINS
;
3923 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern("2");
3924 pDBData
->SetQueryParam(aParam
);
3926 // perform the query.
3927 m_pDoc
->Query(0, aParam
, true);
3929 // Dates in rows 2-4 contain '2', row 5 shows 2001 only as 01, and row 6 doesn't contain it at all.
3930 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0));
3931 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible", !m_pDoc
->RowHidden(2, 0));
3932 CPPUNIT_ASSERT_MESSAGE("row 4 should be visible", !m_pDoc
->RowHidden(3, 0));
3933 CPPUNIT_ASSERT_MESSAGE("row 5 should be hidden", m_pDoc
->RowHidden(4, 0));
3934 CPPUNIT_ASSERT_MESSAGE("row 6 should be hidden", m_pDoc
->RowHidden(5, 0));
3936 m_pDoc
->DeleteTab(0);
3939 CPPUNIT_TEST_FIXTURE(Test
, testTdf98642
)
3941 m_pDoc
->InsertTab(0, "Sheet1");
3942 m_pDoc
->SetString(0, 0, 0, "test");
3944 ScRangeData
* pName1
= new ScRangeData( *m_pDoc
, "name1", "$Sheet1.$A$1");
3945 ScRangeData
* pName2
= new ScRangeData( *m_pDoc
, "name2", "$Sheet1.$A$1");
3947 std::unique_ptr
<ScRangeName
> pGlobalRangeName(new ScRangeName());
3948 pGlobalRangeName
->insert(pName1
);
3949 pGlobalRangeName
->insert(pName2
);
3950 m_pDoc
->SetRangeName(std::move(pGlobalRangeName
));
3952 m_pDoc
->SetString(1, 0, 0, "=name1");
3953 m_pDoc
->SetString(1, 1, 0, "=name2");
3955 CPPUNIT_ASSERT_EQUAL(OUString("test"), m_pDoc
->GetString(1, 0, 0));
3956 CPPUNIT_ASSERT_EQUAL(OUString("test"), m_pDoc
->GetString(1, 1, 0));
3958 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
3959 CPPUNIT_ASSERT_EQUAL(OUString("=name1"), aFormula
);
3960 aFormula
= m_pDoc
->GetFormula(1,1,0);
3962 // Without the fix in place, this test would have failed with
3963 // - Expected: =name2
3964 // - Actual : =name1
3965 CPPUNIT_ASSERT_EQUAL(OUString("=name2"), aFormula
);
3967 m_pDoc
->DeleteTab(0);
3970 CPPUNIT_TEST_FIXTURE(Test
, testMergedCells
)
3972 //test merge and unmerge
3973 //TODO: an undo/redo test for this would be a good idea
3974 m_pDoc
->InsertTab(0, "Sheet1");
3975 m_pDoc
->DoMerge(1, 1, 3, 3, 0, false);
3978 m_pDoc
->ExtendMerge( 1, 1, nEndCol
, nEndRow
, 0);
3979 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCCOL(3), nEndCol
);
3980 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCROW(3), nEndRow
);
3981 ScRange
aRange(0,2,0,m_pDoc
->MaxCol(),2,0);
3982 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3983 aMark
.SetMarkArea(aRange
);
3984 m_xDocShell
->GetDocFunc().InsertCells(aRange
, &aMark
, INS_INSROWS_BEFORE
, true, true);
3985 m_pDoc
->ExtendMerge(1, 1, nEndCol
, nEndRow
, 0);
3986 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCCOL(3), nEndCol
);
3987 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCROW(4), nEndRow
);
3988 m_pDoc
->DeleteTab(0);
3991 CPPUNIT_TEST_FIXTURE(Test
, testRenameTable
)
3993 //test set rename table
3994 //TODO: set name1 and name2 and do an undo to check if name 1 is set now
3995 //TODO: also check if new name for table is same as another table
3997 m_pDoc
->InsertTab(0, "Sheet1");
3998 m_pDoc
->InsertTab(1, "Sheet2");
4000 //test case 1 , rename table2 to sheet 1, it should return error
4001 OUString nameToSet
= "Sheet1";
4002 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4003 CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc
.RenameTable(1,nameToSet
,false,true) );
4005 //test case 2 , simple rename to check name
4006 nameToSet
= "test1";
4007 m_xDocShell
->GetDocFunc().RenameTable(0,nameToSet
,false,true);
4008 OUString nameJustSet
;
4009 m_pDoc
->GetName(0,nameJustSet
);
4010 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4012 //test case 3 , rename again
4014 m_pDoc
->GetName(0,anOldName
);
4016 nameToSet
= "test2";
4017 rDocFunc
.RenameTable(0,nameToSet
,false,true);
4018 m_pDoc
->GetName(0,nameJustSet
);
4019 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4021 //test case 4 , check if undo works
4022 SfxUndoAction
* pUndo
= new ScUndoRenameTab(m_xDocShell
.get(),0,anOldName
,nameToSet
);
4024 m_pDoc
->GetName(0,nameJustSet
);
4025 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct name is not set after undo", nameJustSet
, anOldName
);
4028 m_pDoc
->GetName(0,nameJustSet
);
4029 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after redo", nameJustSet
, nameToSet
);
4032 m_pDoc
->DeleteTab(0);
4033 m_pDoc
->DeleteTab(1);
4036 CPPUNIT_TEST_FIXTURE(Test
, testSetBackgroundColor
)
4038 //test set background color
4039 //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
4041 m_pDoc
->InsertTab(0, "Sheet1");
4046 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4047 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set",
4048 aColor
, m_pDoc
->GetTabBgColor(0));
4050 Color aOldTabBgColor
=m_pDoc
->GetTabBgColor(0);
4052 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4053 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set the second time",
4054 aColor
, m_pDoc
->GetTabBgColor(0));
4056 //now check for undo
4057 SfxUndoAction
* pUndo
= new ScUndoTabColor(m_xDocShell
.get(), 0, aOldTabBgColor
, aColor
);
4059 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aOldTabBgColor
, m_pDoc
->GetTabBgColor(0));
4061 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aColor
, m_pDoc
->GetTabBgColor(0));
4063 m_pDoc
->DeleteTab(0);
4066 CPPUNIT_TEST_FIXTURE(Test
, testUpdateReference
)
4068 //test that formulas are correctly updated during sheet delete
4069 //TODO: add tests for relative references, updating of named ranges, ...
4070 m_pDoc
->InsertTab(0, "Sheet1");
4071 m_pDoc
->InsertTab(1, "Sheet2");
4072 m_pDoc
->InsertTab(2, "Sheet3");
4073 m_pDoc
->InsertTab(3, "Sheet4");
4075 m_pDoc
->SetValue(0,0,2, 1);
4076 m_pDoc
->SetValue(1,0,2, 2);
4077 m_pDoc
->SetValue(1,1,3, 4);
4078 m_pDoc
->SetString(2,0,2, "=A1+B1");
4079 m_pDoc
->SetString(2,1,2, "=Sheet4.B2+A1");
4082 aValue
= m_pDoc
->GetValue(2,0,2);
4083 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", 3, aValue
);
4084 aValue
= m_pDoc
->GetValue(2,1,2);
4085 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", 5, aValue
);
4087 //test deleting both sheets: one is not directly before the sheet, the other one is
4088 m_pDoc
->DeleteTab(0);
4089 aValue
= m_pDoc
->GetValue(2,0,1);
4090 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", 3, aValue
);
4091 aValue
= m_pDoc
->GetValue(2,1,1);
4092 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", 5, aValue
);
4094 m_pDoc
->DeleteTab(0);
4095 aValue
= m_pDoc
->GetValue(2,0,0);
4096 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", 3, aValue
);
4097 aValue
= m_pDoc
->GetValue(2,1,0);
4098 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", 5, aValue
);
4100 //test adding two sheets
4101 m_pDoc
->InsertTab(0, "Sheet2");
4102 aValue
= m_pDoc
->GetValue(2,0,1);
4103 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", 3, aValue
);
4104 aValue
= m_pDoc
->GetValue(2,1,1);
4105 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", 5, aValue
);
4107 m_pDoc
->InsertTab(0, "Sheet1");
4108 aValue
= m_pDoc
->GetValue(2,0,2);
4109 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", 3, aValue
);
4110 aValue
= m_pDoc
->GetValue(2,1,2);
4111 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", 5, aValue
);
4113 //test new DeleteTabs/InsertTabs methods
4114 m_pDoc
->DeleteTabs(0, 2);
4115 aValue
= m_pDoc
->GetValue(2, 0, 0);
4116 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", 3, aValue
);
4117 aValue
= m_pDoc
->GetValue(2, 1, 0);
4118 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", 5, aValue
);
4120 std::vector
<OUString
> aSheets
;
4121 aSheets
.emplace_back("Sheet1");
4122 aSheets
.emplace_back("Sheet2");
4123 m_pDoc
->InsertTabs(0, aSheets
, true);
4124 aValue
= m_pDoc
->GetValue(2, 0, 2);
4126 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", 3, aValue
);
4127 aValue
= m_pDoc
->GetValue(2, 1, 2);
4128 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", 5, aValue
);
4130 m_pDoc
->DeleteTab(3);
4131 m_pDoc
->DeleteTab(2);
4132 m_pDoc
->DeleteTab(1);
4133 m_pDoc
->DeleteTab(0);
4135 // Test positional update and invalidation of lookup cache for insertion
4136 // and deletion within entire column reference.
4137 m_pDoc
->InsertTab(0, "Sheet1");
4138 m_pDoc
->InsertTab(1, "Sheet2");
4139 m_pDoc
->SetString(0,1,0, "s1");
4140 m_pDoc
->SetString(0,0,1, "=MATCH(\"s1\";Sheet1.A:A;0)");
4141 aValue
= m_pDoc
->GetValue(0,0,1);
4142 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4143 m_pDoc
->InsertRow(0,0,m_pDoc
->MaxCol(),0,0,1); // insert 1 row before row 1 in Sheet1
4144 aValue
= m_pDoc
->GetValue(0,0,1);
4145 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 3, aValue
);
4146 m_pDoc
->DeleteRow(0,0,m_pDoc
->MaxCol(),0,0,1); // delete row 1 in Sheet1
4147 aValue
= m_pDoc
->GetValue(0,0,1);
4148 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4149 m_pDoc
->DeleteTab(1);
4150 m_pDoc
->DeleteTab(0);
4153 CPPUNIT_TEST_FIXTURE(Test
, testSearchCells
)
4155 m_pDoc
->InsertTab(0, "Test");
4157 m_pDoc
->SetString(ScAddress(0,0,0), "A");
4158 m_pDoc
->SetString(ScAddress(0,1,0), "B");
4159 m_pDoc
->SetString(ScAddress(0,2,0), "A");
4161 m_pDoc
->SetString(ScAddress(0,4,0), "A");
4162 m_pDoc
->SetString(ScAddress(0,5,0), "B");
4163 m_pDoc
->SetString(ScAddress(0,6,0), "C");
4165 SvxSearchItem
aItem(SID_SEARCH_ITEM
);
4166 aItem
.SetSearchString("A");
4167 aItem
.SetCommand(SvxSearchCmd::FIND_ALL
);
4168 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4169 aMarkData
.SelectOneTable(0);
4173 ScRangeList aMatchedRanges
;
4175 bool bMatchedRangesWereClamped
= false;
4176 bool bSuccess
= m_pDoc
->SearchAndReplace(aItem
, nCol
, nRow
, nTab
, aMarkData
, aMatchedRanges
, aUndoStr
, nullptr, bMatchedRangesWereClamped
);
4178 CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess
);
4179 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 3 matching cells.", size_t(3), aMatchedRanges
.size());
4180 ScAddress
aHit(0,0,0);
4181 CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4183 CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4185 CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4187 m_pDoc
->DeleteTab(0);
4190 CPPUNIT_TEST_FIXTURE(Test
, testFormulaPosition
)
4192 m_pDoc
->InsertTab(0, "Test");
4194 ScAddress
aPos(0,0,0); // A1
4195 m_pDoc
->SetString(aPos
, "=ROW()");
4196 aPos
.IncRow(); // A2
4197 m_pDoc
->SetString(aPos
, "=ROW()");
4198 aPos
.SetRow(3); // A4;
4199 m_pDoc
->SetString(aPos
, "=ROW()");
4202 SCROW aRows
[] = { 0, 1, 3 };
4203 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, SAL_N_ELEMENTS(aRows
));
4204 CPPUNIT_ASSERT(bRes
);
4207 m_pDoc
->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
4209 SCROW aRows
[] = { 0, 6, 8 };
4210 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, SAL_N_ELEMENTS(aRows
));
4211 CPPUNIT_ASSERT(bRes
);
4214 m_pDoc
->DeleteTab(0);
4219 bool hasRange(const ScDocument
* pDoc
, const std::vector
<ScTokenRef
>& rRefTokens
, const ScRange
& rRange
, const ScAddress
& rPos
)
4221 for (const ScTokenRef
& p
: rRefTokens
)
4223 if (!ScRefTokenHelper::isRef(p
) || ScRefTokenHelper::isExternalRef(p
))
4226 switch (p
->GetType())
4228 case formula::svSingleRef
:
4230 ScSingleRefData aData
= *p
->GetSingleRef();
4231 if (rRange
.aStart
!= rRange
.aEnd
)
4234 ScAddress aThis
= aData
.toAbs(*pDoc
, rPos
);
4235 if (aThis
== rRange
.aStart
)
4239 case formula::svDoubleRef
:
4241 ScComplexRefData aData
= *p
->GetDoubleRef();
4242 ScRange aThis
= aData
.toAbs(*pDoc
, rPos
);
4243 if (aThis
== rRange
)
4256 CPPUNIT_TEST_FIXTURE(Test
, testJumpToPrecedentsDependents
)
4259 * Test to make sure correct precedent / dependent cells are obtained when
4260 * preparing to jump to them.
4262 // Precedent is another cell that the cell references, while dependent is
4263 // another cell that references it.
4264 m_pDoc
->InsertTab(0, "Test");
4266 m_pDoc
->SetString(2, 0, 0, "=A1+A2+B3"); // C1
4267 m_pDoc
->SetString(2, 1, 0, "=A1"); // C2
4270 std::vector
<ScTokenRef
> aRefTokens
;
4271 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4274 // C1's precedent should be A1:A2,B3.
4275 ScAddress
aC1(2, 0, 0);
4276 ScRangeList
aRange(aC1
);
4277 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4278 CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
4279 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0, 0, 1, 0), aC1
));
4280 CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
4281 hasRange(m_pDoc
, aRefTokens
, ScRange(1, 2, 0), aC1
));
4285 // C2's precedent should be A1 only.
4286 ScAddress
aC2(2, 1, 0);
4287 ScRangeList
aRange(aC2
);
4288 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4289 CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
4290 static_cast<size_t>(1), aRefTokens
.size());
4291 CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
4292 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0), aC2
));
4296 // A1's dependent should be C1:C2.
4297 ScAddress
aA1(0, 0, 0);
4298 ScRangeList
aRange(aA1
);
4299 rDocFunc
.DetectiveCollectAllSuccs(aRange
, aRefTokens
);
4300 CPPUNIT_ASSERT_EQUAL_MESSAGE("C1:C2 should be the only dependent of A1.",
4301 std::vector
<ScTokenRef
>::size_type(1), aRefTokens
.size());
4302 CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
4303 hasRange(m_pDoc
, aRefTokens
, ScRange(2, 0, 0, 2, 1, 0), aA1
));
4306 m_pDoc
->DeleteTab(0);
4309 CPPUNIT_TEST_FIXTURE(Test
, testTdf149665
)
4311 m_pDoc
->InsertTab(0, "Test");
4313 m_pDoc
->SetString(0, 0, 0, "''1");
4315 // Without the fix in place, this test would have failed with
4318 CPPUNIT_ASSERT_EQUAL( OUString("'1"), m_pDoc
->GetString( 0, 0, 0 ) );
4320 m_pDoc
->DeleteTab(0);
4323 CPPUNIT_TEST_FIXTURE(Test
, testTdf64001
)
4325 m_pDoc
->InsertTab(0, "test");
4327 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4328 aMarkData
.SelectTable(0, true);
4330 m_pDoc
->SetString( 0, 0, 0, "TRUE" );
4331 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 9, FILL_TO_BOTTOM
, FILL_AUTO
);
4333 for (SCCOL i
= 0; i
< 10; ++i
)
4335 CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc
->GetString( 0, i
, 0 ) );
4338 m_pDoc
->SetString( 0, 10, 0, "FALSE" );
4340 m_pDoc
->SetString( 1, 0, 0, "=COUNTIF(A1:A11;TRUE)" );
4342 // Without the fix in place, this test would have failed with
4345 CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc
->GetValue( 1, 0, 0 ) );
4347 m_pDoc
->DeleteTab(0);
4350 CPPUNIT_TEST_FIXTURE(Test
, testAutoFill
)
4352 m_pDoc
->InsertTab(0, "test");
4354 m_pDoc
->SetValue(0,0,0,1);
4356 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4357 aMarkData
.SelectTable(0, true);
4359 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5);
4360 for (SCROW i
= 0; i
< 6; ++i
)
4361 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1.0), m_pDoc
->GetValue(0, i
, 0));
4363 // check that hidden rows are not affected by autofill
4364 // set values for hidden rows
4365 m_pDoc
->SetValue(0,1,0,10);
4366 m_pDoc
->SetValue(0,2,0,10);
4368 m_pDoc
->SetRowHidden(1, 2, 0, true);
4369 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 8);
4371 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,1,0));
4372 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,2,0));
4373 for (SCROW i
= 3; i
< 8; ++i
)
4374 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
-1.0), m_pDoc
->GetValue(0, i
, 0));
4376 m_pDoc
->Fill( 0, 0, 0, 8, nullptr, aMarkData
, 5, FILL_TO_RIGHT
);
4377 for (SCCOL i
= 0; i
< 5; ++i
)
4379 for(SCROW j
= 0; j
< 8; ++j
)
4383 ASSERT_DOUBLES_EQUAL(static_cast<double>(j
-1+i
), m_pDoc
->GetValue(i
, j
, 0));
4387 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(i
, 0, 0));
4389 else // j == 1 || j == 2
4392 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,j
,0));
4394 ASSERT_DOUBLES_EQUAL(0.0, m_pDoc
->GetValue(i
,j
,0));
4399 // test auto fill user data lists
4400 m_pDoc
->SetString( 0, 100, 0, "January" );
4401 m_pDoc
->Fill( 0, 100, 0, 100, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4402 OUString aTestValue
= m_pDoc
->GetString( 0, 101, 0 );
4403 CPPUNIT_ASSERT_EQUAL( OUString("February"), aTestValue
);
4404 aTestValue
= m_pDoc
->GetString( 0, 102, 0 );
4405 CPPUNIT_ASSERT_EQUAL( OUString("March"), aTestValue
);
4407 // test that two same user data list entries will not result in incremental fill
4408 m_pDoc
->SetString( 0, 101, 0, "January" );
4409 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4410 for ( SCROW i
= 102; i
<= 103; ++i
)
4412 aTestValue
= m_pDoc
->GetString( 0, i
, 0 );
4413 CPPUNIT_ASSERT_EQUAL( OUString("January"), aTestValue
);
4416 // Clear column A for a new test.
4417 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4418 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4420 // Fill A1:A6 with 1,2,3,4,5,6.
4421 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4422 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
4423 ScRange
aRange(0,0,0,0,5,0);
4424 aMarkData
.SetMarkArea(aRange
);
4425 rFunc
.FillSeries(aRange
, &aMarkData
, FILL_TO_BOTTOM
, FILL_AUTO
, FILL_DAY
, MAXDOUBLE
, 1.0, MAXDOUBLE
, true);
4426 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4427 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4428 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4429 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4430 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4431 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4433 // Undo should clear the area except for the top cell.
4434 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4435 CPPUNIT_ASSERT(pUndoMgr
);
4438 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4439 for (SCROW i
= 1; i
<= 5; ++i
)
4440 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(0,i
,0)));
4442 // Redo should put the serial values back in.
4444 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4445 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4446 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4447 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4448 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4449 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4451 // test that filling formulas vertically up does the right thing
4452 for(SCROW nRow
= 0; nRow
< 10; ++nRow
)
4453 m_pDoc
->SetValue(100, 100 + nRow
, 0, 1);
4455 m_pDoc
->SetString(100, 110, 0, "=A111");
4457 m_pDoc
->Fill(100, 110, 100, 110, nullptr, aMarkData
, 10, FILL_TO_TOP
, FILL_AUTO
);
4458 for(SCROW nRow
= 110; nRow
>= 100; --nRow
)
4460 OUString aExpected
= "=A" + OUString::number(nRow
+1);
4461 OUString aFormula
= m_pDoc
->GetFormula(100, nRow
, 0);
4462 CPPUNIT_ASSERT_EQUAL(aExpected
, aFormula
);
4465 // Clear column A for a new test.
4466 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4467 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4469 m_pDoc
->SetString( 0, 100, 0, "2012-10-31" );
4470 m_pDoc
->SetString( 0, 101, 0, "2012-10-31" );
4471 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4473 // tdf#89754, Without the fix in place, this test would have failed with
4474 // - Expected: 2012-10-31
4475 // - Actual : 2012-11-01
4476 CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc
->GetString( 0, 102, 0 ) );
4477 CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc
->GetString( 0, 103, 0 ) );
4478 CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc
->GetString( 0, 104, 0 ) );
4480 // Clear column A for a new test.
4481 clearRange(m_pDoc
, ScRange(0, 0, 0, 0, m_pDoc
->MaxRow(), 0));
4482 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4484 m_pDoc
->SetString(0, 100, 0, "2019-10-31");
4485 m_pDoc
->SetString(0, 101, 0, "2019-11-30");
4486 m_pDoc
->SetString(0, 102, 0, "2019-12-31");
4487 m_pDoc
->Fill(0, 100, 0, 102, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4489 // tdf#58745, Without the fix in place, this test would have failed with
4490 // - Expected: 2020-01-31
4491 // - Actual : 2019-01-11
4492 CPPUNIT_ASSERT_EQUAL(OUString("2020-01-31"), m_pDoc
->GetString(0, 103, 0));
4493 CPPUNIT_ASSERT_EQUAL(OUString("2020-02-29"), m_pDoc
->GetString(0, 104, 0));
4494 CPPUNIT_ASSERT_EQUAL(OUString("2020-03-31"), m_pDoc
->GetString(0, 105, 0));
4496 // Clear column A for a new test.
4497 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4498 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4500 m_pDoc
->SetString( 0, 50, 0, "1.0" );
4501 m_pDoc
->SetString( 0, 51, 0, "1.1" );
4502 m_pDoc
->SetString( 0, 52, 0, "1.2" );
4503 m_pDoc
->SetString( 0, 53, 0, "1.3" );
4504 m_pDoc
->Fill( 0, 50, 0, 53, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4506 CPPUNIT_ASSERT_EQUAL( OUString("1.4"), m_pDoc
->GetString( 0, 54, 0 ) );
4507 CPPUNIT_ASSERT_EQUAL( OUString("1.5"), m_pDoc
->GetString( 0, 55, 0 ) );
4508 CPPUNIT_ASSERT_EQUAL( OUString("1.6"), m_pDoc
->GetString( 0, 56, 0 ) );
4510 m_pDoc
->SetString( 0, 60, 0, "4.0" );
4511 m_pDoc
->SetString( 0, 61, 0, "4.1" );
4512 m_pDoc
->SetString( 0, 62, 0, "4.2" );
4513 m_pDoc
->SetString( 0, 63, 0, "4.3" );
4514 m_pDoc
->Fill( 0, 60, 0, 63, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4516 // tdf#37424: Without the fix in place, this test would have failed with
4519 CPPUNIT_ASSERT_EQUAL( OUString("4.4"), m_pDoc
->GetString( 0, 64, 0 ) );
4520 CPPUNIT_ASSERT_EQUAL( OUString("4.5"), m_pDoc
->GetString( 0, 65, 0 ) );
4521 CPPUNIT_ASSERT_EQUAL( OUString("4.6"), m_pDoc
->GetString( 0, 66, 0 ) );
4523 // Clear column A for a new test.
4524 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4525 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4527 m_pDoc
->SetString( 0, 70, 0, "001-001-001" );
4528 m_pDoc
->Fill( 0, 70, 0, 70, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4530 // tdf#105268: Without the fix in place, this test would have failed with
4531 // - Expected: 001-001-002
4532 // - Actual : 001-001000
4533 CPPUNIT_ASSERT_EQUAL( OUString("001-001-002"), m_pDoc
->GetString( 0, 71, 0 ) );
4534 CPPUNIT_ASSERT_EQUAL( OUString("001-001-003"), m_pDoc
->GetString( 0, 72, 0 ) );
4535 CPPUNIT_ASSERT_EQUAL( OUString("001-001-004"), m_pDoc
->GetString( 0, 73, 0 ) );
4537 // Clear column A for a new test.
4538 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4539 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4541 m_pDoc
->SetString( 0, 80, 0, "1%" );
4542 m_pDoc
->Fill( 0, 80, 0, 80, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4544 // tdf#89998: Without the fix in place, this test would have failed with
4545 // - Expected: 2.00%
4546 // - Actual : 101.00%
4547 CPPUNIT_ASSERT_EQUAL( OUString("2.00%"), m_pDoc
->GetString( 0, 81, 0 ) );
4548 CPPUNIT_ASSERT_EQUAL( OUString("3.00%"), m_pDoc
->GetString( 0, 82, 0 ) );
4549 CPPUNIT_ASSERT_EQUAL( OUString("4.00%"), m_pDoc
->GetString( 0, 83, 0 ) );
4551 // Clear column A for a new test.
4552 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4553 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4555 m_pDoc
->SetString( 0, 0, 0, "1" );
4556 m_pDoc
->SetString( 0, 1, 0, "1.1" );
4557 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 60, FILL_TO_BOTTOM
, FILL_AUTO
);
4559 // tdf#129606: Without the fix in place, this test would have failed with
4561 // - Actual : 6.00000000000001
4562 CPPUNIT_ASSERT_EQUAL( OUString("6"), m_pDoc
->GetString( 0, 50, 0 ) );
4564 // Clear column A for a new test.
4565 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4566 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4568 m_pDoc
->SetString( 0, 0, 0, "2022-10-01 00:00:00.000" );
4569 m_pDoc
->SetString( 0, 1, 0, "2022-10-01 01:00:00.000" );
4570 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4572 // tdf#151460: Without the fix in place, this test would have failed with
4573 // - Expected: 2022-10-01 20:00:00.000
4574 // - Actual : 2022-10-01 19:59:59.999
4575 CPPUNIT_ASSERT_EQUAL( OUString("2022-10-01 20:00:00.000"), m_pDoc
->GetString( 0, 20, 0 ) );
4577 // Clear column A for a new test.
4578 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4579 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4581 m_pDoc
->SetString( 0, 0, 0, "1st" );
4583 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5, FILL_TO_BOTTOM
, FILL_AUTO
);
4585 CPPUNIT_ASSERT_EQUAL( OUString("1st"), m_pDoc
->GetString( 0, 0, 0 ) );
4586 CPPUNIT_ASSERT_EQUAL( OUString("2nd"), m_pDoc
->GetString( 0, 1, 0 ) );
4587 CPPUNIT_ASSERT_EQUAL( OUString("3rd"), m_pDoc
->GetString( 0, 2, 0 ) );
4589 // Clear column A for a new test.
4590 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4591 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4593 m_pDoc
->SetString( 0, 200, 0, "15:00" );
4594 m_pDoc
->SetString( 0, 201, 0, "15:20" );
4595 m_pDoc
->Fill( 0, 200, 0, 201, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4597 CPPUNIT_ASSERT_EQUAL( OUString("03:00:00 PM"), m_pDoc
->GetString( 0, 200, 0 ) );
4599 // tdf#153517: Without the fix in place, this test would have failed with
4600 // - Expected: 03:20:00 PM
4601 // - Actual : 03:19:59 PM
4602 CPPUNIT_ASSERT_EQUAL( OUString("03:20:00 PM"), m_pDoc
->GetString( 0, 201, 0 ) );
4603 CPPUNIT_ASSERT_EQUAL( OUString("03:40:00 PM"), m_pDoc
->GetString( 0, 202, 0 ) );
4604 CPPUNIT_ASSERT_EQUAL( OUString("04:00:00 PM"), m_pDoc
->GetString( 0, 203, 0 ) );
4606 m_pDoc
->DeleteTab(0);
4609 CPPUNIT_TEST_FIXTURE(Test
, testAutoFillSimple
)
4611 m_pDoc
->InsertTab(0, "test");
4613 m_pDoc
->SetValue(0, 0, 0, 1);
4614 m_pDoc
->SetString(0, 1, 0, "=10");
4616 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4617 aMarkData
.SelectTable(0, true);
4619 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 6, FILL_TO_BOTTOM
, FILL_AUTO
);
4621 for(SCROW nRow
= 0; nRow
< 8; ++nRow
)
4625 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4626 CPPUNIT_ASSERT_EQUAL((nRow
+2)/2.0, nVal
);
4630 OString aMsg
= "wrong value in row: " + OString::number(nRow
);
4631 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4632 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), 10.0, nVal
);
4636 m_pDoc
->DeleteTab(0);
4639 CPPUNIT_TEST_FIXTURE(Test
, testFindAreaPosVertical
)
4641 std::vector
<std::vector
<const char*>> aData
= {
4642 { nullptr, "1", "1" },
4643 { "1", nullptr, "1" },
4645 { nullptr, "1", "1" },
4647 { "1", nullptr, "1" },
4651 m_pDoc
->InsertTab(0, "Test1");
4652 clearRange( m_pDoc
, ScRange(0, 0, 0, 1, aData
.size(), 0));
4653 ScAddress
aPos(0,0,0);
4654 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4655 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4657 m_pDoc
->SetRowHidden(4,4,0,true);
4658 bool bHidden
= m_pDoc
->RowHidden(4,0);
4659 CPPUNIT_ASSERT(bHidden
);
4663 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4665 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4666 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4668 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4670 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), nRow
);
4671 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4673 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4675 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(5), nRow
);
4676 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4678 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4680 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4681 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4683 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4685 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), nRow
);
4686 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4691 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4693 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), nRow
);
4694 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4696 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4698 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4699 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4703 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_UP
);
4704 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4705 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4707 m_pDoc
->DeleteTab(0);
4710 CPPUNIT_TEST_FIXTURE(Test
, testFindAreaPosColRight
)
4712 std::vector
<std::vector
<const char*>> aData
= {
4713 { "", "1", "1", "", "1", "1", "1" },
4714 { "", "", "1", "1", "1", "", "1" },
4717 m_pDoc
->InsertTab(0, "test1");
4718 clearRange( m_pDoc
, ScRange(0, 0, 0, 7, aData
.size(), 0));
4719 ScAddress
aPos(0,0,0);
4720 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4721 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4723 m_pDoc
->SetColHidden(4,4,0,true);
4724 bool bHidden
= m_pDoc
->ColHidden(4,0);
4725 CPPUNIT_ASSERT(bHidden
);
4729 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4731 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4732 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4734 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4736 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4737 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4739 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4741 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4742 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(5), nCol
);
4744 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4746 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4747 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4749 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4751 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4752 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), nCol
);
4757 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4759 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4760 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(3), nCol
);
4762 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4764 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4765 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4767 m_pDoc
->DeleteTab(0);
4770 CPPUNIT_TEST_FIXTURE(Test
, testShiftCells
)
4772 m_pDoc
->InsertTab(0, "foo");
4774 // We need a drawing layer in order to create caption objects.
4775 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4777 OUString
aTestVal("Some Text");
4779 // Text into cell E5.
4780 m_pDoc
->SetString(4, 3, 0, aTestVal
);
4782 // put a Note in cell E5
4783 ScAddress
rAddr(4, 3, 0);
4784 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
4785 pNote
->SetText(rAddr
, "Hello");
4787 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4789 // Insert cell at D5. This should shift the string cell to right.
4790 m_pDoc
->InsertCol(3, 0, 3, 0, 3, 1);
4791 OUString aStr
= m_pDoc
->GetString(5, 3, 0);
4792 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4793 CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(3, 4, 3, 4, 0));
4795 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(4, 3, 0));
4796 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(5, 3, 0));
4798 // Delete cell D5, to shift the text cell back into D5.
4799 m_pDoc
->DeleteCol(3, 0, 3, 0, 3, 1);
4800 aStr
= m_pDoc
->GetString(4, 3, 0);
4801 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4802 CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(4, 4, 4, 4, 0));
4804 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(5, 3, 0));
4805 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4807 m_pDoc
->DeleteTab(0);
4810 CPPUNIT_TEST_FIXTURE(Test
, testNoteDefaultStyle
)
4812 m_pDoc
->InsertTab(0, "PostIts");
4814 // We need a drawing layer in order to create caption objects.
4815 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4817 auto pNote
= m_pDoc
->GetOrCreateNote({0, 0, 0});
4818 auto pCaption
= pNote
->GetCaption();
4820 CPPUNIT_ASSERT(pCaption
);
4821 CPPUNIT_ASSERT_EQUAL(ScResId(STR_STYLENAME_NOTE
), pCaption
->GetStyleSheet()->GetName());
4823 m_pDoc
->DeleteTab(0);
4826 CPPUNIT_TEST_FIXTURE(Test
, testNoteBasic
)
4828 m_pDoc
->InsertTab(0, "PostIts");
4830 // We need a drawing layer in order to create caption objects.
4831 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4833 CPPUNIT_ASSERT(!m_pDoc
->HasNotes());
4835 // Check for note's presence in all tables before inserting any notes.
4836 for (SCTAB i
= 0; i
<= MAXTAB
; ++i
)
4838 bool bHasNotes
= m_pDoc
->HasTabNotes(i
);
4839 CPPUNIT_ASSERT(!bHasNotes
);
4842 ScAddress
aAddr(2, 2, 0); // cell C3
4843 ScPostIt
*pNote
= m_pDoc
->GetOrCreateNote(aAddr
);
4845 pNote
->SetText(aAddr
, "Hello world");
4846 pNote
->SetAuthor("Jim Bob");
4848 ScPostIt
*pGetNote
= m_pDoc
->GetNote(aAddr
);
4849 CPPUNIT_ASSERT_EQUAL_MESSAGE("note should be itself", pNote
, pGetNote
);
4851 // Insert one row at row 1.
4852 bool bInsertRow
= m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
4853 CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow
);
4855 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4856 aAddr
.IncRow(); // cell C4
4857 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4859 // Insert column at column A.
4860 bool bInsertCol
= m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
4861 CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol
);
4863 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4864 aAddr
.IncCol(); // cell D4
4865 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4867 // Insert a new sheet to shift the current sheet to the right.
4868 m_pDoc
->InsertTab(0, "Table2");
4869 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4870 aAddr
.IncTab(); // Move to the next sheet.
4871 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4873 m_pDoc
->DeleteTab(0);
4875 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4877 // Insert cell at C4. This should NOT shift the note position.
4878 bInsertRow
= m_pDoc
->InsertRow(2, 0, 2, 0, 3, 1);
4879 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow
);
4880 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
4882 // Delete cell at C4. Again, this should NOT shift the note position.
4883 m_pDoc
->DeleteRow(2, 0, 2, 0, 3, 1);
4884 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
4886 // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
4887 m_pDoc
->DeleteRow(3, 0, 3, 0, 2, 1);
4888 aAddr
.IncRow(-1); // cell D3
4889 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D4 should have shifted up to D3.", pNote
, m_pDoc
->GetNote(aAddr
));
4891 // Delete column C. This should shift the note one cell left.
4892 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 2, 1);
4893 aAddr
.IncCol(-1); // cell C3
4894 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D3 should have shifted left to C3.", pNote
, m_pDoc
->GetNote(aAddr
));
4896 // Insert a text where the note is.
4897 m_pDoc
->SetString(aAddr
, "Note is here.");
4899 // Delete row 1. This should shift the note from C3 to C2.
4900 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 1);
4901 aAddr
.IncRow(-1); // C2
4902 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at C3 should have shifted up to C2.", pNote
, m_pDoc
->GetNote(aAddr
));
4904 m_pDoc
->DeleteTab(0);
4907 CPPUNIT_TEST_FIXTURE(Test
, testNoteDeleteRow
)
4909 m_pDoc
->InsertTab(0, "Sheet1");
4911 // We need a drawing layer in order to create caption objects.
4912 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4914 ScAddress
aPos(1, 1, 0);
4915 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
4916 pNote
->SetText(aPos
, "Hello");
4917 pNote
->SetAuthor("Jim Bob");
4919 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
4921 // test with IsBlockEmpty
4922 CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc
->IsEmptyData(0, 0, 100, 100, 0));
4923 CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
4925 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
4927 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
4929 // Set values and notes into B3:B4.
4930 aPos
= ScAddress(1,2,0); // B3
4931 m_pDoc
->SetString(aPos
, "First");
4932 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, "First Note", false, false);
4934 aPos
= ScAddress(1,3,0); // B4
4935 m_pDoc
->SetString(aPos
, "Second");
4936 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, "Second Note", false, false);
4939 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4940 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4941 aMark
.SelectOneTable(0);
4942 rDocFunc
.DeleteCells(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0), &aMark
, DelCellCmd::CellsUp
, true);
4944 // Check to make sure the notes have shifted upward.
4945 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
4946 CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote
);
4947 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote
->GetText());
4948 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4949 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4950 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
4951 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
4952 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
4956 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4957 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
4958 m_pDoc
->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
4961 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
4962 CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote
);
4963 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4964 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4965 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote
->GetText());
4966 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
4967 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
4968 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
4971 rDocFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
4973 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4974 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4975 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
4976 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
4977 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
4979 // Undo and check the result.
4981 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4982 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4983 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote
->GetText());
4984 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
4985 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
4986 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
4988 m_pDoc
->DeleteTab(0);
4991 CPPUNIT_TEST_FIXTURE(Test
, testNoteDeleteCol
)
4993 m_pDoc
->InsertTab(0, "Sheet1");
4995 // We need a drawing layer in order to create caption objects.
4996 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4998 ScAddress
rAddr(1, 1, 0);
4999 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5000 pNote
->SetText(rAddr
, "Hello");
5001 pNote
->SetAuthor("Jim Bob");
5003 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
5005 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
5007 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
5009 m_pDoc
->DeleteTab(0);
5012 CPPUNIT_TEST_FIXTURE(Test
, testNoteLifeCycle
)
5014 m_pDoc
->InsertTab(0, "Test");
5016 // We need a drawing layer in order to create caption objects.
5017 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5019 ScAddress
aPos(1,1,0);
5020 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5021 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote
);
5023 pNote
->SetText(aPos
, "New note");
5024 std::unique_ptr
<ScPostIt
> pNote2
= m_pDoc
->ReleaseNote(aPos
);
5025 CPPUNIT_ASSERT_EQUAL_MESSAGE("This note instance is expected to be identical to the original.", pNote
, pNote2
.get());
5026 CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc
->HasNote(aPos
));
5028 // Modify the internal state of the note instance to make sure it's really
5030 pNote
->SetText(aPos
, "New content");
5032 // Re-insert the note back to the same place.
5033 m_pDoc
->SetNote(aPos
, std::move(pNote2
));
5034 SdrCaptionObj
* pCaption
= pNote
->GetOrCreateCaption(aPos
);
5035 CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption
);
5036 CPPUNIT_ASSERT_EQUAL_MESSAGE("This caption should belong to the drawing layer of the document.",
5037 m_pDoc
->GetDrawLayer(), static_cast<ScDrawLayer
*>(&pCaption
->getSdrModelFromSdrObject()));
5039 // Copy B2 with note to a clipboard.
5041 ScClipParam
aClipParam(aPos
, false);
5042 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5043 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
5044 aMarkData
.SelectOneTable(0);
5045 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMarkData
, false, true);
5047 ScPostIt
* pClipNote
= aClipDoc
.GetNote(aPos
);
5048 CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote
);
5049 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note on the clipboard should share the same caption object from the original.",
5050 pCaption
, pClipNote
->GetCaption());
5053 // Move B2 to B3 with note, which creates an ScUndoDragDrop, and Undo.
5055 ScAddress
aOrigPos(aPos
);
5056 ScAddress
aMovePos(1,2,0);
5057 ScPostIt
* pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5058 const SdrCaptionObj
* pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5059 bool const bCut
= true; // like Drag&Drop
5060 bool bRecord
= true; // record Undo
5061 bool const bPaint
= false; // don't care about
5062 bool bApi
= true; // API to prevent dialogs
5063 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
5064 bool bMoveDone
= rDocFunc
.MoveBlock(ScRange(aOrigPos
, aOrigPos
), aMovePos
, bCut
, bRecord
, bPaint
, bApi
);
5065 CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone
);
5067 // Verify the note move.
5068 ScPostIt
* pGoneNote
= m_pDoc
->GetNote(aOrigPos
);
5069 CPPUNIT_ASSERT_MESSAGE("Failed to move the note from source.", !pGoneNote
);
5070 ScPostIt
* pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5071 CPPUNIT_ASSERT_MESSAGE("Failed to move the note to destination.", pMoveNote
);
5073 // The caption object should not be identical, it was newly created upon
5074 // Drop from clipboard.
5075 // pOrigCaption is a dangling pointer.
5076 const SdrCaptionObj
* pMoveCaption
= pMoveNote
->GetOrCreateCaption(aMovePos
);
5077 CPPUNIT_ASSERT_MESSAGE("Captions identical after move.", pOrigCaption
!= pMoveCaption
);
5079 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5080 CPPUNIT_ASSERT(pUndoMgr
);
5081 pUndoMgr
->Undo(); // this should not crash ... tdf#92995
5083 // Verify the note move Undo.
5084 pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5085 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move from destination.", !pMoveNote
);
5086 pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5087 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move to source.", pOrigNote
);
5089 // The caption object still should not be identical.
5090 // pMoveCaption is a dangling pointer.
5091 pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5092 CPPUNIT_ASSERT_MESSAGE("Captions identical after move undo.", pOrigCaption
!= pMoveCaption
);
5095 // Create a note at B4, merge B4 and B5 with ScUndoMerge, and Undo.
5097 ScAddress
aPosB4(1,3,0);
5098 ScPostIt
* pNoteB4
= m_pDoc
->GetOrCreateNote(aPosB4
);
5099 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B4.", pNoteB4
);
5100 const SdrCaptionObj
* pCaptionB4
= pNoteB4
->GetOrCreateCaption(aPosB4
);
5101 ScCellMergeOption
aCellMergeOption(1,3,2,3);
5102 rDocFunc
.MergeCells( aCellMergeOption
, true /*bContents*/, bRecord
, bApi
, false /*bEmptyMergedCells*/ );
5104 SfxUndoManager
* pMergeUndoManager
= m_pDoc
->GetUndoManager();
5105 CPPUNIT_ASSERT(pMergeUndoManager
);
5106 pMergeUndoManager
->Undo(); // this should not crash ... tdf#105667
5108 // Undo contained the original caption object pointer which was still alive
5109 // at B4 after the merge and not cloned nor recreated during Undo.
5110 ScPostIt
* pUndoNoteB4
= m_pDoc
->GetNote(aPosB4
);
5111 CPPUNIT_ASSERT_MESSAGE("No cell comment at B4 after Undo.", pUndoNoteB4
);
5112 const SdrCaptionObj
* pUndoCaptionB4
= pUndoNoteB4
->GetCaption();
5113 CPPUNIT_ASSERT_EQUAL_MESSAGE("Captions not identical after Merge Undo.", pCaptionB4
, pUndoCaptionB4
);
5116 // In a second document copy a note from B5 to clipboard, close the
5117 // document and then paste the note into this document.
5119 ScDocShellRef xDocSh2
;
5120 getNewDocShell(xDocSh2
);
5121 ScDocument
* pDoc2
= &xDocSh2
->GetDocument();
5122 pDoc2
->InsertTab(0, "OtherSheet1");
5123 pDoc2
->InitDrawLayer(xDocSh2
.get());
5125 ScAddress
aPosB5(1,4,0);
5126 ScPostIt
* pOtherNoteB5
= pDoc2
->GetOrCreateNote(aPosB5
);
5127 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B5.", pOtherNoteB5
);
5128 const SdrCaptionObj
* pOtherCaptionB5
= pOtherNoteB5
->GetOrCreateCaption(aPosB5
);
5129 CPPUNIT_ASSERT_MESSAGE("No caption at B5.", pOtherCaptionB5
);
5131 ScDocument
aClipDoc2(SCDOCMODE_CLIP
);
5132 copyToClip( pDoc2
, aPosB5
, &aClipDoc2
);
5134 // There's no ScTransferObject involved in the "fake" clipboard copy
5135 // and ScDocument dtor asking IsClipboardSource() gets no, so emulate
5136 // the part that normally is responsible for forgetting the caption
5138 aClipDoc2
.ClosingClipboardSource();
5140 pDoc2
->DeleteTab(0);
5144 pasteFromClip( m_pDoc
, aPosB5
, &aClipDoc2
); // should not crash... tdf#104967
5145 ScPostIt
* pNoteB5
= m_pDoc
->GetNote(aPosB5
);
5146 CPPUNIT_ASSERT_MESSAGE("Failed to paste cell comment at B5.", pNoteB5
);
5147 const SdrCaptionObj
* pCaptionB5
= pNoteB5
->GetOrCreateCaption(aPosB5
);
5148 CPPUNIT_ASSERT_MESSAGE("No caption at pasted B5.", pCaptionB5
);
5149 // Do not test if pCaptionB5 != pOtherCaptionB5 because since pDoc2
5150 // has been closed and the caption been deleted objects *may* be
5151 // allocated at the very same memory location.
5154 m_pDoc
->DeleteTab(0);
5157 CPPUNIT_TEST_FIXTURE(Test
, testNoteCopyPaste
)
5159 m_pDoc
->InsertTab(0, "Test");
5161 // We need a drawing layer in order to create caption objects.
5162 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5164 // Insert in B2 a text and cell comment.
5165 ScAddress
aPos(1,1,0);
5166 m_pDoc
->SetString(aPos
, "Text");
5167 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5168 CPPUNIT_ASSERT(pNote
);
5169 pNote
->SetText(aPos
, "Note1");
5171 // Insert in B4 a number and cell comment.
5173 m_pDoc
->SetValue(aPos
, 1.1);
5174 pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5175 CPPUNIT_ASSERT(pNote
);
5176 pNote
->SetText(aPos
, "Note2");
5178 // Copy B2:B4 to clipboard.
5179 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5180 aMark
.SelectOneTable(0);
5181 ScRange
aCopyRange(1,1,0,1,3,0);
5182 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5183 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
5184 ScClipParam
aClipParam(aCopyRange
, false);
5185 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMark
, false, false);
5187 // Make sure the notes are in the clipboard.
5188 pNote
= aClipDoc
.GetNote(ScAddress(1,1,0));
5189 CPPUNIT_ASSERT(pNote
);
5190 CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote
->GetText());
5192 pNote
= aClipDoc
.GetNote(ScAddress(1,3,0));
5193 CPPUNIT_ASSERT(pNote
);
5194 CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote
->GetText());
5196 // Paste to B6:B8 but only cell notes.
5197 ScRange
aDestRange(1,5,0,1,7,0);
5198 m_pDoc
->CopyFromClip(aDestRange
, aMark
, InsertDeleteFlags::NOTE
, nullptr, &aClipDoc
);
5200 // Make sure the notes are there.
5201 pNote
= m_pDoc
->GetNote(ScAddress(1,5,0));
5202 CPPUNIT_ASSERT(pNote
);
5203 CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote
->GetText());
5205 pNote
= m_pDoc
->GetNote(ScAddress(1,7,0));
5206 CPPUNIT_ASSERT(pNote
);
5207 CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote
->GetText());
5209 // Test that GetNotesInRange includes the end of its range
5210 // and so can find the note
5211 std::vector
<sc::NoteEntry
> aNotes
;
5212 m_pDoc
->GetNotesInRange(ScRange(1,7,0), aNotes
);
5213 CPPUNIT_ASSERT_EQUAL(size_t(1), aNotes
.size());
5215 m_pDoc
->DeleteTab(0);
5219 CPPUNIT_TEST_FIXTURE(Test
, testNoteContainsNotesInRange
)
5221 m_pDoc
->InsertTab(0, "PostIts");
5223 // We need a drawing layer in order to create caption objects.
5224 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5226 ScAddress
aAddr(2, 2, 0); // cell C3
5228 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in a document that doesn't have any.",
5229 !m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5231 m_pDoc
->GetOrCreateNote(aAddr
);
5233 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in range that doesn't have any.",
5234 !m_pDoc
->ContainsNotesInRange(ScRange(ScAddress(0, 0, 0), ScAddress(0, 1, 0))));
5235 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies on border of range.",
5236 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5237 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies in inner area of range.",
5238 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), ScAddress(3, 3, 0)))));
5241 CPPUNIT_TEST_FIXTURE(Test
, testAreasWithNotes
)
5243 m_pDoc
->InsertTab(0, "Sheet1");
5245 // We need a drawing layer in order to create caption objects.
5246 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5248 ScAddress
rAddr(1, 5, 0);
5249 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5250 pNote
->SetText(rAddr
, "Hello");
5251 pNote
->SetAuthor("Jim Bob");
5252 ScAddress
rAddrMin(2, 2, 0);
5253 ScPostIt
* pNoteMin
= m_pDoc
->GetOrCreateNote(rAddrMin
);
5254 pNoteMin
->SetText(rAddrMin
, "Hello");
5260 // only cell notes (empty content)
5262 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5264 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5265 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col for notes", static_cast<SCCOL
>(1), col
);
5266 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row for notes", static_cast<SCROW
>(2), row
);
5268 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5270 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5271 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5272 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row for notes", static_cast<SCROW
>(5), row
);
5275 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5277 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5278 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5279 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row for notes", static_cast<SCROW
>(5), row
);
5282 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5283 CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound
);
5286 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5287 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5288 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(5), row
);
5290 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5291 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5292 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(2), row
);
5294 dataFound
= m_pDoc
->GetPrintAreaVer(0,20,21,row
, bNotes
); // cols 20 & 21
5295 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer found", !dataFound
);
5296 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(0), row
);
5299 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // col 0 & 1
5300 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound
);
5302 // now add cells with value, check that notes are taken into account in good cases
5304 m_pDoc
->SetString(0, 3, 0, "Some Text");
5305 m_pDoc
->SetString(3, 3, 0, "Some Text");
5307 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5309 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5310 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col", static_cast<SCCOL
>(0), col
);
5311 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row", static_cast<SCROW
>(2), row
);
5313 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5315 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5316 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col", static_cast<SCCOL
>(3), col
);
5317 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row", static_cast<SCROW
>(5), row
);
5320 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5322 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5323 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5324 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(5), row
);
5327 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5328 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5329 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5330 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(3), row
);
5333 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5334 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5335 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(5), row
);
5337 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5338 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5339 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5342 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5343 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5344 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5346 m_pDoc
->DeleteTab(0);
5349 CPPUNIT_TEST_FIXTURE(Test
, testAnchoredRotatedShape
)
5351 m_pDoc
->InsertTab(0, "TestTab");
5353 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
5354 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
5355 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
5356 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
5358 m_pDoc
->InitDrawLayer();
5359 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
5360 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
5361 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
5362 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
5363 m_pDoc
->SetRowHeightRange(0, m_pDoc
->MaxRow(), 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5364 constexpr tools::Long TOLERANCE
= 30; //30 hmm
5365 for ( SCCOL nCol
= 0; nCol
< m_pDoc
->MaxCol(); ++nCol
)
5366 m_pDoc
->SetColWidth(nCol
, 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5369 tools::Rectangle
aRect( 4000, 5000, 10000, 7000 );
5371 tools::Rectangle
aRotRect( 6000, 3000, 8000, 9000 );
5372 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aRect
);
5373 pPage
->InsertObject(pObj
.get());
5374 Point
aRef1(pObj
->GetSnapRect().Center());
5375 Degree100 nAngle
= 9000_deg100
; //90 deg.
5376 double nSin
= 1.0; // sin(90 deg)
5377 double nCos
= 0.0; // cos(90 deg)
5378 pObj
->Rotate(aRef1
,nAngle
,nSin
,nCos
);
5380 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
5382 tools::Rectangle aSnap
= pObj
->GetSnapRect();
5383 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5384 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5385 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Left(), aSnap
.Left(), TOLERANCE
);
5386 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Top(), aSnap
.Top(), TOLERANCE
);
5388 ScDrawObjData aAnchor
;
5389 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pObj
.get() );
5390 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
5392 aAnchor
.maStart
= pData
->maStart
;
5393 aAnchor
.maEnd
= pData
->maEnd
;
5395 m_pDoc
->SetDrawPageSize(0);
5397 // increase row 5 by 2000 hmm
5398 m_pDoc
->SetRowHeight(5, 0, o3tl::toTwips(3000, o3tl::Length::mm100
));
5399 // increase col 6 by 1000 hmm
5400 m_pDoc
->SetColWidth(6, 0, o3tl::toTwips(2000, o3tl::Length::mm100
));
5402 aRotRect
.setWidth( aRotRect
.GetWidth() + 1000 );
5403 aRotRect
.setHeight( aRotRect
.GetHeight() + 2000 );
5405 m_pDoc
->SetDrawPageSize(0);
5407 aSnap
= pObj
->GetSnapRect();
5409 // ensure that width and height have been adjusted accordingly
5410 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5411 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5413 // ensure that anchor start and end addresses haven't changed
5414 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Row(), pData
->maStart
.Row() ); // start row 0
5415 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Col(), pData
->maStart
.Col() ); // start column 5
5416 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Row(), pData
->maEnd
.Row() ); // end row 3
5417 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Col(), pData
->maEnd
.Col() ); // end col 7
5419 m_pDoc
->DeleteTab(0);
5422 CPPUNIT_TEST_FIXTURE(Test
, testCellTextWidth
)
5424 m_pDoc
->InsertTab(0, "Test");
5426 ScAddress
aTopCell(0, 0, 0);
5429 std::unique_ptr
<ScColumnTextWidthIterator
> pIter(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5430 CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter
->hasCell());
5432 // Sheet only has one cell.
5433 m_pDoc
->SetString(0, 0, 0, "Only one cell");
5434 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5435 CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter
->hasCell());
5436 CPPUNIT_ASSERT_EQUAL(SCROW(0), pIter
->getPos());
5438 // Setting a text width here should commit it to the column.
5439 sal_uInt16 nTestVal
= 432;
5440 pIter
->setValue(nTestVal
);
5441 CPPUNIT_ASSERT_EQUAL(nTestVal
, m_pDoc
->GetTextWidth(aTopCell
));
5443 // Set values to row 2 through 6.
5444 for (SCROW i
= 2; i
<= 6; ++i
)
5445 m_pDoc
->SetString(0, i
, 0, "foo");
5447 // Set values to row 10 through 18.
5448 for (SCROW i
= 10; i
<= 18; ++i
)
5449 m_pDoc
->SetString(0, i
, 0, "foo");
5453 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5454 SCROW aRows
[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
5455 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5457 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5458 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5460 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5464 // Specify start and end rows (6 - 16)
5465 ScAddress aStart
= aTopCell
;
5467 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aStart
, 16));
5468 SCROW aRows
[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
5469 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5471 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5472 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5474 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5477 // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
5478 clearRange(m_pDoc
, ScRange(0, 3, 0, 0, 17, 0));
5481 // Full range again.
5482 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5483 SCROW aRows
[] = { 0, 2, 18 };
5484 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5486 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5487 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5489 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5492 // Delete row 2 which shifts all cells below row 2 upward. After this, we
5493 // should only have cells at rows 0 and 17.
5494 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), MAXTAB
, 2, 1);
5496 // Full range again.
5497 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5498 SCROW aRows
[] = { 0, 17 };
5499 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5501 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5502 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5504 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5507 m_pDoc
->DeleteTab(0);
5510 static bool checkEditTextIterator(sc::EditTextIterator
& rIter
, const char** pChecks
)
5512 const EditTextObject
* pText
= rIter
.first();
5513 const char* p
= *pChecks
;
5515 for (int i
= 0; i
< 100; ++i
) // cap it to 100 loops.
5518 // No more edit cells. The check string array should end too.
5519 return p
== nullptr;
5522 // More edit cell, but no more check string. Bad.
5525 if (pText
->GetParagraphCount() != 1)
5526 // For this test, we don't handle multi-paragraph text.
5529 if (pText
->GetText(0) != OUString::createFromAscii(p
))
5530 // Text differs from what's expected.
5533 pText
= rIter
.next();
5541 CPPUNIT_TEST_FIXTURE(Test
, testEditTextIterator
)
5543 m_pDoc
->InsertTab(0, "Test");
5546 // First, try with an empty sheet.
5547 sc::EditTextIterator
aIter(*m_pDoc
,0);
5548 const char* pChecks
[] = { nullptr };
5549 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5552 ScFieldEditEngine
& rEditEngine
= m_pDoc
->GetEditEngine();
5555 // Only set one edit cell.
5556 rEditEngine
.SetTextCurrentDefaults("A2");
5557 m_pDoc
->SetEditText(ScAddress(0,1,0), rEditEngine
.CreateTextObject());
5558 sc::EditTextIterator
aIter(*m_pDoc
,0);
5559 const char* pChecks
[] = { "A2", nullptr };
5560 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5564 // Add a series of edit cells.
5565 rEditEngine
.SetTextCurrentDefaults("A5");
5566 m_pDoc
->SetEditText(ScAddress(0,4,0), rEditEngine
.CreateTextObject());
5567 rEditEngine
.SetTextCurrentDefaults("A6");
5568 m_pDoc
->SetEditText(ScAddress(0,5,0), rEditEngine
.CreateTextObject());
5569 rEditEngine
.SetTextCurrentDefaults("A7");
5570 m_pDoc
->SetEditText(ScAddress(0,6,0), rEditEngine
.CreateTextObject());
5571 sc::EditTextIterator
aIter(*m_pDoc
,0);
5572 const char* pChecks
[] = { "A2", "A5", "A6", "A7", nullptr };
5573 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5577 // Add more edit cells to column C. Skip column B.
5578 rEditEngine
.SetTextCurrentDefaults("C1");
5579 m_pDoc
->SetEditText(ScAddress(2,0,0), rEditEngine
.CreateTextObject());
5580 rEditEngine
.SetTextCurrentDefaults("C3");
5581 m_pDoc
->SetEditText(ScAddress(2,2,0), rEditEngine
.CreateTextObject());
5582 rEditEngine
.SetTextCurrentDefaults("C4");
5583 m_pDoc
->SetEditText(ScAddress(2,3,0), rEditEngine
.CreateTextObject());
5584 sc::EditTextIterator
aIter(*m_pDoc
,0);
5585 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5586 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5590 // Add some numeric, string and formula cells. This shouldn't affect the outcome.
5591 m_pDoc
->SetString(ScAddress(0,99,0), "=ROW()");
5592 m_pDoc
->SetValue(ScAddress(1,3,0), 1.2);
5593 m_pDoc
->SetString(ScAddress(2,4,0), "Simple string");
5594 sc::EditTextIterator
aIter(*m_pDoc
,0);
5595 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5596 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5599 m_pDoc
->DeleteTab(0);
5602 CPPUNIT_TEST_FIXTURE(Test
, testImportStream
)
5604 sc::AutoCalcSwitch
aAC(*m_pDoc
, true); // turn on auto calc.
5605 sc::UndoSwitch
aUndo(*m_pDoc
, true); // enable undo.
5607 m_pDoc
->InsertTab(0, "Test");
5609 m_pDoc
->SetString(ScAddress(0,1,0), "=SUM(A1:C1)"); // A2
5611 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5613 // CSV import options.
5614 ScAsciiOptions aOpt
;
5615 aOpt
.SetFieldSeps(",");
5617 // Import values to A1:C1.
5618 ScImportExport
aObj(*m_pDoc
, ScAddress(0,0,0));
5619 aObj
.SetImportBroadcast(true);
5620 aObj
.SetExtOptions(aOpt
);
5621 aObj
.ImportString("1,2,3", SotClipboardFormatId::STRING
);
5623 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5624 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5625 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5627 // Formula value should have been updated.
5628 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5630 // Undo, and check the result.
5631 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5632 CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr
);
5635 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5636 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5637 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5639 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5641 // Redo, and check the result.
5644 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5645 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5646 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5648 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5652 m_pDoc
->DeleteTab(0);
5655 CPPUNIT_TEST_FIXTURE(Test
, testDeleteContents
)
5657 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
5658 sc::UndoSwitch
aUndoSwitch(*m_pDoc
, true); // enable undo.
5660 m_pDoc
->InsertTab(0, "Test");
5662 m_pDoc
->SetValue(ScAddress(3,1,0), 1.0);
5663 m_pDoc
->SetValue(ScAddress(3,2,0), 1.0);
5664 m_pDoc
->SetValue(ScAddress(3,3,0), 1.0);
5665 m_pDoc
->SetValue(ScAddress(3,4,0), 1.0);
5666 m_pDoc
->SetValue(ScAddress(3,5,0), 1.0);
5667 m_pDoc
->SetValue(ScAddress(3,6,0), 1.0);
5668 m_pDoc
->SetValue(ScAddress(3,7,0), 1.0);
5669 m_pDoc
->SetValue(ScAddress(3,8,0), 1.0);
5670 m_pDoc
->SetString(ScAddress(3,15,0), "=SUM(D2:D15)");
5672 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5675 ScRange
aRange(3,1,0,3,5,0);
5676 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5677 aMark
.SelectOneTable(0);
5678 aMark
.SetMarkArea(aRange
);
5680 ScDocumentUniquePtr
pUndoDoc(new ScDocument(SCDOCMODE_UNDO
));
5681 pUndoDoc
->InitUndo(*m_pDoc
, 0, 0);
5682 m_pDoc
->CopyToDocument(aRange
, InsertDeleteFlags::CONTENTS
, false, *pUndoDoc
, &aMark
);
5683 ScUndoDeleteContents
aUndo(m_xDocShell
.get(), aMark
, aRange
, std::move(pUndoDoc
), false, InsertDeleteFlags::CONTENTS
, true);
5685 clearRange(m_pDoc
, aRange
);
5686 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5689 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5692 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5694 m_pDoc
->DeleteTab(0);
5697 CPPUNIT_TEST_FIXTURE(Test
, testTransliterateText
)
5699 m_pDoc
->InsertTab(0, "Test");
5701 // Set texts to A1:A3.
5702 m_pDoc
->SetString(ScAddress(0,0,0), "Mike");
5703 m_pDoc
->SetString(ScAddress(0,1,0), "Noah");
5704 m_pDoc
->SetString(ScAddress(0,2,0), "Oscar");
5706 // Change them to uppercase.
5707 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5708 aMark
.SetMarkArea(ScRange(0,0,0,0,2,0));
5709 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5710 rFunc
.TransliterateText(
5711 aMark
, TransliterationFlags::LOWERCASE_UPPERCASE
, true);
5713 CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc
->GetString(ScAddress(0,0,0)));
5714 CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc
->GetString(ScAddress(0,1,0)));
5715 CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc
->GetString(ScAddress(0,2,0)));
5717 // Test the undo and redo.
5718 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5719 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
5722 CPPUNIT_ASSERT_EQUAL(OUString("Mike"), m_pDoc
->GetString(ScAddress(0,0,0)));
5723 CPPUNIT_ASSERT_EQUAL(OUString("Noah"), m_pDoc
->GetString(ScAddress(0,1,0)));
5724 CPPUNIT_ASSERT_EQUAL(OUString("Oscar"), m_pDoc
->GetString(ScAddress(0,2,0)));
5727 CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc
->GetString(ScAddress(0,0,0)));
5728 CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc
->GetString(ScAddress(0,1,0)));
5729 CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc
->GetString(ScAddress(0,2,0)));
5731 m_pDoc
->DeleteTab(0);
5734 CPPUNIT_TEST_FIXTURE(Test
, testFormulaToValue
)
5736 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5737 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5739 m_pDoc
->InsertTab(0, "Test");
5741 std::vector
<std::vector
<const char*>> aData
= {
5742 { "=1", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5743 { "=2", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5744 { "=3", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5745 { "=4", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5746 { "=5", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5747 { "=6", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5750 ScAddress
aPos(1,2,0); // B3
5751 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5752 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
5755 // Expected output table content. 0 = empty cell
5756 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5757 { "1", "2", "TRUE" },
5758 { "2", "4", "TRUE" },
5759 { "3", "6", "TRUE" },
5760 { "4", "8", "TRUE" },
5761 { "5", "10", "TRUE" },
5762 { "6", "12", "TRUE" },
5765 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5766 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5769 // Convert B5:C6 to static values, and check the result.
5770 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5771 ScRange
aConvRange(1,4,0,2,5,0); // B5:C6
5772 rFunc
.ConvertFormulaToValue(aConvRange
, false);
5775 // Expected output table content. 0 = empty cell
5776 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5777 { "1", "2", "TRUE" },
5778 { "2", "4", "TRUE" },
5779 { "3", "6", "FALSE" },
5780 { "4", "8", "FALSE" },
5781 { "5", "10", "TRUE" },
5782 { "6", "12", "TRUE" },
5785 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5786 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5789 // Make sure that B3:B4 and B7:B8 are formula cells.
5790 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5791 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5792 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5793 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5795 // Make sure that B5:C6 are numeric cells.
5796 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5797 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5798 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5799 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5801 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5802 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5803 CPPUNIT_ASSERT(pFC
);
5804 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5805 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5806 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5807 CPPUNIT_ASSERT(pFC
);
5808 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5809 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5812 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5813 CPPUNIT_ASSERT(pUndoMgr
);
5817 // Expected output table content. 0 = empty cell
5818 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5819 { "1", "2", "TRUE" },
5820 { "2", "4", "TRUE" },
5821 { "3", "6", "TRUE" },
5822 { "4", "8", "TRUE" },
5823 { "5", "10", "TRUE" },
5824 { "6", "12", "TRUE" },
5827 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "After undo");
5828 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5831 // B3:B8 should all be (ungrouped) formula cells.
5832 for (SCROW i
= 2; i
<= 7; ++i
)
5834 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,i
,0));
5835 CPPUNIT_ASSERT(pFC
);
5836 CPPUNIT_ASSERT(!pFC
->IsShared());
5839 // C3:C8 should be shared formula cells.
5840 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5841 CPPUNIT_ASSERT(pFC
);
5842 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5843 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedLength());
5848 // Expected output table content. 0 = empty cell
5849 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5850 { "1", "2", "TRUE" },
5851 { "2", "4", "TRUE" },
5852 { "3", "6", "FALSE" },
5853 { "4", "8", "FALSE" },
5854 { "5", "10", "TRUE" },
5855 { "6", "12", "TRUE" },
5858 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5859 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5862 // Make sure that B3:B4 and B7:B8 are formula cells.
5863 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5864 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5865 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5866 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5868 // Make sure that B5:C6 are numeric cells.
5869 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5870 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5871 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5872 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5874 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5875 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5876 CPPUNIT_ASSERT(pFC
);
5877 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5878 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5879 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5880 CPPUNIT_ASSERT(pFC
);
5881 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5882 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5884 // Undo again and make sure the recovered formulas in C5:C6 still track B5:B6.
5886 m_pDoc
->SetValue(ScAddress(1,4,0), 10);
5887 m_pDoc
->SetValue(ScAddress(1,5,0), 11);
5888 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
5889 CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc
->GetValue(ScAddress(2,5,0)));
5891 m_pDoc
->DeleteTab(0);
5894 CPPUNIT_TEST_FIXTURE(Test
, testFormulaToValue2
)
5896 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5897 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5899 m_pDoc
->InsertTab(0, "Test");
5901 std::vector
<std::vector
<const char*>> aData
= {
5902 { "=1", "=ISFORMULA(RC[-1])" },
5903 { "=2", "=ISFORMULA(RC[-1])" },
5904 { "3", "=ISFORMULA(RC[-1])" },
5905 { "=4", "=ISFORMULA(RC[-1])" },
5906 { "=5", "=ISFORMULA(RC[-1])" },
5909 // Insert data into B2:C6.
5910 ScAddress
aPos(1,1,0); // B2
5911 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5912 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
5915 // Expected output table content. 0 = empty cell
5916 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5924 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5925 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5928 // Convert B3:B5 to a value.
5929 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5930 ScRange
aConvRange(1,2,0,1,4,0); // B3:B5
5931 rFunc
.ConvertFormulaToValue(aConvRange
, false);
5934 // Expected output table content. 0 = empty cell
5935 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5943 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5944 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5948 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5949 CPPUNIT_ASSERT(pUndoMgr
);
5953 // Expected output table content. 0 = empty cell
5954 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5962 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5963 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5966 m_pDoc
->DeleteTab(0);
5969 CPPUNIT_TEST_FIXTURE(Test
, testColumnFindEditCells
)
5971 m_pDoc
->InsertTab(0, "Test");
5973 // Test the basics with real edit cells, using Column A.
5975 SCROW nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
5976 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
5977 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,0,0));
5978 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
5979 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,10,0));
5980 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
5982 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
5983 rEE
.SetTextCurrentDefaults("Test");
5984 m_pDoc
->SetEditText(ScAddress(0,0,0), rEE
.CreateTextObject());
5985 const EditTextObject
* pObj
= m_pDoc
->GetEditText(ScAddress(0,0,0));
5986 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell here.", pObj
);
5988 ScRange
aRange(0,0,0,0,0,0);
5989 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
5990 CPPUNIT_ASSERT_EQUAL_MESSAGE("There is an edit cell here.", SCROW(0), nResRow
);
5992 aRange
.aStart
.SetRow(1);
5993 aRange
.aEnd
.SetRow(1);
5994 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
5995 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
5997 aRange
.aStart
.SetRow(2);
5998 aRange
.aEnd
.SetRow(4);
5999 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6000 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6002 aRange
.aStart
.SetRow(0);
6003 aRange
.aEnd
.SetRow(m_pDoc
->MaxRow());
6004 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6005 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an edit cell in specified range.", SCROW(0), nResRow
);
6007 m_pDoc
->SetString(ScAddress(0,0,0), "Test");
6008 m_pDoc
->SetValue(ScAddress(0,2,0), 1.0);
6009 ScRefCellValue aCell
;
6010 aCell
.assign(*m_pDoc
, ScAddress(0,0,0));
6011 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a string cell.", CELLTYPE_STRING
, aCell
.getType());
6012 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
6013 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6014 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
6015 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a numeric cell.", CELLTYPE_VALUE
, aCell
.getType());
6016 aCell
.assign(*m_pDoc
, ScAddress(0,3,0));
6017 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6019 aRange
.aStart
.SetRow(1);
6020 aRange
.aEnd
.SetRow(1);
6021 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6022 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6024 // Test with non-edit cell but with ambiguous script type.
6026 m_pDoc
->SetString(ScAddress(1,11,0), "Some text");
6027 m_pDoc
->SetString(ScAddress(1,12,0), "Some text");
6028 m_pDoc
->SetString(ScAddress(1,13,0), "Other text");
6030 m_pDoc
->SetScriptType(ScAddress(1,11,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6031 m_pDoc
->SetScriptType(ScAddress(1,12,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6032 m_pDoc
->SetScriptType(ScAddress(1,13,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6034 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(1,11,0));
6035 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(11), nResRow
);
6036 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(1,12,0));
6037 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), nResRow
);
6039 for (SCROW i
= 0; i
<= 5; ++i
)
6040 m_pDoc
->SetString(ScAddress(2,i
,0), "Text");
6042 m_pDoc
->SetScriptType(ScAddress(2,5,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6044 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(2,1,0));
6045 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(-1), nResRow
);
6047 m_pDoc
->DeleteTab(0);
6051 CPPUNIT_TEST_FIXTURE(Test
, testSetFormula
)
6053 m_pDoc
->InsertTab(0, "Test");
6055 static struct aInputs
6059 const char* aFormula1
; // Represents the formula that is input to SetFormula function.
6060 const char* aFormula2
; // Represents the formula that is actually stored in the cell.
6061 formula::FormulaGrammar::Grammar
const eGram
;
6064 { 5 , 4 , "=SUM($D$2:$F$3)" ,"=SUM($D$2:$F$3)" , formula::FormulaGrammar::Grammar::GRAM_ENGLISH
},
6065 { 5 , 5 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE
},
6066 { 6 , 6 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE_XL_A1
},
6067 { 7 , 8 , "=[.A1]-[.$C2]+[.G$3]-[.$F$4]","=A1-$C2+G$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_ODFF
}
6070 for(size_t i
= 0; i
< SAL_N_ELEMENTS(aTest
); ++i
)
6072 m_pDoc
->SetFormula(ScAddress(aTest
[i
].nCol
, aTest
[i
].nRow
, 0), OUString::createFromAscii(aTest
[i
].aFormula1
), aTest
[i
].eGram
);
6073 OUString aBuffer
= m_pDoc
->GetFormula(aTest
[i
].nCol
, aTest
[i
].nRow
, 0);
6075 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to set formula", OUString::createFromAscii(aTest
[i
].aFormula2
), aBuffer
);
6078 m_pDoc
->DeleteTab(0);
6081 CPPUNIT_TEST_FIXTURE(Test
, testMultipleDataCellsInRange
)
6083 m_pDoc
->InsertTab(0, "Test");
6085 ScRange
aRange(1,2,0); // B3
6086 sc::MultiDataCellState aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6087 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::Empty
, aState
.meState
);
6089 // Set a numeric value to B3.
6090 m_pDoc
->SetValue(ScAddress(1,2,0), 1.0);
6091 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6092 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6093 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6094 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6096 // Set another numeric value to B4.
6097 m_pDoc
->SetValue(ScAddress(1,3,0), 2.0);
6098 aRange
.aEnd
.SetRow(3); // B3:B4
6099 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6100 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6101 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6102 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6104 // Set the query range to B4:B5. Now it should only report one cell, with
6105 // B4 being the first non-empty cell.
6106 aRange
.aStart
.SetRow(3);
6107 aRange
.aEnd
.SetRow(4);
6108 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6109 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6110 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6111 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6113 // Set the query range to A1:C3. The first non-empty cell should be B3.
6114 aRange
= ScRange(0,0,0,2,2,0);
6115 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6116 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6117 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6118 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6120 // Set string cells to D4 and F5, and query D3:F5. D4 should be the first
6122 m_pDoc
->SetString(ScAddress(3,3,0), "foo");
6123 m_pDoc
->SetString(ScAddress(5,4,0), "bar");
6124 aRange
= ScRange(3,2,0,5,4,0);
6125 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6126 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6127 CPPUNIT_ASSERT_EQUAL(SCCOL(3), aState
.mnCol1
);
6128 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6130 // TODO : add more test cases as needed.
6132 m_pDoc
->DeleteTab(0);
6135 CPPUNIT_TEST_FIXTURE(Test
, testFormulaWizardSubformula
)
6137 m_pDoc
->InsertTab(0, "Test");
6139 m_pDoc
->SetString(ScAddress(1,0,0), "=1"); // B1
6140 m_pDoc
->SetString(ScAddress(1,1,0), "=1/0"); // B2
6141 m_pDoc
->SetString(ScAddress(1,2,0), "=gibberish"); // B3
6143 ScSimpleFormulaCalculator
aFCell1( *m_pDoc
, ScAddress(0,0,0), "=B1:B3", true );
6144 FormulaError nErrCode
= aFCell1
.GetErrCode();
6145 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell1
.IsMatrix() );
6146 CPPUNIT_ASSERT_EQUAL( OUString("{1|#DIV/0!|#NAME?}"), aFCell1
.GetString().getString() );
6148 m_pDoc
->SetString(ScAddress(1,0,0), "=NA()"); // B1
6149 m_pDoc
->SetString(ScAddress(1,1,0), "2"); // B2
6150 m_pDoc
->SetString(ScAddress(1,2,0), "=1+2"); // B3
6151 ScSimpleFormulaCalculator
aFCell2( *m_pDoc
, ScAddress(0,0,0), "=B1:B3", true );
6152 nErrCode
= aFCell2
.GetErrCode();
6153 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell2
.IsMatrix() );
6154 CPPUNIT_ASSERT_EQUAL( OUString("{#N/A|2|3}"), aFCell2
.GetString().getString() );
6156 m_pDoc
->DeleteTab(0);
6159 CPPUNIT_TEST_FIXTURE(Test
, testDiagonalBorders
)
6161 m_pDoc
->InsertTab(0, "Diagonal");
6164 const editeng::SvxBorderLine
* pLine
;
6165 const ScPatternAttr
* pPat
;
6167 // diagonal down border
6168 ::editeng::SvxBorderLine
dDownBorderLine(nullptr, 1);
6169 SvxLineItem
dDownLineItem(ATTR_BORDER_TLBR
);
6170 dDownLineItem
.SetLine(&dDownBorderLine
);
6172 // set diagonal down border to cell(A1)
6173 m_pDoc
->ApplyAttr(0, 0, 0, dDownLineItem
);
6176 pPat
= m_pDoc
->GetPattern(aPos
);
6177 CPPUNIT_ASSERT(pPat
);
6179 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6180 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6182 // diagonal up border
6183 ::editeng::SvxBorderLine
dUpBorderLine(nullptr, 1);
6184 SvxLineItem
dUpLineItem(ATTR_BORDER_BLTR
);
6185 dUpLineItem
.SetLine(&dUpBorderLine
);
6187 // set diagonal up border to cell(A2)
6188 m_pDoc
->ApplyAttr(0, 1, 0, dUpLineItem
);
6191 pPat
= m_pDoc
->GetPattern(aPos
);
6192 CPPUNIT_ASSERT(pPat
);
6194 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6195 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6197 // diagonal down and up border in the same cell (A5)
6198 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6199 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6201 // test if both borders are applied successfully in the same cell (A5)
6203 pPat
= m_pDoc
->GetPattern(aPos
);
6204 CPPUNIT_ASSERT(pPat
);
6206 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6207 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6208 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6209 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6211 // test if both borders are removed successfully
6212 dDownLineItem
.SetLine(nullptr);
6213 dUpLineItem
.SetLine(nullptr);
6215 // SetLine(nullptr) should remove the lines from (A5)
6216 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6217 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6219 pPat
= m_pDoc
->GetPattern(aPos
);
6220 CPPUNIT_ASSERT(pPat
);
6222 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6223 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was not expected, but is found!", !pLine
);
6224 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6225 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was not expected, but is found!", !pLine
);
6227 m_pDoc
->DeleteTab(0);
6230 CPPUNIT_TEST_FIXTURE(Test
, testWholeDocBorders
)
6232 m_pDoc
->InsertTab(0, "Borders");
6234 // Set outside border to be on all sides, and inside borders to be only vertical.
6235 // This should result in edge borders of the spreadsheets being set, but internal
6236 // borders between cells should be only vertical, not horizontal.
6237 ::editeng::SvxBorderLine
line(nullptr, 50, SvxBorderLineStyle::SOLID
);
6238 SvxBoxItem
borderItem(ATTR_BORDER
);
6239 borderItem
.SetLine(&line
, SvxBoxItemLine::LEFT
);
6240 borderItem
.SetLine(&line
, SvxBoxItemLine::RIGHT
);
6241 borderItem
.SetLine(&line
, SvxBoxItemLine::TOP
);
6242 borderItem
.SetLine(&line
, SvxBoxItemLine::BOTTOM
);
6243 SvxBoxInfoItem
boxInfoItem(ATTR_BORDER
);
6244 boxInfoItem
.SetLine(&line
, SvxBoxInfoItemLine::VERT
);
6246 ScMarkData
mark( m_pDoc
->GetSheetLimits(), ScRange( 0, 0, 0, m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 ));
6247 m_pDoc
->ApplySelectionFrame( mark
, borderItem
, &boxInfoItem
);
6249 const ScPatternAttr
* attr
;
6250 attr
= m_pDoc
->GetPattern( 0, 0, 0 );
6251 CPPUNIT_ASSERT(attr
);
6252 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6253 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6254 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6255 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6257 attr
= m_pDoc
->GetPattern( 1, 0, 0 );
6258 CPPUNIT_ASSERT(attr
);
6259 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6260 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6261 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6262 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6264 attr
= m_pDoc
->GetPattern( 0, 1, 0 );
6265 CPPUNIT_ASSERT(attr
);
6266 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6267 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6268 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6269 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6271 attr
= m_pDoc
->GetPattern( 1, 1, 0 );
6272 CPPUNIT_ASSERT(attr
);
6273 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6274 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6275 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6276 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6278 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), 0, 0 );
6279 CPPUNIT_ASSERT(attr
);
6280 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6281 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6282 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6283 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6285 attr
= m_pDoc
->GetPattern( 0, m_pDoc
->MaxRow(), 0 );
6286 CPPUNIT_ASSERT(attr
);
6287 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6288 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6289 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6290 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6292 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 );
6293 CPPUNIT_ASSERT(attr
);
6294 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6295 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6296 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6297 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6299 m_pDoc
->DeleteTab(0);
6302 CPPUNIT_TEST_FIXTURE(Test
, testSetStringAndNote
)
6304 m_pDoc
->InsertTab(0, "Test");
6306 // We need a drawing layer in order to create caption objects.
6307 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
6310 ScAddress
aAdrA1 (0, 0, 0);
6311 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
6312 pNote
->SetText(aAdrA1
, "Hello world in A1");
6314 m_pDoc
->SetString(0, 0, 0, "");
6316 pNote
= m_pDoc
->GetNote(aAdrA1
);
6317 CPPUNIT_ASSERT(pNote
);
6319 m_pDoc
->DeleteTab(0);
6322 CPPUNIT_TEST_FIXTURE(Test
, testUndoDataAnchor
)
6324 m_pDoc
->InsertTab(0, "Tab1");
6325 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 1 sheets to begin with",
6326 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
6328 m_pDoc
->InitDrawLayer();
6329 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
6330 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
6331 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
6332 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
6334 // Insert an object.
6335 tools::Rectangle
aObjRect(2,1000,100,1100);
6336 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
6337 pPage
->InsertObject(pObj
.get());
6338 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
6341 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
6342 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6344 ScAddress aOldStart
= pData
->maStart
;
6345 ScAddress aOldEnd
= pData
->maEnd
;
6347 // Get non rotated anchor data
6348 ScDrawObjData
* pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6349 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6351 ScAddress aNOldStart
= pNData
->maStart
;
6352 ScAddress aNOldEnd
= pNData
->maEnd
;
6353 CPPUNIT_ASSERT_EQUAL(aOldStart
, aNOldStart
);
6354 CPPUNIT_ASSERT_EQUAL(aOldEnd
, aNOldEnd
);
6356 //pDrawLayer->BeginCalcUndo(false);
6357 // Insert a new row at row 3.
6358 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
6359 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6360 aMark
.SelectOneTable(0);
6361 rFunc
.InsertCells(ScRange( 0, aOldStart
.Row() - 1, 0, m_pDoc
->MaxCol(), aOldStart
.Row(), 0 ), &aMark
, INS_INSROWS_BEFORE
, true, true);
6363 pData
= ScDrawLayer::GetObjData(pObj
.get());
6364 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6366 ScAddress aNewStart
= pData
->maStart
;
6367 ScAddress aNewEnd
= pData
->maEnd
;
6369 // Get non rotated anchor data
6370 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6371 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6373 ScAddress aNNewStart
= pNData
->maStart
;
6374 ScAddress aNNewEnd
= pNData
->maEnd
;
6375 CPPUNIT_ASSERT_EQUAL(aNewStart
, aNNewStart
);
6376 CPPUNIT_ASSERT_EQUAL(aNewEnd
, aNNewEnd
);
6377 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart
!= aOldStart
);
6378 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewEnd
!= aOldEnd
);
6379 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewStart
!= aNOldStart
);
6380 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewEnd
!= aNOldEnd
);
6382 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6383 CPPUNIT_ASSERT(pUndoMgr
);
6387 ScAnchorType oldType
= ScDrawLayer::GetAnchorType(*pObj
);
6388 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to check state SCA_CELL.", SCA_CELL
, oldType
);
6391 pData
= ScDrawLayer::GetObjData(pObj
.get());
6392 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6394 // Get non rotated anchor data
6395 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6396 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6398 // Check if data has moved to new rows
6399 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aOldStart
);
6400 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aOldEnd
);
6402 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNOldStart
);
6403 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNOldEnd
);
6408 pData
= ScDrawLayer::GetObjData(pObj
.get());
6409 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6411 // Get non rotated anchor data
6412 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6413 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6415 // Check if data has moved to new rows
6416 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aNewStart
);
6417 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aNewEnd
);
6419 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNNewStart
);
6420 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNNewEnd
);
6422 m_pDoc
->DeleteTab(0);
6426 CPPUNIT_TEST_FIXTURE(Test
, testEmptyCalcDocDefaults
)
6428 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCellCount() );
6429 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetFormulaGroupCount() );
6430 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCodeCount() );
6431 CPPUNIT_ASSERT_EQUAL( int(CharCompressType::NONE
), static_cast<int>(m_pDoc
->GetAsianCompression()) );
6433 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasPrintRange() );
6434 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInVBAMode() );
6435 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasNotes() );
6436 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6438 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedFonts() );
6439 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedUsedFontsOnly() );
6440 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptLatin() );
6441 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptAsian() );
6442 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptComplex() );
6443 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedded() );
6445 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDocEditable() );
6446 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocProtected() );
6447 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocVisible() );
6448 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUserInteractionEnabled() );
6450 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasAnyCalcNotification() );
6451 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAutoCalcShellDisabled() );
6452 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsForcedFormulaPending() );
6453 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalculatingFormulaTree() );
6455 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipOrUndo() );
6456 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboard() );
6457 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsUndo() );
6458 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUndoEnabled() );
6459 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6460 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboardSource() );
6461 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInsertingFromOtherDoc() );
6462 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->PastingDrawFromOtherDoc() );
6464 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAdjustHeightLocked() );
6465 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsExecuteLinkEnabled() );
6466 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChangeReadOnlyEnabled() );
6468 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IdleCalcTextWidth() );
6469 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsIdleEnabled() );
6470 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDetectiveDirty() );
6471 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasLinkFormulaNeedingCheck() );
6472 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChartListenerCollectionNeedsUpdate() );
6474 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasRangeOverflow() );
6475 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsImportingXML() );
6476 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalcingAfterLoad() );
6477 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetNoListening() );
6479 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianCompression() );
6480 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetAsianKerning() );
6481 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianKerning() );
6483 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreter() );
6484 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreterTableOp() );
6485 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInDtorClear() );
6486 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsExpandRefs() );
6487 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInLinkUpdate() );
6489 SCTAB tab
= m_pDoc
->GetVisibleTab();
6491 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsVisible(tab
) );
6492 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDefaultTabBgColor(tab
) );
6493 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasTable(tab
) );
6495 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsActiveScenario(tab
) );
6496 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasCalcNotification(tab
) );
6497 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasManualBreaks(tab
) );
6500 void Test::checkPrecisionAsShown( OUString
& rCode
, double fValue
, double fExpectedRoundVal
)
6502 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
6503 sal_uInt32 nFormat
= pFormatter
->GetEntryKey( rCode
);
6504 if ( nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
6506 sal_Int32 nCheckPos
= 0;
6507 SvNumFormatType nType
;
6508 pFormatter
->PutEntry( rCode
, nCheckPos
, nType
, nFormat
);
6509 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), nCheckPos
);
6511 double fRoundValue
= m_pDoc
->RoundValueAsShown( fValue
, nFormat
);
6512 OString aMessage
= "Format \"" +
6513 OUStringToOString( rCode
, RTL_TEXTENCODING_ASCII_US
) +
6514 "\" is not correctly rounded";
6515 CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage
.getStr(), fExpectedRoundVal
, fRoundValue
);
6518 CPPUNIT_TEST_FIXTURE(Test
, testPrecisionAsShown
)
6520 m_pDoc
->InsertTab(0, "Test");
6522 // Turn on "precision as shown" option.
6523 setCalcAsShown( m_pDoc
, true);
6526 double fValue
, fExpectedRoundVal
;
6527 { // decimal rounding
6530 fExpectedRoundVal
= 0.33;
6531 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6532 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6534 fExpectedRoundVal
= 10.0;
6535 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6536 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6538 { // thousand rounding tdf#106253
6540 fValue
= 4.0e9
/ 7.0;
6541 fExpectedRoundVal
= 571e6
;
6542 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6543 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6544 aCode
= "\"k\"[$$-409]* #,;[RED]-\"k\"[$$-409]* #,";
6545 fValue
= 4.0e8
/ 7.0;
6546 fExpectedRoundVal
= 57.143e6
;
6547 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6548 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6550 { // percent rounding
6553 fExpectedRoundVal
= 0.5714;
6554 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6555 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6556 fValue
= 40.0 / 7.0;
6557 fExpectedRoundVal
= 5.7143;
6558 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6559 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6561 { // scientific rounding
6563 fValue
= 400000.0 / 7.0;
6564 fExpectedRoundVal
= 57100.0;
6565 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6566 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6567 fValue
= 4.0 / 70000.0;
6568 fExpectedRoundVal
= 5.71e-5;
6569 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6570 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6571 // engineering rounding tdf#106252
6572 aCode
= "##0.000E0";
6573 fValue
= 400000.0 / 7.0;
6574 fExpectedRoundVal
= 57.143e3
;
6575 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6576 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6577 fValue
= 4000000.0 / 7.0;
6578 fExpectedRoundVal
= 571.429e3
;
6579 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6580 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6581 fValue
= 40000000.0 / 7.0;
6582 fExpectedRoundVal
= 5.714e6
;
6583 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6584 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6585 fValue
= 4.0 / 70000.0;
6586 fExpectedRoundVal
= 57.143e-6;
6587 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6588 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6589 fValue
= 4.0 / 7000.0;
6590 fExpectedRoundVal
= 571.429e-6;
6591 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6592 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6593 fValue
= 4.0 / 700.0;
6594 fExpectedRoundVal
= 5.714e-3;
6595 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6596 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6597 aCode
= "##?0.0#E0";
6598 fValue
= 400000.0 / 7.0;
6599 fExpectedRoundVal
= 5.71e4
;
6600 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6601 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6602 fValue
= 4000000.0 / 7.0;
6603 fExpectedRoundVal
= 57.14e4
;
6604 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6605 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6606 fValue
= 40000000.0 / 7.0;
6607 fExpectedRoundVal
= 571.43e4
;
6608 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6609 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6610 fValue
= 400000000.0 / 7.0;
6611 fExpectedRoundVal
= 5714.29e4
;
6612 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6613 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6614 fValue
= 4.0 / 70000.0;
6615 fExpectedRoundVal
= 5714.29e-8;
6616 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6617 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6618 fValue
= 4.0 / 7000.0;
6619 fExpectedRoundVal
= 5.71e-4;
6620 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6621 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6622 fValue
= 4.0 / 700.0;
6623 fExpectedRoundVal
= 57.14e-4;
6624 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6625 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6626 fValue
= 4.0 / 70.0;
6627 fExpectedRoundVal
= 571.43e-4;
6628 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6629 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6631 { // fraction rounding tdf#105657
6634 fExpectedRoundVal
= 1.0/3.0;
6635 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6636 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6641 fExpectedRoundVal
= 0.35;
6642 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6643 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6645 { // several sub-formats tdf#106052
6646 aCode
= "0.00;-0.000";
6648 fExpectedRoundVal
= 0.33;
6649 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6651 fExpectedRoundVal
= -0.333;
6652 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6655 setCalcAsShown( m_pDoc
, false);
6656 m_pDoc
->DeleteTab(0);
6659 CPPUNIT_TEST_FIXTURE(Test
, testProtectedSheetEditByRow
)
6661 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6662 m_pDoc
->InsertTab(0, "Protected");
6665 // Remove protected flags from rows 2-5.
6666 ScPatternAttr
aAttr(m_pDoc
->GetPool());
6667 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6668 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 4, 0, aAttr
);
6670 // Protect the sheet without any options.
6671 ScTableProtection aProtect
;
6672 aProtect
.setProtected(true);
6673 m_pDoc
->SetTabProtection(0, &aProtect
);
6675 // Try to delete row 3. It should fail.
6676 ScRange
aRow3(0,2,0,m_pDoc
->MaxCol(),2,0);
6677 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6678 aMark
.SelectOneTable(0);
6679 bool bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6680 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should fail.", !bDeleted
);
6682 // Protect the sheet but allow row deletion.
6683 aProtect
.setOption(ScTableProtection::DELETE_ROWS
, true);
6684 m_pDoc
->SetTabProtection(0, &aProtect
);
6686 // Now we should be able to delete row 3.
6687 bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6688 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should succeed.", bDeleted
);
6690 // But, row deletion should still fail on a protected row.
6691 ScRange
aRow10(0,9,0,m_pDoc
->MaxCol(),9,0);
6692 bDeleted
= rDocFunc
.DeleteCells(aRow10
, &aMark
, DelCellCmd::Rows
, true);
6693 CPPUNIT_ASSERT_MESSAGE("deletion of row 10 should not be allowed.", !bDeleted
);
6695 // Try inserting a new row. It should fail.
6696 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6697 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6699 // Allow row insertions.
6700 aProtect
.setOption(ScTableProtection::INSERT_ROWS
, true);
6701 m_pDoc
->SetTabProtection(0, &aProtect
);
6703 bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6704 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should succeed.", bInserted
);
6706 // Row insertion is allowed even when the rows above and below have protected flags set.
6707 bInserted
= rDocFunc
.InsertCells(aRow10
, &aMark
, INS_INSROWS_AFTER
, true, true);
6708 CPPUNIT_ASSERT_MESSAGE("row insertion at row 10 should succeed.", bInserted
);
6711 m_pDoc
->InsertTab(1, "Matrix"); // This sheet is unprotected.
6714 // Insert matrix into B2:C3.
6715 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6716 aMark
.SelectOneTable(1);
6717 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, "={1;2|3;4}");
6719 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6720 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6721 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6722 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6724 // Try to insert a row at row 3. It should fail because of matrix's presence.
6726 ScRange
aRow3(0,2,1,m_pDoc
->MaxCol(),2,1);
6727 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_BEFORE
, true, true);
6728 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6731 m_pDoc
->DeleteTab(1);
6732 m_pDoc
->DeleteTab(0);
6735 CPPUNIT_TEST_FIXTURE(Test
, testProtectedSheetEditByColumn
)
6737 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6738 m_pDoc
->InsertTab(0, "Protected");
6741 // Remove protected flags from columns B to E.
6742 ScPatternAttr
aAttr(m_pDoc
->GetPool());
6743 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6744 m_pDoc
->ApplyPatternAreaTab(1, 0, 4, m_pDoc
->MaxRow(), 0, aAttr
);
6746 // Protect the sheet without any options.
6747 ScTableProtection aProtect
;
6748 aProtect
.setProtected(true);
6749 m_pDoc
->SetTabProtection(0, &aProtect
);
6751 // Try to delete column C. It should fail.
6752 ScRange
aCol3(2,0,0,2,m_pDoc
->MaxRow(),0);
6753 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6754 aMark
.SelectOneTable(0);
6755 bool bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6756 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should fail.", !bDeleted
);
6758 // Protect the sheet but allow column deletion.
6759 aProtect
.setOption(ScTableProtection::DELETE_COLUMNS
, true);
6760 m_pDoc
->SetTabProtection(0, &aProtect
);
6762 // Now we should be able to delete column C.
6763 bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6764 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should succeed.", bDeleted
);
6766 // But, column deletion should still fail on a protected column.
6767 ScRange
aCol10(9,0,0,9,m_pDoc
->MaxRow(),0);
6768 bDeleted
= rDocFunc
.DeleteCells(aCol10
, &aMark
, DelCellCmd::Cols
, true);
6769 CPPUNIT_ASSERT_MESSAGE("deletion of column 10 should not be allowed.", !bDeleted
);
6771 // Try inserting a new column. It should fail.
6772 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6773 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should fail.", !bInserted
);
6775 // Allow column insertions.
6776 aProtect
.setOption(ScTableProtection::INSERT_COLUMNS
, true);
6777 m_pDoc
->SetTabProtection(0, &aProtect
);
6779 bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6780 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should succeed.", bInserted
);
6782 // Column insertion is allowed even when the columns above and below have protected flags set.
6783 bInserted
= rDocFunc
.InsertCells(aCol10
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6784 CPPUNIT_ASSERT_MESSAGE("column insertion at column 10 should succeed.", bInserted
);
6787 m_pDoc
->InsertTab(1, "Matrix"); // This sheet is unprotected.
6790 // Insert matrix into B2:C3.
6791 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6792 aMark
.SelectOneTable(1);
6793 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, "={1;2|3;4}");
6795 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6796 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6797 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6798 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6800 // Try to insert a column at column C. It should fail because of matrix's presence.
6802 ScRange
aCol3(2,0,1,2,m_pDoc
->MaxRow(),1);
6803 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_BEFORE
, true, true);
6804 CPPUNIT_ASSERT_MESSAGE("column insertion at column C should fail.", !bInserted
);
6807 m_pDoc
->DeleteTab(1);
6808 m_pDoc
->DeleteTab(0);
6811 CPPUNIT_TEST_FIXTURE(Test
, testInsertColumnsWithFormulaCells
)
6813 m_pDoc
->InsertTab(0, "Tab1");
6815 std::set
<SCCOL
> aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6816 CPPUNIT_ASSERT_MESSAGE("empty sheet should contain no formula cells.", aCols
.empty());
6818 auto equals
= [](const std::set
<SCCOL
>& left
, const std::set
<SCCOL
>& right
)
6820 return left
== right
;
6823 // insert formula cells in columns 2, 4 and 6.
6824 m_pDoc
->SetFormula(ScAddress(2, 2, 0), "=1", m_pDoc
->GetGrammar());
6825 m_pDoc
->SetFormula(ScAddress(4, 2, 0), "=1", m_pDoc
->GetGrammar());
6826 m_pDoc
->SetFormula(ScAddress(6, 2, 0), "=1", m_pDoc
->GetGrammar());
6828 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6830 std::set
<SCCOL
> aExpected
= { 2, 4, 6 };
6831 CPPUNIT_ASSERT_MESSAGE("Columns 2, 4 and 6 should contain formula cells.", equals(aExpected
, aCols
));
6833 // Insert 2 columns at column A to shift everything to right by 2.
6834 m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 0, 2);
6836 aExpected
= { 4, 6, 8 };
6837 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6838 CPPUNIT_ASSERT_MESSAGE("Columns 4, 6 and 8 should contain formula cells.", equals(aExpected
, aCols
));
6842 m_pDoc
->CheckIntegrity(0);
6844 catch (const std::exception
& e
)
6846 std::ostringstream os
;
6847 os
<< "document integrity check failed: " << e
.what();
6848 CPPUNIT_FAIL(os
.str());
6851 m_pDoc
->DeleteTab(0);
6854 CPPUNIT_TEST_FIXTURE(Test
, testDocumentModelAccessor_getDocumentCurrencies
)
6856 m_pDoc
->InsertTab(0, "Sheet1");
6858 // Check document currencies - expect 0
6859 auto pAccessor
= m_xDocShell
->GetDocumentModelAccessor();
6860 CPPUNIT_ASSERT(pAccessor
);
6861 CPPUNIT_ASSERT_EQUAL(size_t(0), pAccessor
->getDocumentCurrencies().size());
6863 // Set a currency to a cell
6865 m_pDoc
->SetValue(ScAddress(0, 0, 0), 2.0);
6867 OUString aCode
= u
"#.##0,00[$€-424]"_ustr
;
6869 sal_Int32 nCheckPos
;
6870 SvNumFormatType eType
;
6873 m_pDoc
->GetFormatTable()->PutEntry(aCode
, nCheckPos
, eType
, nFormat
, LANGUAGE_SLOVENIAN
);
6874 CPPUNIT_ASSERT_EQUAL(SvNumFormatType::CURRENCY
, eType
);
6876 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
6877 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
6878 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
6879 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
); // A1.
6881 CPPUNIT_ASSERT_EQUAL(u
"2,00€"_ustr
, m_pDoc
->GetString(ScAddress(0, 0, 0)));
6884 // Check document currencies again
6885 auto aCurrencyIDs
= pAccessor
->getDocumentCurrencies();
6886 CPPUNIT_ASSERT_EQUAL(size_t(1), aCurrencyIDs
.size());
6888 CPPUNIT_ASSERT_EQUAL(LANGUAGE_SLOVENIAN
, aCurrencyIDs
[0].eLanguage
);
6889 CPPUNIT_ASSERT_EQUAL(u
"-424"_ustr
, aCurrencyIDs
[0].aExtension
);
6890 CPPUNIT_ASSERT_EQUAL(u
"€"_ustr
, aCurrencyIDs
[0].aSymbol
);
6892 // Set the same currency to 2 more cells
6894 m_pDoc
->SetValue(ScAddress(1, 1, 0), 5.0);
6895 m_pDoc
->SetValue(ScAddress(2, 2, 0), 7.0);
6897 OUString aCode
= u
"#.##0,00[$€-424]"_ustr
;
6899 sal_Int32 nCheckPos
;
6900 SvNumFormatType eType
;
6903 m_pDoc
->GetFormatTable()->PutEntry(aCode
, nCheckPos
, eType
, nFormat
, LANGUAGE_SLOVENIAN
);
6904 CPPUNIT_ASSERT_EQUAL(SvNumFormatType::CURRENCY
, eType
);
6906 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
6907 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
6908 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
6909 m_pDoc
->ApplyPattern(1, 1, 0, aNewAttrs
); // B2.
6910 m_pDoc
->ApplyPattern(2, 2, 0, aNewAttrs
); // C3.
6912 CPPUNIT_ASSERT_EQUAL(u
"5,00€"_ustr
, m_pDoc
->GetString(ScAddress(1, 1, 0)));
6913 CPPUNIT_ASSERT_EQUAL(u
"7,00€"_ustr
, m_pDoc
->GetString(ScAddress(2, 2, 0)));
6916 // Check document currencies again - should be 1 entry only
6917 aCurrencyIDs
= pAccessor
->getDocumentCurrencies();
6918 CPPUNIT_ASSERT_EQUAL(size_t(1), aCurrencyIDs
.size());
6920 CPPUNIT_ASSERT_EQUAL(LANGUAGE_SLOVENIAN
, aCurrencyIDs
[0].eLanguage
);
6921 CPPUNIT_ASSERT_EQUAL(u
"-424"_ustr
, aCurrencyIDs
[0].aExtension
);
6922 CPPUNIT_ASSERT_EQUAL(u
"€"_ustr
, aCurrencyIDs
[0].aSymbol
);
6926 CPPUNIT_PLUGIN_IMPLEMENT();
6928 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */