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 <globalnames.hxx>
42 #include <columnspanset.hxx>
44 #include <editable.hxx>
45 #include <tabprotection.hxx>
46 #include <undomanager.hxx>
48 #include <formula/IFunctionDescription.hxx>
50 #include <editeng/borderline.hxx>
51 #include <editeng/brushitem.hxx>
52 #include <editeng/eeitem.hxx>
53 #include <editeng/wghtitem.hxx>
54 #include <editeng/postitem.hxx>
55 #include <editeng/lineitem.hxx>
57 #include <o3tl/nonstaticstring.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(u
"A"_ustr
, u
"B"_ustr
);
111 CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes
!= 0);
114 CPPUNIT_TEST_FIXTURE(Test
, testSharedStringPool
)
116 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
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), o3tl::nonStaticString(u
"Andy")); // A1
124 m_pDoc
->SetString(ScAddress(0,1,0), o3tl::nonStaticString(u
"Andy")); // A2
125 m_pDoc
->SetString(ScAddress(0,2,0), o3tl::nonStaticString(u
"Bruce")); // A3
126 m_pDoc
->SetString(ScAddress(0,3,0), o3tl::nonStaticString(u
"andy")); // A4
127 m_pDoc
->SetString(ScAddress(0,4,0), o3tl::nonStaticString(u
"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 // [-loplugin:ostr]
179 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
180 rEE
.SetTextCurrentDefaults(u
"Andy and Bruce"_ustr
);
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(u
"ANDY and BRUCE"_ustr
);
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, u
"Test"_ustr
);
264 m_pDoc
->SetString(ScAddress(0,0,0), u
"Header"_ustr
);
265 m_pDoc
->SetString(ScAddress(0,1,0), u
"A1"_ustr
);
266 m_pDoc
->SetString(ScAddress(0,2,0), u
"A2"_ustr
);
267 m_pDoc
->SetString(ScAddress(0,3,0), u
"A3"_ustr
);
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, u
"foo"_ustr
);
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, u
"foo"_ustr
));
358 m_pDoc
->SetString(0, 0, 0, u
"'10.5"_ustr
);
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, u
"'apple'"_ustr
);
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, u
"000123"_ustr
, &aParam
);
371 test
= m_pDoc
->GetString(0, 0, 0);
372 CPPUNIT_ASSERT_EQUAL_MESSAGE("Text content should have been treated as string, not number.", u
"000123"_ustr
, 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, u
"foo"_ustr
));
382 m_pDoc
->SetString(0, 0, 0, u
"'10.5"_ustr
);
383 m_pDoc
->SetString(0, m_pDoc
->MaxRow()-5, 0, u
"42.0"_ustr
);
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
, u
"FirstPrintRange"_ustr
));
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
, u
"SecondPrintRange"_ustr
));
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, u
"Sheet 1"_ustr
));
461 CPPUNIT_ASSERT(m_pDoc
->InsertTab(1, u
"Sheet 2"_ustr
));
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(u
"='Sheet 2'!R1C1"_ustr
, 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, u
"Test"_ustr
));
486 m_pDoc
->SetString(ScAddress(0,0,0), u
"=(1;2)"_ustr
);
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(u
"=(1;2)"_ustr
, aFormula
);
494 m_pDoc
->DeleteTab(0);
497 CPPUNIT_TEST_FIXTURE(Test
, testTdf114406
)
499 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, u
"Test"_ustr
));
500 m_pDoc
->SetString(ScAddress(0,0,0), u
"5"_ustr
);
501 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1/100%"_ustr
);
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(u
"=A1/100%"_ustr
, 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, u
"Test"_ustr
));
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, u
"Test"_ustr
));
533 m_pDoc
->SetString(ScAddress(0,0,0), u
"--1"_ustr
);
534 m_pDoc
->SetString(ScAddress(0,1,0), u
"---1"_ustr
);
535 m_pDoc
->SetString(ScAddress(0,2,0), u
"+-1"_ustr
);
536 m_pDoc
->SetString(ScAddress(0,3,0), u
"+--1"_ustr
);
538 // Without the fix in place, this test would have failed with
541 CPPUNIT_ASSERT_EQUAL(u
"--1"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
542 CPPUNIT_ASSERT_EQUAL(u
"---1"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
543 CPPUNIT_ASSERT_EQUAL(u
"+-1"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
544 CPPUNIT_ASSERT_EQUAL(u
"+--1"_ustr
, 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, u
"Test"_ustr
));
553 m_pDoc
->SetString(ScAddress(0,0,0), u
"1:60"_ustr
);
554 m_pDoc
->SetString(ScAddress(0,1,0), u
"1:123"_ustr
);
555 m_pDoc
->SetString(ScAddress(0,2,0), u
"1:1:123"_ustr
);
556 m_pDoc
->SetString(ScAddress(0,3,0), u
"0:123"_ustr
);
557 m_pDoc
->SetString(ScAddress(0,4,0), u
"0:0:123"_ustr
);
558 m_pDoc
->SetString(ScAddress(0,5,0), u
"0:123:59"_ustr
);
560 // These are not valid duration inputs
561 CPPUNIT_ASSERT_EQUAL(u
"1:60"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
562 CPPUNIT_ASSERT_EQUAL(u
"1:123"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
563 CPPUNIT_ASSERT_EQUAL(u
"1:1:123"_ustr
, 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(u
"02:03:00 AM"_ustr
, m_pDoc
->GetString(ScAddress(0,3,0)));
570 CPPUNIT_ASSERT_EQUAL(u
"12:02:03 AM"_ustr
, m_pDoc
->GetString(ScAddress(0,4,0)));
571 CPPUNIT_ASSERT_EQUAL(u
"02:03:59 AM"_ustr
, 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, u
"Sheet1"_ustr
);
580 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
581 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
582 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
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), u
"Test"_ustr
);
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), u
"=A1"_ustr
);
596 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
597 m_pDoc
->SetString(ScAddress(3,1,1), u
"=A2"_ustr
);
598 m_pDoc
->SetString(ScAddress(3,2,1), u
"=A3"_ustr
);
599 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
600 m_pDoc
->SetString(ScAddress(3,3,1), u
"=A5"_ustr
);
601 m_pDoc
->SetString(ScAddress(3,4,1), u
"=A6"_ustr
);
602 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetFormulaGroupCount());
603 m_pDoc
->SetString(ScAddress(3,1,1), u
"=A3"_ustr
);
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, u
"Sheet1"_ustr
);
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, u
"Test"_ustr
);
655 m_pDoc
->SetString(ScAddress(0,5,0), u
"Andy"_ustr
);
656 m_pDoc
->SetString(ScAddress(0,6,0), u
"Bruce"_ustr
);
657 m_pDoc
->SetString(ScAddress(0,7,0), u
"Charlie"_ustr
);
658 m_pDoc
->SetString(ScAddress(0,10,0), u
"Andy"_ustr
);
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(u
"Andy"_ustr
, it
->GetString());
668 CPPUNIT_ASSERT_EQUAL(u
"Bruce"_ustr
, it
->GetString());
670 CPPUNIT_ASSERT_EQUAL(u
"Charlie"_ustr
, 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(u
"Andy"_ustr
, it
->GetString());
682 CPPUNIT_ASSERT_EQUAL(u
"Bruce"_ustr
, it
->GetString());
684 CPPUNIT_ASSERT_EQUAL(u
"Charlie"_ustr
, 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, u
"Test"_ustr
);
699 // Insert values into B2:B4.
700 m_pDoc
->SetString(ScAddress(1,1,0), u
"=1"_ustr
); // 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), u
"A"_ustr
);
706 m_pDoc
->SetString(ScAddress(1,5,0), u
"B"_ustr
);
707 m_pDoc
->SetString(ScAddress(1,6,0), u
"=\"C\""_ustr
); // formula
708 m_pDoc
->SetString(ScAddress(1,7,0), u
"D"_ustr
);
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(u
"Rich Text"_ustr
);
718 m_pDoc
->SetEditText(ScAddress(3,4,0), rEE
.CreateTextObject());
720 // Insert Another string into D6.
721 m_pDoc
->SetString(ScAddress(3,5,0), u
"E"_ustr
);
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, u
"Test2"_ustr
);
834 m_pDoc
->InsertTab(2, u
"Test3"_ustr
);
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, u
"Test"_ustr
);
868 // Insert cells to A1, A5, B2 and C3.
869 m_pDoc
->SetString(ScAddress(0,0,0), u
"California"_ustr
);
870 m_pDoc
->SetValue(ScAddress(0,4,0), 1.2);
871 m_pDoc
->SetEditText(ScAddress(1,1,0), u
"Boston"_ustr
);
872 m_pDoc
->SetFormula(ScAddress(2,2,0), u
"=SUM(1,2,3)"_ustr
, 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, u
"src"_ustr
));
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, u
"Header"_ustr
);
924 m_pDoc
->SetString(0, 1, 0, u
"1"_ustr
);
925 m_pDoc
->SetString(0, 2, 0, u
"2"_ustr
);
926 m_pDoc
->SetString(0, 3, 0, u
"3"_ustr
);
927 m_pDoc
->SetString(0, 4, 0, u
"=4/2"_ustr
);
931 ScAddress
aAdrA1 (0, 0, 0); // numerical cell content
932 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
933 pNote
->SetText(aAdrA1
, u
"Hello world in A1"_ustr
);
935 // Copy statically to another document.
937 ScDocShellRef xDocSh2
;
938 getNewDocShell(xDocSh2
);
939 ScDocument
* pDestDoc
= &xDocSh2
->GetDocument();
940 pDestDoc
->InsertTab(0, u
"src"_ustr
);
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, u
"test"_ustr
);
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, u
"Test"_ustr
);
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, u
"Test"_ustr
);
1190 // Set the background color of B2:C3,D2,E3,C4:D4,B5:D5 to blue
1191 ScPatternAttr
aCellBackColor(m_pDoc
->getCellAttributeHelper());
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 (pAttr
->isDefault())
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, u
"Tab1"_ustr
);
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
->getCellAttributeHelper());
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, u
"Tab1"_ustr
);
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
->getCellAttributeHelper());
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
->getCellAttributeHelper().getDefaultCellAttribute()); //GetDefPattern();
1305 CPPUNIT_ASSERT(!ScPatternAttr::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, u
"Tab1"_ustr
);
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, u
"foo"_ustr
));
1449 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calculation.
1450 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1"_ustr
); // 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), u
"=A1"_ustr
); // 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), u
"=A1"_ustr
);
1523 m_pDoc
->SetString(ScAddress(1,1,0), u
"=A2"_ustr
);
1524 m_pDoc
->SetString(ScAddress(1,2,0), u
"=A3"_ustr
);
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), u
"=RC[-1]"_ustr
);
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), u
"=A1"_ustr
);
1606 m_pDoc
->SetString(ScAddress(2,0,0), u
"=B1"_ustr
);
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, u
"foo"_ustr
));
1644 // First, the normal case, with no missing parameters.
1645 m_pDoc
->SetString(0, 0, 0, u
"=AVERAGE(1;2;3)"_ustr
);
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, u
"=AVERAGE(1;;;)"_ustr
);
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, u
"=\"\"+3"_ustr
); // empty string
1659 m_pDoc
->SetString(0, 1, 0, u
"=\" \"+3"_ustr
); // only blank
1660 m_pDoc
->SetString(0, 2, 0, u
"=\" 4 \"+3"_ustr
); // number in blanks
1661 m_pDoc
->SetString(0, 3, 0, u
"=\" x \"+3"_ustr
); // non-numeric
1662 m_pDoc
->SetString(0, 4, 0, u
"=\"4.4\"+3"_ustr
); // 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", u
"#VALUE!"_ustr
, 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", u
"#VALUE!"_ustr
, aVal
);
1690 aVal
= m_pDoc
->GetString( 0, 1, 0);
1691 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, 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", u
"#VALUE!"_ustr
, 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", u
"#VALUE!"_ustr
, aVal
);
1712 aVal
= m_pDoc
->GetString( 0, 4, 0);
1713 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, 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", u
"#VALUE!"_ustr
, aVal
);
1722 aVal
= m_pDoc
->GetString( 0, 1, 0);
1723 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, 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", u
"#VALUE!"_ustr
, aVal
);
1728 aVal
= m_pDoc
->GetString( 0, 4, 0);
1729 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, 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", u
"#VALUE!"_ustr
, aVal
);
1754 aVal
= m_pDoc
->GetString( 0, 1, 0);
1755 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1756 aVal
= m_pDoc
->GetString( 0, 2, 0);
1757 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1758 aVal
= m_pDoc
->GetString( 0, 3, 0);
1759 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1760 aVal
= m_pDoc
->GetString( 0, 4, 0);
1761 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, 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, u
"Sheet1"_ustr
));
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, u
"=A1/Divisor"_ustr
);
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
, u
"local1"_ustr
, ScAddress(0,0,0));
1817 ScRangeData
* pLocal2
= new ScRangeData( *m_pDoc
, u
"local2"_ustr
, u
"$Sheet1.$A$1"_ustr
);
1818 ScRangeData
* pLocal3
= new ScRangeData( *m_pDoc
, u
"local3"_ustr
, u
"Sheet1.$A$1"_ustr
);
1819 ScRangeData
* pLocal4
= new ScRangeData( *m_pDoc
, u
"local4"_ustr
, u
"$A$1"_ustr
); // 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, u
"Sheet2"_ustr
));
1829 // Use other-sheet-local name of Sheet1 on Sheet2.
1830 ScAddress
aPos(1,0,1);
1831 OUString
aFormula(u
"=Sheet1.local1+Sheet1.local2+Sheet1.local3+Sheet1.local4"_ustr
);
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, u
"Test"_ustr
);
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", u
"Test"_ustr
, 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(u
"Test"_ustr
), 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(u
"Test"_ustr
), 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(u
"A"_ustr
), 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(u
"B"_ustr
), 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, u
"foo"_ustr
);
2138 // Insert the source values in A1:A2.
2139 m_pDoc
->SetString(0, 0, 0, u
"=1/0"_ustr
);
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
, u
"=A1:A2>0"_ustr
);
2148 CPPUNIT_ASSERT_EQUAL(u
"#DIV/0!"_ustr
, m_pDoc
->GetString(0,0,0));
2149 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue( 0,1,0));
2150 CPPUNIT_ASSERT_EQUAL(u
"#DIV/0!"_ustr
, m_pDoc
->GetString(1,2,0));
2151 CPPUNIT_ASSERT_EQUAL(u
"TRUE"_ustr
, m_pDoc
->GetString(1,3,0));
2153 m_pDoc
->DeleteTab(0);
2156 CPPUNIT_TEST_FIXTURE(Test
, testMatrixConditionalBooleanResult
)
2158 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
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
, u
"=IF({1;0};TRUE();42)"_ustr
); // {TRUE,42}
2165 m_pDoc
->InsertMatrixFormula( 0,1, 1,1, aMark
, u
"=IF({0;1};TRUE();42)"_ustr
); // {42,1} aim for {42,TRUE}
2166 m_pDoc
->InsertMatrixFormula( 0,2, 1,2, aMark
, u
"=IF({1;0};42;FALSE())"_ustr
); // {42,0} aim for {42,FALSE}
2167 m_pDoc
->InsertMatrixFormula( 0,3, 1,3, aMark
, u
"=IF({0;1};42;FALSE())"_ustr
); // {FALSE,42}
2169 CPPUNIT_ASSERT_EQUAL( u
"TRUE"_ustr
, m_pDoc
->GetString(0,0,0));
2170 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(1,0,0));
2171 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(0,1,0));
2172 //CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc->GetString(1,1,0)); // not yet
2173 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(0,2,0));
2174 //CPPUNIT_ASSERT_EQUAL( OUString("FALSE"), m_pDoc->GetString(1,2,0)); // not yet
2175 CPPUNIT_ASSERT_EQUAL( u
"FALSE"_ustr
, m_pDoc
->GetString(0,3,0));
2176 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(1,3,0));
2178 m_pDoc
->DeleteTab(0);
2181 CPPUNIT_TEST_FIXTURE(Test
, testEnterMixedMatrix
)
2183 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
2185 // Insert the source values in A1:B2.
2186 m_pDoc
->SetString(0, 0, 0, u
"A"_ustr
);
2187 m_pDoc
->SetString(1, 0, 0, u
"B"_ustr
);
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
, u
"=A1:B2"_ustr
);
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, u
"Test"_ustr
);
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), u
"=5"_ustr
);
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
, u
"=TRANSPOSE(A1:B1)"_ustr
);
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, u
"TestTab"_ustr
);
2252 ScAddress
aSrc(0,0,0);
2253 ScAddress
aDest(0,1,0);
2254 OUString
aStr(u
"please copy me"_ustr
);
2255 m_pDoc
->SetString(aSrc
, u
"please copy me"_ustr
);
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, u
"TestTab"_ustr
);
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), u
"copy me"_ustr
);
2274 // Insert edit cells in B1:B3.
2275 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
2276 rEE
.SetTextCurrentDefaults(u
"Edit 1"_ustr
);
2277 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject());
2278 rEE
.SetTextCurrentDefaults(u
"Edit 2"_ustr
);
2279 m_pDoc
->SetEditText(ScAddress(1,1,0), rEE
.CreateTextObject());
2280 rEE
.SetTextCurrentDefaults(u
"Edit 3"_ustr
);
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
, u
"Hello world in A3"_ustr
);
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(u
"copy me"_ustr
, 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(u
"Edit 1"_ustr
, 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(u
"Edit 2"_ustr
, 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(u
"Edit 3"_ustr
, 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, u
"TestTab1"_ustr
);
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, u
"TestTab2"_ustr
);
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", u
"TestTab1"_ustr
, 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", u
"TestTab2"_ustr
, aName
);
2413 m_pDoc
->DeleteTab(1);
2414 m_pDoc
->DeleteTab(0);
2417 CPPUNIT_TEST_FIXTURE(Test
, testDataArea
)
2419 m_pDoc
->InsertTab(0, u
"Data"_ustr
);
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, u
"Some text"_ustr
);
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, u
"Sheet1"_ustr
);
2457 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
2458 m_pDoc
->InsertTab(2, u
"Sheet3"_ustr
);
2459 m_pDoc
->InsertTab(3, u
"Sheet4"_ustr
);
2460 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", static_cast<SCTAB
>(4), m_pDoc
->GetTableCount());
2462 OUString
a1(u
"A1"_ustr
);
2463 OUString
a2(u
"A2"_ustr
);
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, u
"=Sheet1.A1"_ustr
);
2476 m_pDoc
->SetString(0, 1, 1, u
"=Sheet1.A2"_ustr
);
2477 m_pDoc
->SetString(0, 0, 2, u
"=Sheet1.A1"_ustr
);
2478 m_pDoc
->SetString(0, 0, 3, u
"=Sheet1.A2"_ustr
);
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
[] = {
2730 const char* aArray
[] = {
2750 const char* aStatistical
[] = {
2803 "FORECAST.ETS.MULT",
2804 "FORECAST.ETS.PI.ADD",
2805 "FORECAST.ETS.PI.MULT",
2806 "FORECAST.ETS.SEASONALITY",
2807 "FORECAST.ETS.STAT.ADD",
2808 "FORECAST.ETS.STAT.MULT",
2905 const char* aSpreadsheet
[] = {
2938 const char* aText
[] = {
2990 const char* Category
; const char** Functions
;
2992 { "Database", aDataBase
},
2993 { "Date&Time", aDateTime
},
2994 { "Financial", aFinancial
},
2995 { "Information", aInformation
},
2996 { "Logical", aLogical
},
2997 { "Mathematical", aMathematical
},
2998 { "Array", aArray
},
2999 { "Statistical", aStatistical
},
3000 { "Spreadsheet", aSpreadsheet
},
3002 { "Add-in", nullptr },
3003 { nullptr, nullptr }
3006 ScFunctionMgr
* pFuncMgr
= ScGlobal::GetStarCalcFunctionMgr();
3007 sal_uInt32 n
= pFuncMgr
->getCount();
3008 for (sal_uInt32 i
= 0; i
< n
; ++i
)
3010 const formula::IFunctionCategory
* pCat
= pFuncMgr
->getCategory(i
);
3011 CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat
->getName().equalsAscii(aTests
[i
].Category
));
3012 sal_uInt32 nFuncCount
= pCat
->getCount();
3013 for (sal_uInt32 j
= 0; j
< nFuncCount
; ++j
)
3015 const formula::IFunctionDescription
* pFunc
= pCat
->getFunction(j
);
3016 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests
[i
].Functions
[j
]), pFunc
->getFunctionName());
3021 CPPUNIT_TEST_FIXTURE(Test
, testGraphicsInGroup
)
3023 m_pDoc
->InsertTab(0, u
"TestTab"_ustr
);
3024 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
3025 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
3027 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3028 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
3029 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
3030 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
3032 m_pDoc
->InitDrawLayer();
3033 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
3034 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
3035 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3036 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
3040 tools::Rectangle
aOrigRect(2,2,100,100);
3041 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aOrigRect
);
3042 pPage
->InsertObject(pObj
.get());
3043 const tools::Rectangle
&rNewRect
= pObj
->GetLogicRect();
3044 CPPUNIT_ASSERT_EQUAL_MESSAGE("must have equal position and size",
3045 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3047 ScDrawLayer::SetPageAnchored(*pObj
);
3049 //Use a range of rows guaranteed to include all of the square
3050 m_pDoc
->ShowRows(0, 100, 0, false);
3051 m_pDoc
->SetDrawPageSize(0);
3052 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3053 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3054 m_pDoc
->ShowRows(0, 100, 0, true);
3055 m_pDoc
->SetDrawPageSize(0);
3056 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3057 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3059 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
3060 CPPUNIT_ASSERT_EQUAL_MESSAGE("That shouldn't change size or positioning",
3061 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3063 m_pDoc
->ShowRows(0, 100, 0, false);
3064 m_pDoc
->SetDrawPageSize(0);
3066 CPPUNIT_ASSERT_EQUAL_MESSAGE("Hiding should not change the logic rectangle",
3067 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3068 CPPUNIT_ASSERT_MESSAGE("Hiding should make invisible", !pObj
->IsVisible());
3070 m_pDoc
->ShowRows(0, 100, 0, true);
3071 m_pDoc
->SetDrawPageSize(0);
3072 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when cell anchored",
3073 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3074 CPPUNIT_ASSERT_MESSAGE("Show should make visible", pObj
->IsVisible());
3079 tools::Rectangle
aOrigRect(10,10,210,210); // 200 x 200
3080 rtl::Reference
<SdrCircObj
> pObj
= new SdrCircObj(*pDrawLayer
, SdrCircKind::Full
, aOrigRect
);
3081 pPage
->InsertObject(pObj
.get());
3082 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3083 CPPUNIT_ASSERT_EQUAL_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
3084 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3086 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3087 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell anchored. Not good.",
3088 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3090 // Insert 2 rows at the top. This should push the circle object down.
3091 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3092 m_pDoc
->SetDrawPageSize(0);
3094 // Make sure the size of the circle is still identical.
3095 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of the circle has changed, but shouldn't!",
3096 aOrigRect
.GetSize(), rNewRect
.GetSize());
3098 // Delete 2 rows at the top. This should bring the circle object to its original position.
3099 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3100 m_pDoc
->SetDrawPageSize(0);
3101 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to move back to its original position.",
3102 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3107 basegfx::B2DPolygon aTempPoly
;
3108 Point
aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
3109 tools::Rectangle
aOrigRect(10,200,110,300); // 100 x 100
3110 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
3111 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
3112 rtl::Reference
<SdrPathObj
> pObj
= new SdrPathObj(*pDrawLayer
, SdrObjKind::Line
, basegfx::B2DPolyPolygon(aTempPoly
));
3113 pObj
->NbcSetLogicRect(aOrigRect
);
3114 pPage
->InsertObject(pObj
.get());
3115 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3116 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size differ.",
3117 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3119 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3120 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell-anchored. Not good.",
3121 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3123 // Insert 2 rows at the top and delete them immediately.
3124 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3125 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3126 m_pDoc
->SetDrawPageSize(0);
3127 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of a line object changed after row insertion and removal.",
3128 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3130 sal_Int32 n
= pObj
->GetPointCount();
3131 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 2 points in a line object.", static_cast<sal_Int32
>(2), n
);
3132 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3133 aStartPos
, pObj
->GetPoint(0));
3134 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3135 aEndPos
, pObj
->GetPoint(1));
3138 m_pDoc
->DeleteTab(0);
3141 CPPUNIT_TEST_FIXTURE(Test
, testGraphicsOnSheetMove
)
3143 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
3144 m_pDoc
->InsertTab(1, u
"Tab2"_ustr
);
3145 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 2 sheets to begin with", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
3147 m_pDoc
->InitDrawLayer();
3148 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
3149 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
3150 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3151 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
3153 // Insert an object.
3154 tools::Rectangle
aObjRect(2,2,100,100);
3155 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
3156 pPage
->InsertObject(pObj
.get());
3157 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3159 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", static_cast<size_t>(1), pPage
->GetObjCount());
3161 const ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
3162 CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData
);
3163 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3164 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3166 pPage
= pDrawLayer
->GetPage(1);
3167 CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage
);
3168 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", static_cast<size_t>(0), pPage
->GetObjCount());
3170 // Insert a new sheet at left-end, and make sure the object has moved to
3172 m_pDoc
->InsertTab(0, u
"NewTab"_ustr
);
3173 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", static_cast<SCTAB
>(3), m_pDoc
->GetTableCount());
3174 pPage
= pDrawLayer
->GetPage(0);
3175 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3176 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3177 pPage
= pDrawLayer
->GetPage(1);
3178 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3179 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3180 pPage
= pDrawLayer
->GetPage(2);
3181 CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage
);
3182 CPPUNIT_ASSERT_EQUAL_MESSAGE("3rd sheet should have no object.", size_t(0), pPage
->GetObjCount());
3184 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3185 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3187 // Now, delete the sheet that just got inserted. The object should be back
3188 // on the 1st sheet.
3189 m_pDoc
->DeleteTab(0);
3190 pPage
= pDrawLayer
->GetPage(0);
3191 CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage
);
3192 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have one object.", size_t(1), pPage
->GetObjCount());
3193 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size and position of the object shouldn't change.",
3194 aObjRect
, pObj
->GetLogicRect());
3196 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3197 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3199 // Move the 1st sheet to the last position.
3200 m_pDoc
->MoveTab(0, 1);
3201 pPage
= pDrawLayer
->GetPage(0);
3202 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3203 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3204 pPage
= pDrawLayer
->GetPage(1);
3205 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3206 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3207 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3208 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3210 // Copy the 2nd sheet, which has one drawing object to the last position.
3211 m_pDoc
->CopyTab(1, 2);
3212 pPage
= pDrawLayer
->GetPage(2);
3213 CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage
);
3214 CPPUNIT_ASSERT_EQUAL_MESSAGE("Copied sheet should have one object.", size_t(1), pPage
->GetObjCount());
3215 pObj
= pPage
->GetObj(0);
3216 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj
);
3217 pData
= ScDrawLayer::GetObjData(pObj
.get());
3218 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
3219 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maStart
.Tab());
3220 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maEnd
.Tab());
3222 m_pDoc
->DeleteTab(2);
3223 m_pDoc
->DeleteTab(1);
3224 m_pDoc
->DeleteTab(0);
3227 CPPUNIT_TEST_FIXTURE(Test
, testToggleRefFlag
)
3230 * Test toggling relative/absolute flag of cell and cell range references.
3231 * This corresponds with hitting Shift-F4 while the cursor is on a formula
3234 // In this test, there is no need to insert formula string into a cell in
3235 // the document, as ScRefFinder does not depend on the content of the
3236 // document except for the sheet names.
3238 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3241 // Calc A1: basic 2D reference
3243 OUString
aFormula(u
"=B100"_ustr
);
3244 ScAddress
aPos(1, 5, 0);
3245 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3248 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3250 // column relative / row relative -> column absolute / row absolute
3251 aFinder
.ToggleRel(0, aFormula
.getLength());
3252 aFormula
= aFinder
.GetText();
3253 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=$B$100"_ustr
, aFormula
);
3255 // column absolute / row absolute -> column relative / row absolute
3256 aFinder
.ToggleRel(0, aFormula
.getLength());
3257 aFormula
= aFinder
.GetText();
3258 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=B$100"_ustr
, aFormula
);
3260 // column relative / row absolute -> column absolute / row relative
3261 aFinder
.ToggleRel(0, aFormula
.getLength());
3262 aFormula
= aFinder
.GetText();
3263 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=$B100"_ustr
, aFormula
);
3265 // column absolute / row relative -> column relative / row relative
3266 aFinder
.ToggleRel(0, aFormula
.getLength());
3267 aFormula
= aFinder
.GetText();
3268 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=B100"_ustr
, aFormula
);
3272 // Excel R1C1: basic 2D reference
3274 OUString
aFormula(u
"=R2C1"_ustr
);
3275 ScAddress
aPos(3, 5, 0);
3276 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3279 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3281 // column absolute / row absolute -> column relative / row absolute
3282 aFinder
.ToggleRel(0, aFormula
.getLength());
3283 aFormula
= aFinder
.GetText();
3284 CPPUNIT_ASSERT_EQUAL(u
"=R2C[-3]"_ustr
, aFormula
);
3286 // column relative / row absolute - > column absolute / row relative
3287 aFinder
.ToggleRel(0, aFormula
.getLength());
3288 aFormula
= aFinder
.GetText();
3289 CPPUNIT_ASSERT_EQUAL(u
"=R[-4]C1"_ustr
, aFormula
);
3291 // column absolute / row relative -> column relative / row relative
3292 aFinder
.ToggleRel(0, aFormula
.getLength());
3293 aFormula
= aFinder
.GetText();
3294 CPPUNIT_ASSERT_EQUAL(u
"=R[-4]C[-3]"_ustr
, aFormula
);
3296 // column relative / row relative -> column absolute / row absolute
3297 aFinder
.ToggleRel(0, aFormula
.getLength());
3298 aFormula
= aFinder
.GetText();
3299 CPPUNIT_ASSERT_EQUAL(u
"=R2C1"_ustr
, aFormula
);
3303 // Excel R1C1: Selection at the end of the formula string and does not
3304 // overlap the formula string at all (inspired by fdo#39135).
3305 OUString
aFormula(u
"=R1C1"_ustr
);
3306 ScAddress
aPos(1, 1, 0);
3307 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3310 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3312 // Make the column relative.
3313 sal_Int32 n
= aFormula
.getLength();
3314 aFinder
.ToggleRel(n
, n
);
3315 aFormula
= aFinder
.GetText();
3316 CPPUNIT_ASSERT_EQUAL(u
"=R1C[-1]"_ustr
, aFormula
);
3318 // Make the row relative.
3319 n
= aFormula
.getLength();
3320 aFinder
.ToggleRel(n
, n
);
3321 aFormula
= aFinder
.GetText();
3322 CPPUNIT_ASSERT_EQUAL(u
"=R[-1]C1"_ustr
, aFormula
);
3324 // Make both relative.
3325 n
= aFormula
.getLength();
3326 aFinder
.ToggleRel(n
, n
);
3327 aFormula
= aFinder
.GetText();
3328 CPPUNIT_ASSERT_EQUAL(u
"=R[-1]C[-1]"_ustr
, aFormula
);
3330 // Back to the original.
3331 n
= aFormula
.getLength();
3332 aFinder
.ToggleRel(n
, n
);
3333 aFormula
= aFinder
.GetText();
3334 CPPUNIT_ASSERT_EQUAL(u
"=R1C1"_ustr
, aFormula
);
3339 OUString
aFormula(u
"=A1+4"_ustr
);
3340 ScAddress
aPos(1, 1, 0);
3341 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3344 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3346 // Set the cursor over the 'A1' part and toggle.
3347 aFinder
.ToggleRel(2, 2);
3348 aFormula
= aFinder
.GetText();
3349 CPPUNIT_ASSERT_EQUAL(u
"=$A$1+4"_ustr
, aFormula
);
3351 aFinder
.ToggleRel(2, 2);
3352 aFormula
= aFinder
.GetText();
3353 CPPUNIT_ASSERT_EQUAL(u
"=A$1+4"_ustr
, aFormula
);
3355 aFinder
.ToggleRel(2, 2);
3356 aFormula
= aFinder
.GetText();
3357 CPPUNIT_ASSERT_EQUAL(u
"=$A1+4"_ustr
, aFormula
);
3359 aFinder
.ToggleRel(2, 2);
3360 aFormula
= aFinder
.GetText();
3361 CPPUNIT_ASSERT_EQUAL(u
"=A1+4"_ustr
, aFormula
);
3364 // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
3365 // partial selection within formula string.
3367 m_pDoc
->DeleteTab(0);
3370 CPPUNIT_TEST_FIXTURE(Test
, testAutofilter
)
3372 m_pDoc
->InsertTab( 0, u
"Test"_ustr
);
3374 // cell contents (0 = empty cell)
3375 const char* aData
[][3] = {
3376 { "C1", "C2", "C3" },
3378 { "1", "2", nullptr },
3383 SCCOL nCols
= SAL_N_ELEMENTS(aData
[0]);
3384 SCROW nRows
= SAL_N_ELEMENTS(aData
);
3387 for (SCROW i
= 0; i
< nRows
; ++i
)
3388 for (SCCOL j
= 0; j
< nCols
; ++j
)
3390 m_pDoc
->SetString(j
, i
, 0, OUString::createFromAscii(aData
[i
][j
]));
3392 ScDBData
* pDBData
= new ScDBData(u
"NONAME"_ustr
, 0, 0, 0, nCols
-1, nRows
-1);
3393 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3395 pDBData
->SetAutoFilter(true);
3397 pDBData
->GetArea(aRange
);
3398 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3399 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3400 aRange
.aStart
.Tab(), ScMF::Auto
);
3402 //create the query param
3403 ScQueryParam aParam
;
3404 pDBData
->GetQueryParam(aParam
);
3405 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3406 rEntry
.bDoQuery
= true;
3408 rEntry
.eOp
= SC_EQUAL
;
3409 rEntry
.GetQueryItem().mfVal
= 0;
3410 // add queryParam to database range.
3411 pDBData
->SetQueryParam(aParam
);
3413 // perform the query.
3414 m_pDoc
->Query(0, aParam
, true);
3418 bool bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3419 CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden
);
3420 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(2), nRow1
);
3421 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(3), nRow2
);
3423 // Remove filtering.
3425 m_pDoc
->Query(0, aParam
, true);
3426 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3427 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden
);
3428 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3429 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3431 // Filter for non-empty cells by column C.
3432 rEntry
.bDoQuery
= true;
3434 rEntry
.SetQueryByNonEmpty();
3435 m_pDoc
->Query(0, aParam
, true);
3437 // only row 3 should be hidden. The rest should be visible.
3438 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3439 CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden
);
3440 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(0), nRow1
);
3441 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(1), nRow2
);
3442 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3443 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden
);
3444 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow1
);
3445 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow2
);
3446 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3447 CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden
);
3448 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", SCROW(3), nRow1
);
3449 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", m_pDoc
->MaxRow(), nRow2
);
3451 // Now, filter for empty cells by column C.
3452 rEntry
.SetQueryByEmpty();
3453 m_pDoc
->Query(0, aParam
, true);
3455 // Now, only row 1 and 3, and 6 and down should be visible.
3456 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3457 CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden
);
3458 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow1
);
3459 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow2
);
3460 bHidden
= m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
);
3461 CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden
);
3462 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow1
);
3463 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow2
);
3464 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3465 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden
);
3466 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow1
);
3467 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow2
);
3468 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3469 CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden
);
3470 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(3), nRow1
);
3471 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(4), nRow2
);
3472 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
3473 CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden
);
3474 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", SCROW(5), nRow1
);
3475 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", m_pDoc
->MaxRow(), nRow2
);
3477 m_pDoc
->DeleteTab(0);
3480 CPPUNIT_TEST_FIXTURE(Test
, testAutoFilterTimeValue
)
3482 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3484 m_pDoc
->SetString(ScAddress(0,0,0), u
"Hours"_ustr
);
3485 m_pDoc
->SetValue(ScAddress(0,1,0), 72.3604166666671);
3486 m_pDoc
->SetValue(ScAddress(0,2,0), 265);
3488 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 0, 2);
3489 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3491 // Apply the "hour:minute:second" format to A2:A3.
3492 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3493 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_TIME_HH_MMSS
, LANGUAGE_ENGLISH_US
);
3494 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3495 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3496 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3498 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 2, 0, aNewAttrs
); // apply it to A2:A3.
3500 printRange(m_pDoc
, ScRange(0,0,0,0,2,0), "Data"); // A1:A3
3502 // Make sure the hour:minute:second format is really applied.
3503 CPPUNIT_ASSERT_EQUAL(u
"1736:39:00"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0))); // A2
3504 CPPUNIT_ASSERT_EQUAL(u
"6360:00:00"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0))); // A3
3506 // Filter by the A2 value. Only A1 and A2 should be visible.
3507 ScQueryParam aParam
;
3508 pDBData
->GetQueryParam(aParam
);
3509 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3510 rEntry
.bDoQuery
= true;
3512 rEntry
.eOp
= SC_EQUAL
;
3513 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern(u
"1736:39:00"_ustr
);
3514 rEntry
.GetQueryItem().meType
= ScQueryEntry::ByString
;
3516 pDBData
->SetQueryParam(aParam
);
3518 // perform the query.
3519 m_pDoc
->Query(0, aParam
, true);
3521 // A1:A2 should be visible while A3 should be filtered out.
3522 CPPUNIT_ASSERT_MESSAGE("A1 should be visible.", !m_pDoc
->RowFiltered(0,0));
3523 CPPUNIT_ASSERT_MESSAGE("A2 should be visible.", !m_pDoc
->RowFiltered(1,0));
3524 CPPUNIT_ASSERT_MESSAGE("A3 should be filtered out.", m_pDoc
->RowFiltered(2,0));
3526 m_pDoc
->DeleteTab(0);
3529 CPPUNIT_TEST_FIXTURE(Test
, testAutofilterOptimizations
)
3531 m_pDoc
->InsertTab( 0, u
"Test"_ustr
);
3533 constexpr SCCOL nCols
= 4;
3534 constexpr SCROW nRows
= 200;
3535 m_pDoc
->SetString(0, 0, 0, u
"Column1"_ustr
);
3536 m_pDoc
->SetString(1, 0, 0, u
"Column2"_ustr
);
3537 m_pDoc
->SetString(2, 0, 0, u
"Column3"_ustr
);
3538 m_pDoc
->SetString(3, 0, 0, u
"Column4"_ustr
);
3540 // Fill 1st column with 0-199, 2nd with 1-200, 3rd with "1000"-"1199", 4th with "1001-1200"
3541 // (the pairs are off by one to each other to check filtering out a value filters out
3542 // only the relevant column).
3543 for(SCROW i
= 0; i
< nRows
; ++i
)
3545 m_pDoc
->SetValue(0, i
+ 1, 0, i
);
3546 m_pDoc
->SetValue(1, i
+ 1, 0, i
+1);
3547 m_pDoc
->SetString(2, i
+ 1, 0, "val" + OUString::number(i
+1000));
3548 m_pDoc
->SetString(3, i
+ 1, 0, "val" + OUString::number(i
+1000+1));
3551 ScDBData
* pDBData
= new ScDBData(u
"NONAME"_ustr
, 0, 0, 0, nCols
, nRows
);
3552 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3554 pDBData
->SetAutoFilter(true);
3556 pDBData
->GetArea(aRange
);
3557 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3558 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3559 aRange
.aStart
.Tab(), ScMF::Auto
);
3561 //create the query param
3562 ScQueryParam aParam
;
3563 pDBData
->GetQueryParam(aParam
);
3564 ScQueryEntry
& rEntry0
= aParam
.GetEntry(0);
3565 rEntry0
.bDoQuery
= true;
3567 rEntry0
.eOp
= SC_EQUAL
;
3568 rEntry0
.GetQueryItems().resize(nRows
);
3569 ScQueryEntry
& rEntry1
= aParam
.GetEntry(1);
3570 rEntry1
.bDoQuery
= true;
3572 rEntry1
.eOp
= SC_EQUAL
;
3573 rEntry1
.GetQueryItems().resize(nRows
);
3574 ScQueryEntry
& rEntry2
= aParam
.GetEntry(2);
3575 rEntry2
.bDoQuery
= true;
3577 rEntry2
.eOp
= SC_EQUAL
;
3578 rEntry2
.GetQueryItems().resize(nRows
);
3579 ScQueryEntry
& rEntry3
= aParam
.GetEntry(3);
3580 rEntry3
.bDoQuery
= true;
3582 rEntry3
.eOp
= SC_EQUAL
;
3583 rEntry3
.GetQueryItems().resize(nRows
);
3584 // Set up autofilter to select all values except one in each column.
3585 // This should only filter out 2nd, 3rd, 6th and 7th rows.
3586 for( int i
= 0; i
< nRows
; ++i
)
3589 rEntry0
.GetQueryItems()[i
].mfVal
= i
;
3591 rEntry1
.GetQueryItems()[i
].mfVal
= i
+ 1;
3594 rEntry2
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000));
3595 rEntry2
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3599 rEntry3
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000+1));
3600 rEntry3
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3603 // add queryParam to database range.
3604 pDBData
->SetQueryParam(aParam
);
3606 // perform the query.
3607 m_pDoc
->Query(0, aParam
, true);
3609 // check that only rows with filtered out values are hidden, and not rows that share
3610 // a value in a different column
3612 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
));
3613 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden", m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
));
3614 CPPUNIT_ASSERT_MESSAGE("row 4 should be hidden", m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
));
3615 CPPUNIT_ASSERT_MESSAGE("row 5 should be visible", !m_pDoc
->RowHidden(4, 0, &nRow1
, &nRow2
));
3616 CPPUNIT_ASSERT_MESSAGE("row 6 should be visible", !m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
));
3617 CPPUNIT_ASSERT_MESSAGE("row 7 should be hidden", m_pDoc
->RowHidden(6, 0, &nRow1
, &nRow2
));
3618 CPPUNIT_ASSERT_MESSAGE("row 8 should be hidden", m_pDoc
->RowHidden(7, 0, &nRow1
, &nRow2
));
3619 CPPUNIT_ASSERT_MESSAGE("row 9 should be visible", !m_pDoc
->RowHidden(8, 0, &nRow1
, &nRow2
));
3621 // Remove filtering.
3625 m_pDoc
->Query(0, aParam
, true);
3626 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
));
3627 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3628 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3630 m_pDoc
->DeleteTab(0);
3633 CPPUNIT_TEST_FIXTURE(Test
, testTdf76441
)
3635 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3637 // The result will be different depending on whether the format is set before
3638 // or after inserting the string
3640 OUString aCode
= u
"MM:SS"_ustr
;
3641 sal_Int32 nCheckPos
;
3642 SvNumFormatType nType
;
3644 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3645 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3647 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3648 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3649 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3651 // First insert the string, then the format
3652 m_pDoc
->SetString(ScAddress(0,0,0), u
"01:20"_ustr
);
3654 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3656 CPPUNIT_ASSERT_EQUAL(u
"20:00"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3660 // First set the format, then insert the string
3661 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3663 m_pDoc
->SetString(ScAddress(0,1,0), u
"01:20"_ustr
);
3665 // Without the fix in place, this test would have failed with
3666 // - Expected: 01:20
3668 CPPUNIT_ASSERT_EQUAL(u
"01:20"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3671 m_pDoc
->DeleteTab(0);
3674 CPPUNIT_TEST_FIXTURE(Test
, testTdf76836
)
3676 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3678 OUString aCode
= u
"\"192.168.0.\"@"_ustr
;
3679 sal_Int32 nCheckPos
;
3680 SvNumFormatType nType
;
3682 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3683 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3685 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3686 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3687 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3689 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3690 m_pDoc
->SetValue(0,0,0, 10.0);
3692 // Without the fix in place, this test would have failed with
3694 // - Actual : 192.168.0.10
3695 CPPUNIT_ASSERT_EQUAL(u
"10"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3697 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3698 m_pDoc
->SetString(ScAddress(0,1,0), u
"10"_ustr
);
3699 CPPUNIT_ASSERT_EQUAL(u
"192.168.0.10"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3701 m_pDoc
->DeleteTab(0);
3704 CPPUNIT_TEST_FIXTURE(Test
, testTdf151752
)
3706 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3708 m_pDoc
->SetString(ScAddress(0,0,0), u
"66000:00"_ustr
);
3710 // Without the fix in place, this test would have failed with
3711 // - Expected: 66000:00:00
3712 // - Actual : 464:00:00
3713 CPPUNIT_ASSERT_EQUAL(u
"66000:00:00"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3715 m_pDoc
->DeleteTab(0);
3718 CPPUNIT_TEST_FIXTURE(Test
, testTdf142186
)
3720 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3722 // The result will be different depending on whether the format is set before
3723 // or after inserting the string
3725 OUString aCode
= u
"0\".\"0"_ustr
;
3726 sal_Int32 nCheckPos
;
3727 SvNumFormatType nType
;
3729 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3730 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3732 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3733 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3734 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3736 // First insert the string, then the format
3737 m_pDoc
->SetString(ScAddress(0,0,0), u
"123.45"_ustr
);
3739 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3741 CPPUNIT_ASSERT_EQUAL(u
"12.3"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3745 // First set the format, then insert the string
3746 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3748 m_pDoc
->SetString(ScAddress(0,1,0), u
"123.45"_ustr
);
3750 // Without the fix in place, this test would have failed with
3752 // - Actual : 1234.5
3753 CPPUNIT_ASSERT_EQUAL(u
"12.3"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3756 m_pDoc
->DeleteTab(0);
3759 CPPUNIT_TEST_FIXTURE(Test
, testTdf137063
)
3761 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3763 m_pDoc
->SetValue(0,0,0, 0.000000006);
3764 m_pDoc
->SetValue(0,1,0, 0.0000000006);
3766 // Without the fix in place, this test would have failed with
3767 // - Expected: 0.000000006
3769 CPPUNIT_ASSERT_EQUAL(u
"0.000000006"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3770 CPPUNIT_ASSERT_EQUAL(u
"6E-10"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3772 m_pDoc
->DeleteTab(0);
3775 CPPUNIT_TEST_FIXTURE(Test
, testTdf126342
)
3777 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3779 OUString aCode
= u
"YYYY-MM-DD"_ustr
;
3780 sal_Int32 nCheckPos
;
3781 SvNumFormatType nType
;
3783 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3784 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3786 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3787 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3788 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3789 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3791 m_pDoc
->SetString(ScAddress(0,0,0), u
"11/7/19"_ustr
);
3793 CPPUNIT_ASSERT_EQUAL(u
"2019-11-07"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3795 // Overwrite the existing date with the exact same input
3796 m_pDoc
->SetString(ScAddress(0,0,0), u
"11/7/19"_ustr
);
3798 // Without the fix in place, this test would have failed with
3799 // - Expected: 2019-11-07
3800 // - Actual : 2011-07-19
3801 CPPUNIT_ASSERT_EQUAL(u
"2019-11-07"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3803 m_pDoc
->DeleteTab(0);
3806 CPPUNIT_TEST_FIXTURE(Test
, testAdvancedFilter
)
3808 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3810 // cell contents (nullptr = empty cell)
3811 std::vector
<std::vector
<const char*>> aData
= {
3812 { "Value", "Tag" }, // A1:B11
3824 { "Value", "Tag" }, // A13:B14
3829 for (size_t nRow
= 0; nRow
< aData
.size(); ++nRow
)
3831 const std::vector
<const char*>& rRowData
= aData
[nRow
];
3832 for (size_t nCol
= 0; nCol
< rRowData
.size(); ++nCol
)
3834 const char* pCell
= rRowData
[nCol
];
3836 m_pDoc
->SetString(nCol
, nRow
, 0, OUString::createFromAscii(pCell
));
3840 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 1, 10);
3841 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3843 ScRange
aDataRange(0,0,0,1,10,0);
3844 ScRange
aFilterRuleRange(0,12,0,1,13,0);
3846 printRange(m_pDoc
, aDataRange
, "Data");
3847 printRange(m_pDoc
, aFilterRuleRange
, "Filter Rule");
3849 ScQueryParam aQueryParam
;
3850 aQueryParam
.bHasHeader
= true;
3851 aQueryParam
.nCol1
= aDataRange
.aStart
.Col();
3852 aQueryParam
.nRow1
= aDataRange
.aStart
.Row();
3853 aQueryParam
.nCol2
= aDataRange
.aEnd
.Col();
3854 aQueryParam
.nRow2
= aDataRange
.aEnd
.Row();
3855 aQueryParam
.nTab
= aDataRange
.aStart
.Tab();
3857 bool bGood
= m_pDoc
->CreateQueryParam(aFilterRuleRange
, aQueryParam
);
3858 CPPUNIT_ASSERT_MESSAGE("failed to create query param.", bGood
);
3860 // First entry is for the 'Value' field, and is greater than 5.
3861 ScQueryEntry aEntry
= aQueryParam
.GetEntry(0);
3862 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
3863 CPPUNIT_ASSERT_EQUAL(SCCOLROW(0), aEntry
.nField
);
3864 CPPUNIT_ASSERT_EQUAL(SC_GREATER
, aEntry
.eOp
);
3866 ScQueryEntry::QueryItemsType aItems
= aEntry
.GetQueryItems();
3867 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
3868 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByValue
, aItems
[0].meType
);
3869 CPPUNIT_ASSERT_EQUAL(5.0, aItems
[0].mfVal
);
3871 // Second entry is for the 'Tag' field, and is == 'R'.
3872 aEntry
= aQueryParam
.GetEntry(1);
3873 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
3874 CPPUNIT_ASSERT_EQUAL(SCCOLROW(1), aEntry
.nField
);
3875 CPPUNIT_ASSERT_EQUAL(SC_EQUAL
, aEntry
.eOp
);
3877 aItems
= aEntry
.GetQueryItems();
3878 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
3879 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByString
, aItems
[0].meType
);
3880 CPPUNIT_ASSERT_EQUAL(u
"R"_ustr
, aItems
[0].maString
.getString());
3882 // perform the query.
3883 m_pDoc
->Query(0, aQueryParam
, true);
3885 // Only rows 1,8-10 should be visible.
3886 bool bFiltered
= m_pDoc
->RowFiltered(0, 0);
3887 CPPUNIT_ASSERT_MESSAGE("row 1 (header row) should be visible", !bFiltered
);
3889 SCROW nRow1
= -1, nRow2
= -1;
3890 bFiltered
= m_pDoc
->RowFiltered(1, 0, &nRow1
, &nRow2
);
3891 CPPUNIT_ASSERT_MESSAGE("rows 2-7 should be filtered out.", bFiltered
);
3892 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(1), nRow1
);
3893 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(6), nRow2
);
3895 bFiltered
= m_pDoc
->RowFiltered(7, 0, &nRow1
, &nRow2
);
3896 CPPUNIT_ASSERT_MESSAGE("rows 8-10 should be visible.", !bFiltered
);
3897 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(7), nRow1
);
3898 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(9), nRow2
);
3900 m_pDoc
->DeleteTab(0);
3903 CPPUNIT_TEST_FIXTURE(Test
, testDateFilterContains
)
3905 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3907 constexpr SCCOL nCols
= 1;
3908 constexpr SCROW nRows
= 5;
3909 m_pDoc
->SetString(0, 0, 0, u
"Date"_ustr
);
3910 m_pDoc
->SetString(0, 1, 0, u
"1/2/2021"_ustr
);
3911 m_pDoc
->SetString(0, 2, 0, u
"2/1/1999"_ustr
);
3912 m_pDoc
->SetString(0, 3, 0, u
"2/1/1997"_ustr
);
3913 m_pDoc
->SetString(0, 4, 0, u
"3/3/2001"_ustr
);
3914 m_pDoc
->SetString(0, 5, 0, u
"3/3/1996"_ustr
);
3916 // Set the fields as dates.
3917 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3918 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_DATE_DIN_YYMMDD
, LANGUAGE_ENGLISH_US
);
3919 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3920 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3921 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3922 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 5, 0, aNewAttrs
); // apply it to A1:A6
3924 ScDBData
* pDBData
= new ScDBData(u
"NONAME"_ustr
, 0, 0, 0, nCols
, nRows
);
3925 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3927 pDBData
->SetAutoFilter(true);
3929 pDBData
->GetArea(aRange
);
3930 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3931 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3932 aRange
.aStart
.Tab(), ScMF::Auto
);
3934 //create the query param
3935 ScQueryParam aParam
;
3936 pDBData
->GetQueryParam(aParam
);
3937 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3938 rEntry
.bDoQuery
= true;
3940 rEntry
.eOp
= SC_CONTAINS
;
3941 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern(u
"2"_ustr
);
3942 pDBData
->SetQueryParam(aParam
);
3944 // perform the query.
3945 m_pDoc
->Query(0, aParam
, true);
3947 // Dates in rows 2-4 contain '2', row 5 shows 2001 only as 01, and row 6 doesn't contain it at all.
3948 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0));
3949 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible", !m_pDoc
->RowHidden(2, 0));
3950 CPPUNIT_ASSERT_MESSAGE("row 4 should be visible", !m_pDoc
->RowHidden(3, 0));
3951 CPPUNIT_ASSERT_MESSAGE("row 5 should be hidden", m_pDoc
->RowHidden(4, 0));
3952 CPPUNIT_ASSERT_MESSAGE("row 6 should be hidden", m_pDoc
->RowHidden(5, 0));
3954 m_pDoc
->DeleteTab(0);
3957 CPPUNIT_TEST_FIXTURE(Test
, testTdf98642
)
3959 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
3960 m_pDoc
->SetString(0, 0, 0, u
"test"_ustr
);
3962 ScRangeData
* pName1
= new ScRangeData( *m_pDoc
, u
"name1"_ustr
, u
"$Sheet1.$A$1"_ustr
);
3963 ScRangeData
* pName2
= new ScRangeData( *m_pDoc
, u
"name2"_ustr
, u
"$Sheet1.$A$1"_ustr
);
3965 std::unique_ptr
<ScRangeName
> pGlobalRangeName(new ScRangeName());
3966 pGlobalRangeName
->insert(pName1
);
3967 pGlobalRangeName
->insert(pName2
);
3968 m_pDoc
->SetRangeName(std::move(pGlobalRangeName
));
3970 m_pDoc
->SetString(1, 0, 0, u
"=name1"_ustr
);
3971 m_pDoc
->SetString(1, 1, 0, u
"=name2"_ustr
);
3973 CPPUNIT_ASSERT_EQUAL(u
"test"_ustr
, m_pDoc
->GetString(1, 0, 0));
3974 CPPUNIT_ASSERT_EQUAL(u
"test"_ustr
, m_pDoc
->GetString(1, 1, 0));
3976 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
3977 CPPUNIT_ASSERT_EQUAL(u
"=name1"_ustr
, aFormula
);
3978 aFormula
= m_pDoc
->GetFormula(1,1,0);
3980 // Without the fix in place, this test would have failed with
3981 // - Expected: =name2
3982 // - Actual : =name1
3983 CPPUNIT_ASSERT_EQUAL(u
"=name2"_ustr
, aFormula
);
3985 m_pDoc
->DeleteTab(0);
3988 CPPUNIT_TEST_FIXTURE(Test
, testMergedCells
)
3990 //test merge and unmerge
3991 //TODO: an undo/redo test for this would be a good idea
3992 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
3993 m_pDoc
->DoMerge(1, 1, 3, 3, 0, false);
3996 m_pDoc
->ExtendMerge( 1, 1, nEndCol
, nEndRow
, 0);
3997 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCCOL(3), nEndCol
);
3998 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCROW(3), nEndRow
);
3999 ScRange
aRange(0,2,0,m_pDoc
->MaxCol(),2,0);
4000 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4001 aMark
.SetMarkArea(aRange
);
4002 m_xDocShell
->GetDocFunc().InsertCells(aRange
, &aMark
, INS_INSROWS_BEFORE
, true, true);
4003 m_pDoc
->ExtendMerge(1, 1, nEndCol
, nEndRow
, 0);
4004 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCCOL(3), nEndCol
);
4005 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCROW(4), nEndRow
);
4006 m_pDoc
->DeleteTab(0);
4009 CPPUNIT_TEST_FIXTURE(Test
, testRenameTable
)
4011 //test set rename table
4012 //TODO: set name1 and name2 and do an undo to check if name 1 is set now
4013 //TODO: also check if new name for table is same as another table
4015 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4016 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
4018 //test case 1 , rename table2 to sheet 1, it should return error
4019 OUString nameToSet
= u
"Sheet1"_ustr
;
4020 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4021 CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc
.RenameTable(1,nameToSet
,false,true) );
4023 //test case 2 , simple rename to check name
4024 nameToSet
= "test1";
4025 m_xDocShell
->GetDocFunc().RenameTable(0,nameToSet
,false,true);
4026 OUString nameJustSet
;
4027 m_pDoc
->GetName(0,nameJustSet
);
4028 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4030 //test case 3 , rename again
4032 m_pDoc
->GetName(0,anOldName
);
4034 nameToSet
= "test2";
4035 rDocFunc
.RenameTable(0,nameToSet
,false,true);
4036 m_pDoc
->GetName(0,nameJustSet
);
4037 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4039 //test case 4 , check if undo works
4040 SfxUndoAction
* pUndo
= new ScUndoRenameTab(m_xDocShell
.get(),0,anOldName
,nameToSet
);
4042 m_pDoc
->GetName(0,nameJustSet
);
4043 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct name is not set after undo", nameJustSet
, anOldName
);
4046 m_pDoc
->GetName(0,nameJustSet
);
4047 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after redo", nameJustSet
, nameToSet
);
4050 m_pDoc
->DeleteTab(0);
4051 m_pDoc
->DeleteTab(1);
4054 CPPUNIT_TEST_FIXTURE(Test
, testSetBackgroundColor
)
4056 //test set background color
4057 //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
4059 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4064 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4065 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set",
4066 aColor
, m_pDoc
->GetTabBgColor(0));
4068 Color aOldTabBgColor
=m_pDoc
->GetTabBgColor(0);
4070 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4071 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set the second time",
4072 aColor
, m_pDoc
->GetTabBgColor(0));
4074 //now check for undo
4075 SfxUndoAction
* pUndo
= new ScUndoTabColor(m_xDocShell
.get(), 0, aOldTabBgColor
, aColor
);
4077 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aOldTabBgColor
, m_pDoc
->GetTabBgColor(0));
4079 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aColor
, m_pDoc
->GetTabBgColor(0));
4081 m_pDoc
->DeleteTab(0);
4084 CPPUNIT_TEST_FIXTURE(Test
, testUpdateReference
)
4086 //test that formulas are correctly updated during sheet delete
4087 //TODO: add tests for relative references, updating of named ranges, ...
4088 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4089 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
4090 m_pDoc
->InsertTab(2, u
"Sheet3"_ustr
);
4091 m_pDoc
->InsertTab(3, u
"Sheet4"_ustr
);
4093 m_pDoc
->SetValue(0,0,2, 1);
4094 m_pDoc
->SetValue(1,0,2, 2);
4095 m_pDoc
->SetValue(1,1,3, 4);
4096 m_pDoc
->SetString(2,0,2, u
"=A1+B1"_ustr
);
4097 m_pDoc
->SetString(2,1,2, u
"=Sheet4.B2+A1"_ustr
);
4100 aValue
= m_pDoc
->GetValue(2,0,2);
4101 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", 3, aValue
);
4102 aValue
= m_pDoc
->GetValue(2,1,2);
4103 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", 5, aValue
);
4105 //test deleting both sheets: one is not directly before the sheet, the other one is
4106 m_pDoc
->DeleteTab(0);
4107 aValue
= m_pDoc
->GetValue(2,0,1);
4108 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", 3, aValue
);
4109 aValue
= m_pDoc
->GetValue(2,1,1);
4110 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", 5, aValue
);
4112 m_pDoc
->DeleteTab(0);
4113 aValue
= m_pDoc
->GetValue(2,0,0);
4114 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", 3, aValue
);
4115 aValue
= m_pDoc
->GetValue(2,1,0);
4116 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", 5, aValue
);
4118 //test adding two sheets
4119 m_pDoc
->InsertTab(0, u
"Sheet2"_ustr
);
4120 aValue
= m_pDoc
->GetValue(2,0,1);
4121 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", 3, aValue
);
4122 aValue
= m_pDoc
->GetValue(2,1,1);
4123 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", 5, aValue
);
4125 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4126 aValue
= m_pDoc
->GetValue(2,0,2);
4127 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", 3, aValue
);
4128 aValue
= m_pDoc
->GetValue(2,1,2);
4129 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", 5, aValue
);
4131 //test new DeleteTabs/InsertTabs methods
4132 m_pDoc
->DeleteTabs(0, 2);
4133 aValue
= m_pDoc
->GetValue(2, 0, 0);
4134 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", 3, aValue
);
4135 aValue
= m_pDoc
->GetValue(2, 1, 0);
4136 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", 5, aValue
);
4138 std::vector
<OUString
> aSheets
;
4139 aSheets
.emplace_back("Sheet1");
4140 aSheets
.emplace_back("Sheet2");
4141 m_pDoc
->InsertTabs(0, aSheets
, true);
4142 aValue
= m_pDoc
->GetValue(2, 0, 2);
4144 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", 3, aValue
);
4145 aValue
= m_pDoc
->GetValue(2, 1, 2);
4146 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", 5, aValue
);
4148 m_pDoc
->DeleteTab(3);
4149 m_pDoc
->DeleteTab(2);
4150 m_pDoc
->DeleteTab(1);
4151 m_pDoc
->DeleteTab(0);
4153 // Test positional update and invalidation of lookup cache for insertion
4154 // and deletion within entire column reference.
4155 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4156 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
4157 m_pDoc
->SetString(0,1,0, u
"s1"_ustr
);
4158 m_pDoc
->SetString(0,0,1, u
"=MATCH(\"s1\";Sheet1.A:A;0)"_ustr
);
4159 aValue
= m_pDoc
->GetValue(0,0,1);
4160 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4161 m_pDoc
->InsertRow(0,0,m_pDoc
->MaxCol(),0,0,1); // insert 1 row before row 1 in Sheet1
4162 aValue
= m_pDoc
->GetValue(0,0,1);
4163 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 3, aValue
);
4164 m_pDoc
->DeleteRow(0,0,m_pDoc
->MaxCol(),0,0,1); // delete row 1 in Sheet1
4165 aValue
= m_pDoc
->GetValue(0,0,1);
4166 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4167 m_pDoc
->DeleteTab(1);
4168 m_pDoc
->DeleteTab(0);
4171 CPPUNIT_TEST_FIXTURE(Test
, testSearchCells
)
4173 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4175 m_pDoc
->SetString(ScAddress(0,0,0), u
"A"_ustr
);
4176 m_pDoc
->SetString(ScAddress(0,1,0), u
"B"_ustr
);
4177 m_pDoc
->SetString(ScAddress(0,2,0), u
"A"_ustr
);
4179 m_pDoc
->SetString(ScAddress(0,4,0), u
"A"_ustr
);
4180 m_pDoc
->SetString(ScAddress(0,5,0), u
"B"_ustr
);
4181 m_pDoc
->SetString(ScAddress(0,6,0), u
"C"_ustr
);
4183 SvxSearchItem
aItem(SID_SEARCH_ITEM
);
4184 aItem
.SetSearchString(u
"A"_ustr
);
4185 aItem
.SetCommand(SvxSearchCmd::FIND_ALL
);
4186 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4187 aMarkData
.SelectOneTable(0);
4191 ScRangeList aMatchedRanges
;
4193 bool bMatchedRangesWereClamped
= false;
4194 bool bSuccess
= m_pDoc
->SearchAndReplace(aItem
, nCol
, nRow
, nTab
, aMarkData
, aMatchedRanges
, aUndoStr
, nullptr, bMatchedRangesWereClamped
);
4196 CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess
);
4197 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 3 matching cells.", size_t(3), aMatchedRanges
.size());
4198 ScAddress
aHit(0,0,0);
4199 CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4201 CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4203 CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4205 m_pDoc
->DeleteTab(0);
4208 CPPUNIT_TEST_FIXTURE(Test
, testFormulaPosition
)
4210 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4212 ScAddress
aPos(0,0,0); // A1
4213 m_pDoc
->SetString(aPos
, u
"=ROW()"_ustr
);
4214 aPos
.IncRow(); // A2
4215 m_pDoc
->SetString(aPos
, u
"=ROW()"_ustr
);
4216 aPos
.SetRow(3); // A4;
4217 m_pDoc
->SetString(aPos
, u
"=ROW()"_ustr
);
4220 SCROW aRows
[] = { 0, 1, 3 };
4221 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, SAL_N_ELEMENTS(aRows
));
4222 CPPUNIT_ASSERT(bRes
);
4225 m_pDoc
->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
4227 SCROW aRows
[] = { 0, 6, 8 };
4228 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, SAL_N_ELEMENTS(aRows
));
4229 CPPUNIT_ASSERT(bRes
);
4232 m_pDoc
->DeleteTab(0);
4237 bool hasRange(const ScDocument
* pDoc
, const std::vector
<ScTokenRef
>& rRefTokens
, const ScRange
& rRange
, const ScAddress
& rPos
)
4239 for (const ScTokenRef
& p
: rRefTokens
)
4241 if (!ScRefTokenHelper::isRef(p
) || ScRefTokenHelper::isExternalRef(p
))
4244 switch (p
->GetType())
4246 case formula::svSingleRef
:
4248 ScSingleRefData aData
= *p
->GetSingleRef();
4249 if (rRange
.aStart
!= rRange
.aEnd
)
4252 ScAddress aThis
= aData
.toAbs(*pDoc
, rPos
);
4253 if (aThis
== rRange
.aStart
)
4257 case formula::svDoubleRef
:
4259 ScComplexRefData aData
= *p
->GetDoubleRef();
4260 ScRange aThis
= aData
.toAbs(*pDoc
, rPos
);
4261 if (aThis
== rRange
)
4274 CPPUNIT_TEST_FIXTURE(Test
, testJumpToPrecedentsDependents
)
4277 * Test to make sure correct precedent / dependent cells are obtained when
4278 * preparing to jump to them.
4280 // Precedent is another cell that the cell references, while dependent is
4281 // another cell that references it.
4282 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4284 m_pDoc
->SetString(2, 0, 0, u
"=A1+A2+B3"_ustr
); // C1
4285 m_pDoc
->SetString(2, 1, 0, u
"=A1"_ustr
); // C2
4288 std::vector
<ScTokenRef
> aRefTokens
;
4289 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4292 // C1's precedent should be A1:A2,B3.
4293 ScAddress
aC1(2, 0, 0);
4294 ScRangeList
aRange(aC1
);
4295 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4296 CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
4297 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0, 0, 1, 0), aC1
));
4298 CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
4299 hasRange(m_pDoc
, aRefTokens
, ScRange(1, 2, 0), aC1
));
4303 // C2's precedent should be A1 only.
4304 ScAddress
aC2(2, 1, 0);
4305 ScRangeList
aRange(aC2
);
4306 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4307 CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
4308 static_cast<size_t>(1), aRefTokens
.size());
4309 CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
4310 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0), aC2
));
4314 // A1's dependent should be C1:C2.
4315 ScAddress
aA1(0, 0, 0);
4316 ScRangeList
aRange(aA1
);
4317 rDocFunc
.DetectiveCollectAllSuccs(aRange
, aRefTokens
);
4318 CPPUNIT_ASSERT_EQUAL_MESSAGE("C1:C2 should be the only dependent of A1.",
4319 std::vector
<ScTokenRef
>::size_type(1), aRefTokens
.size());
4320 CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
4321 hasRange(m_pDoc
, aRefTokens
, ScRange(2, 0, 0, 2, 1, 0), aA1
));
4324 m_pDoc
->DeleteTab(0);
4327 CPPUNIT_TEST_FIXTURE(Test
, testTdf149665
)
4329 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4331 m_pDoc
->SetString(0, 0, 0, u
"''1"_ustr
);
4333 // Without the fix in place, this test would have failed with
4336 CPPUNIT_ASSERT_EQUAL( u
"'1"_ustr
, m_pDoc
->GetString( 0, 0, 0 ) );
4338 m_pDoc
->DeleteTab(0);
4341 CPPUNIT_TEST_FIXTURE(Test
, testTdf64001
)
4343 m_pDoc
->InsertTab(0, u
"test"_ustr
);
4345 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4346 aMarkData
.SelectTable(0, true);
4348 m_pDoc
->SetString( 0, 0, 0, u
"TRUE"_ustr
);
4349 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 9, FILL_TO_BOTTOM
, FILL_AUTO
);
4351 for (SCCOL i
= 0; i
< 10; ++i
)
4353 CPPUNIT_ASSERT_EQUAL( u
"TRUE"_ustr
, m_pDoc
->GetString( 0, i
, 0 ) );
4356 m_pDoc
->SetString( 0, 10, 0, u
"FALSE"_ustr
);
4358 m_pDoc
->SetString( 1, 0, 0, u
"=COUNTIF(A1:A11;TRUE)"_ustr
);
4360 // Without the fix in place, this test would have failed with
4363 CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc
->GetValue( 1, 0, 0 ) );
4365 m_pDoc
->DeleteTab(0);
4368 CPPUNIT_TEST_FIXTURE(Test
, testAutoFill
)
4370 m_pDoc
->InsertTab(0, u
"test"_ustr
);
4372 m_pDoc
->SetValue(0,0,0,1);
4374 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4375 aMarkData
.SelectTable(0, true);
4377 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5);
4378 for (SCROW i
= 0; i
< 6; ++i
)
4379 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1.0), m_pDoc
->GetValue(0, i
, 0));
4381 // check that hidden rows are not affected by autofill
4382 // set values for hidden rows
4383 m_pDoc
->SetValue(0,1,0,10);
4384 m_pDoc
->SetValue(0,2,0,10);
4386 m_pDoc
->SetRowHidden(1, 2, 0, true);
4387 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 8);
4389 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,1,0));
4390 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,2,0));
4391 for (SCROW i
= 3; i
< 8; ++i
)
4392 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
-1.0), m_pDoc
->GetValue(0, i
, 0));
4394 m_pDoc
->Fill( 0, 0, 0, 8, nullptr, aMarkData
, 5, FILL_TO_RIGHT
);
4395 for (SCCOL i
= 0; i
< 5; ++i
)
4397 for(SCROW j
= 0; j
< 8; ++j
)
4401 ASSERT_DOUBLES_EQUAL(static_cast<double>(j
-1+i
), m_pDoc
->GetValue(i
, j
, 0));
4405 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(i
, 0, 0));
4407 else // j == 1 || j == 2
4410 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,j
,0));
4412 ASSERT_DOUBLES_EQUAL(0.0, m_pDoc
->GetValue(i
,j
,0));
4417 // test auto fill user data lists
4418 m_pDoc
->SetString( 0, 100, 0, u
"January"_ustr
);
4419 m_pDoc
->Fill( 0, 100, 0, 100, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4420 OUString aTestValue
= m_pDoc
->GetString( 0, 101, 0 );
4421 CPPUNIT_ASSERT_EQUAL( u
"February"_ustr
, aTestValue
);
4422 aTestValue
= m_pDoc
->GetString( 0, 102, 0 );
4423 CPPUNIT_ASSERT_EQUAL( u
"March"_ustr
, aTestValue
);
4425 // test that two same user data list entries will not result in incremental fill
4426 m_pDoc
->SetString( 0, 101, 0, u
"January"_ustr
);
4427 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4428 for ( SCROW i
= 102; i
<= 103; ++i
)
4430 aTestValue
= m_pDoc
->GetString( 0, i
, 0 );
4431 CPPUNIT_ASSERT_EQUAL( u
"January"_ustr
, aTestValue
);
4434 // Clear column A for a new test.
4435 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4436 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4438 // Fill A1:A6 with 1,2,3,4,5,6.
4439 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4440 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
4441 ScRange
aRange(0,0,0,0,5,0);
4442 aMarkData
.SetMarkArea(aRange
);
4443 rFunc
.FillSeries(aRange
, &aMarkData
, FILL_TO_BOTTOM
, FILL_AUTO
, FILL_DAY
, MAXDOUBLE
, 1.0, MAXDOUBLE
, true);
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 // Undo should clear the area except for the top cell.
4452 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4453 CPPUNIT_ASSERT(pUndoMgr
);
4456 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4457 for (SCROW i
= 1; i
<= 5; ++i
)
4458 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(0,i
,0)));
4460 // Redo should put the serial values back in.
4462 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4463 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4464 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4465 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4466 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4467 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4469 // test that filling formulas vertically up does the right thing
4470 for(SCROW nRow
= 0; nRow
< 10; ++nRow
)
4471 m_pDoc
->SetValue(100, 100 + nRow
, 0, 1);
4473 m_pDoc
->SetString(100, 110, 0, u
"=A111"_ustr
);
4475 m_pDoc
->Fill(100, 110, 100, 110, nullptr, aMarkData
, 10, FILL_TO_TOP
, FILL_AUTO
);
4476 for(SCROW nRow
= 110; nRow
>= 100; --nRow
)
4478 OUString aExpected
= "=A" + OUString::number(nRow
+1);
4479 OUString aFormula
= m_pDoc
->GetFormula(100, nRow
, 0);
4480 CPPUNIT_ASSERT_EQUAL(aExpected
, aFormula
);
4483 // Clear column A for a new test.
4484 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4485 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4487 m_pDoc
->SetString( 0, 100, 0, u
"2012-10-31"_ustr
);
4488 m_pDoc
->SetString( 0, 101, 0, u
"2012-10-31"_ustr
);
4489 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4491 // tdf#89754, Without the fix in place, this test would have failed with
4492 // - Expected: 2012-10-31
4493 // - Actual : 2012-11-01
4494 CPPUNIT_ASSERT_EQUAL( u
"2012-10-31"_ustr
, m_pDoc
->GetString( 0, 102, 0 ) );
4495 CPPUNIT_ASSERT_EQUAL( u
"2012-10-31"_ustr
, m_pDoc
->GetString( 0, 103, 0 ) );
4496 CPPUNIT_ASSERT_EQUAL( u
"2012-10-31"_ustr
, m_pDoc
->GetString( 0, 104, 0 ) );
4498 // Clear column A for a new test.
4499 clearRange(m_pDoc
, ScRange(0, 0, 0, 0, m_pDoc
->MaxRow(), 0));
4500 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4502 m_pDoc
->SetString(0, 100, 0, u
"2019-10-31"_ustr
);
4503 m_pDoc
->SetString(0, 101, 0, u
"2019-11-30"_ustr
);
4504 m_pDoc
->SetString(0, 102, 0, u
"2019-12-31"_ustr
);
4505 m_pDoc
->Fill(0, 100, 0, 102, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4507 // tdf#58745, Without the fix in place, this test would have failed with
4508 // - Expected: 2020-01-31
4509 // - Actual : 2019-01-11
4510 CPPUNIT_ASSERT_EQUAL(u
"2020-01-31"_ustr
, m_pDoc
->GetString(0, 103, 0));
4511 CPPUNIT_ASSERT_EQUAL(u
"2020-02-29"_ustr
, m_pDoc
->GetString(0, 104, 0));
4512 CPPUNIT_ASSERT_EQUAL(u
"2020-03-31"_ustr
, m_pDoc
->GetString(0, 105, 0));
4514 // Clear column A for a new test.
4515 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4516 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4518 m_pDoc
->SetString( 0, 50, 0, u
"1.0"_ustr
);
4519 m_pDoc
->SetString( 0, 51, 0, u
"1.1"_ustr
);
4520 m_pDoc
->SetString( 0, 52, 0, u
"1.2"_ustr
);
4521 m_pDoc
->SetString( 0, 53, 0, u
"1.3"_ustr
);
4522 m_pDoc
->Fill( 0, 50, 0, 53, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4524 CPPUNIT_ASSERT_EQUAL( u
"1.4"_ustr
, m_pDoc
->GetString( 0, 54, 0 ) );
4525 CPPUNIT_ASSERT_EQUAL( u
"1.5"_ustr
, m_pDoc
->GetString( 0, 55, 0 ) );
4526 CPPUNIT_ASSERT_EQUAL( u
"1.6"_ustr
, m_pDoc
->GetString( 0, 56, 0 ) );
4528 m_pDoc
->SetString( 0, 60, 0, u
"4.0"_ustr
);
4529 m_pDoc
->SetString( 0, 61, 0, u
"4.1"_ustr
);
4530 m_pDoc
->SetString( 0, 62, 0, u
"4.2"_ustr
);
4531 m_pDoc
->SetString( 0, 63, 0, u
"4.3"_ustr
);
4532 m_pDoc
->Fill( 0, 60, 0, 63, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4534 // tdf#37424: Without the fix in place, this test would have failed with
4537 CPPUNIT_ASSERT_EQUAL( u
"4.4"_ustr
, m_pDoc
->GetString( 0, 64, 0 ) );
4538 CPPUNIT_ASSERT_EQUAL( u
"4.5"_ustr
, m_pDoc
->GetString( 0, 65, 0 ) );
4539 CPPUNIT_ASSERT_EQUAL( u
"4.6"_ustr
, m_pDoc
->GetString( 0, 66, 0 ) );
4541 // Clear column A for a new test.
4542 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4543 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4545 m_pDoc
->SetString( 0, 70, 0, u
"001-001-001"_ustr
);
4546 m_pDoc
->Fill( 0, 70, 0, 70, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4548 // tdf#105268: Without the fix in place, this test would have failed with
4549 // - Expected: 001-001-002
4550 // - Actual : 001-001000
4551 CPPUNIT_ASSERT_EQUAL( u
"001-001-002"_ustr
, m_pDoc
->GetString( 0, 71, 0 ) );
4552 CPPUNIT_ASSERT_EQUAL( u
"001-001-003"_ustr
, m_pDoc
->GetString( 0, 72, 0 ) );
4553 CPPUNIT_ASSERT_EQUAL( u
"001-001-004"_ustr
, m_pDoc
->GetString( 0, 73, 0 ) );
4555 // Clear column A for a new test.
4556 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4557 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4559 m_pDoc
->SetString( 0, 80, 0, u
"1%"_ustr
);
4560 m_pDoc
->Fill( 0, 80, 0, 80, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4562 // tdf#89998: Without the fix in place, this test would have failed with
4563 // - Expected: 2.00%
4564 // - Actual : 101.00%
4565 CPPUNIT_ASSERT_EQUAL( u
"2.00%"_ustr
, m_pDoc
->GetString( 0, 81, 0 ) );
4566 CPPUNIT_ASSERT_EQUAL( u
"3.00%"_ustr
, m_pDoc
->GetString( 0, 82, 0 ) );
4567 CPPUNIT_ASSERT_EQUAL( u
"4.00%"_ustr
, m_pDoc
->GetString( 0, 83, 0 ) );
4569 // Clear column A for a new test.
4570 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4571 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4573 m_pDoc
->SetString( 0, 0, 0, u
"1"_ustr
);
4574 m_pDoc
->SetString( 0, 1, 0, u
"1.1"_ustr
);
4575 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 60, FILL_TO_BOTTOM
, FILL_AUTO
);
4577 // tdf#129606: Without the fix in place, this test would have failed with
4579 // - Actual : 6.00000000000001
4580 CPPUNIT_ASSERT_EQUAL( u
"6"_ustr
, m_pDoc
->GetString( 0, 50, 0 ) );
4582 // Clear column A for a new test.
4583 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4584 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4586 m_pDoc
->SetString( 0, 0, 0, u
"2022-10-01 00:00:00.000"_ustr
);
4587 m_pDoc
->SetString( 0, 1, 0, u
"2022-10-01 01:00:00.000"_ustr
);
4588 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4590 // tdf#151460: Without the fix in place, this test would have failed with
4591 // - Expected: 2022-10-01 20:00:00.000
4592 // - Actual : 2022-10-01 19:59:59.999
4593 CPPUNIT_ASSERT_EQUAL( u
"2022-10-01 20:00:00.000"_ustr
, m_pDoc
->GetString( 0, 20, 0 ) );
4595 // Clear column A for a new test.
4596 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4597 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4599 m_pDoc
->SetString( 0, 0, 0, u
"1st"_ustr
);
4601 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5, FILL_TO_BOTTOM
, FILL_AUTO
);
4603 CPPUNIT_ASSERT_EQUAL( u
"1st"_ustr
, m_pDoc
->GetString( 0, 0, 0 ) );
4604 CPPUNIT_ASSERT_EQUAL( u
"2nd"_ustr
, m_pDoc
->GetString( 0, 1, 0 ) );
4605 CPPUNIT_ASSERT_EQUAL( u
"3rd"_ustr
, m_pDoc
->GetString( 0, 2, 0 ) );
4607 // Clear column A for a new test.
4608 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4609 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4611 m_pDoc
->SetString( 0, 200, 0, u
"15:00"_ustr
);
4612 m_pDoc
->SetString( 0, 201, 0, u
"15:20"_ustr
);
4613 m_pDoc
->Fill( 0, 200, 0, 201, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4615 CPPUNIT_ASSERT_EQUAL( u
"03:00:00 PM"_ustr
, m_pDoc
->GetString( 0, 200, 0 ) );
4617 // tdf#153517: Without the fix in place, this test would have failed with
4618 // - Expected: 03:20:00 PM
4619 // - Actual : 03:19:59 PM
4620 CPPUNIT_ASSERT_EQUAL( u
"03:20:00 PM"_ustr
, m_pDoc
->GetString( 0, 201, 0 ) );
4621 CPPUNIT_ASSERT_EQUAL( u
"03:40:00 PM"_ustr
, m_pDoc
->GetString( 0, 202, 0 ) );
4622 CPPUNIT_ASSERT_EQUAL( u
"04:00:00 PM"_ustr
, m_pDoc
->GetString( 0, 203, 0 ) );
4624 m_pDoc
->DeleteTab(0);
4627 CPPUNIT_TEST_FIXTURE(Test
, testAutoFillSimple
)
4629 m_pDoc
->InsertTab(0, u
"test"_ustr
);
4631 m_pDoc
->SetValue(0, 0, 0, 1);
4632 m_pDoc
->SetString(0, 1, 0, u
"=10"_ustr
);
4634 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4635 aMarkData
.SelectTable(0, true);
4637 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 6, FILL_TO_BOTTOM
, FILL_AUTO
);
4639 for(SCROW nRow
= 0; nRow
< 8; ++nRow
)
4643 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4644 CPPUNIT_ASSERT_EQUAL((nRow
+2)/2.0, nVal
);
4648 OString aMsg
= "wrong value in row: " + OString::number(nRow
);
4649 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4650 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), 10.0, nVal
);
4654 m_pDoc
->DeleteTab(0);
4657 CPPUNIT_TEST_FIXTURE(Test
, testFindAreaPosVertical
)
4659 std::vector
<std::vector
<const char*>> aData
= {
4660 { nullptr, "1", "1" },
4661 { "1", nullptr, "1" },
4663 { nullptr, "1", "1" },
4665 { "1", nullptr, "1" },
4669 m_pDoc
->InsertTab(0, u
"Test1"_ustr
);
4670 clearRange( m_pDoc
, ScRange(0, 0, 0, 1, aData
.size(), 0));
4671 ScAddress
aPos(0,0,0);
4672 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4673 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4675 m_pDoc
->SetRowHidden(4,4,0,true);
4676 bool bHidden
= m_pDoc
->RowHidden(4,0);
4677 CPPUNIT_ASSERT(bHidden
);
4681 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4683 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4684 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4686 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4688 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), nRow
);
4689 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
>(5), nRow
);
4694 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), 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
>(0), nCol
);
4701 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4703 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), nRow
);
4704 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4709 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4711 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), nRow
);
4712 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4714 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4716 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4717 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4721 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_UP
);
4722 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4723 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4725 m_pDoc
->DeleteTab(0);
4728 CPPUNIT_TEST_FIXTURE(Test
, testFindAreaPosColRight
)
4730 std::vector
<std::vector
<const char*>> aData
= {
4731 { "", "1", "1", "", "1", "1", "1" },
4732 { "", "", "1", "1", "1", "", "1" },
4735 m_pDoc
->InsertTab(0, u
"test1"_ustr
);
4736 clearRange( m_pDoc
, ScRange(0, 0, 0, 7, aData
.size(), 0));
4737 ScAddress
aPos(0,0,0);
4738 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4739 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4741 m_pDoc
->SetColHidden(4,4,0,true);
4742 bool bHidden
= m_pDoc
->ColHidden(4,0);
4743 CPPUNIT_ASSERT(bHidden
);
4747 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4749 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4750 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4752 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4754 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4755 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4757 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4759 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4760 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(5), nCol
);
4762 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4764 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4765 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4767 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4769 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4770 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), nCol
);
4775 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4777 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4778 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(3), nCol
);
4780 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4782 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4783 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4785 m_pDoc
->DeleteTab(0);
4788 CPPUNIT_TEST_FIXTURE(Test
, testShiftCells
)
4790 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
4792 // We need a drawing layer in order to create caption objects.
4793 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4795 OUString
aTestVal(u
"Some Text"_ustr
);
4797 // Text into cell E5.
4798 m_pDoc
->SetString(4, 3, 0, aTestVal
);
4800 // put a Note in cell E5
4801 ScAddress
rAddr(4, 3, 0);
4802 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
4803 pNote
->SetText(rAddr
, u
"Hello"_ustr
);
4805 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4807 // Insert cell at D5. This should shift the string cell to right.
4808 m_pDoc
->InsertCol(3, 0, 3, 0, 3, 1);
4809 OUString aStr
= m_pDoc
->GetString(5, 3, 0);
4810 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4811 CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(3, 4, 3, 4, 0));
4813 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(4, 3, 0));
4814 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(5, 3, 0));
4816 // Delete cell D5, to shift the text cell back into D5.
4817 m_pDoc
->DeleteCol(3, 0, 3, 0, 3, 1);
4818 aStr
= m_pDoc
->GetString(4, 3, 0);
4819 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4820 CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(4, 4, 4, 4, 0));
4822 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(5, 3, 0));
4823 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4825 m_pDoc
->DeleteTab(0);
4828 CPPUNIT_TEST_FIXTURE(Test
, testNoteDefaultStyle
)
4830 m_pDoc
->InsertTab(0, u
"PostIts"_ustr
);
4832 // We need a drawing layer in order to create caption objects.
4833 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4835 auto pNote
= m_pDoc
->GetOrCreateNote({0, 0, 0});
4836 auto pCaption
= pNote
->GetCaption();
4838 CPPUNIT_ASSERT(pCaption
);
4839 CPPUNIT_ASSERT_EQUAL(ScResId(STR_STYLENAME_NOTE
), pCaption
->GetStyleSheet()->GetName());
4841 m_pDoc
->DeleteTab(0);
4844 CPPUNIT_TEST_FIXTURE(Test
, testNoteBasic
)
4846 m_pDoc
->InsertTab(0, u
"PostIts"_ustr
);
4848 // We need a drawing layer in order to create caption objects.
4849 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4851 CPPUNIT_ASSERT(!m_pDoc
->HasNotes());
4853 // Check for note's presence in all tables before inserting any notes.
4854 for (SCTAB i
= 0; i
<= MAXTAB
; ++i
)
4856 bool bHasNotes
= m_pDoc
->HasTabNotes(i
);
4857 CPPUNIT_ASSERT(!bHasNotes
);
4860 ScAddress
aAddr(2, 2, 0); // cell C3
4861 ScPostIt
*pNote
= m_pDoc
->GetOrCreateNote(aAddr
);
4863 pNote
->SetText(aAddr
, u
"Hello world"_ustr
);
4864 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
4866 ScPostIt
*pGetNote
= m_pDoc
->GetNote(aAddr
);
4867 CPPUNIT_ASSERT_EQUAL_MESSAGE("note should be itself", pNote
, pGetNote
);
4869 // Insert one row at row 1.
4870 bool bInsertRow
= m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
4871 CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow
);
4873 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4874 aAddr
.IncRow(); // cell C4
4875 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4877 // Insert column at column A.
4878 bool bInsertCol
= m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
4879 CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol
);
4881 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4882 aAddr
.IncCol(); // cell D4
4883 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4885 // Insert a new sheet to shift the current sheet to the right.
4886 m_pDoc
->InsertTab(0, u
"Table2"_ustr
);
4887 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4888 aAddr
.IncTab(); // Move to the next sheet.
4889 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4891 m_pDoc
->DeleteTab(0);
4893 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4895 // Insert cell at C4. This should NOT shift the note position.
4896 bInsertRow
= m_pDoc
->InsertRow(2, 0, 2, 0, 3, 1);
4897 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow
);
4898 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
4900 // Delete cell at C4. Again, this should NOT shift the note position.
4901 m_pDoc
->DeleteRow(2, 0, 2, 0, 3, 1);
4902 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
4904 // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
4905 m_pDoc
->DeleteRow(3, 0, 3, 0, 2, 1);
4906 aAddr
.IncRow(-1); // cell D3
4907 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D4 should have shifted up to D3.", pNote
, m_pDoc
->GetNote(aAddr
));
4909 // Delete column C. This should shift the note one cell left.
4910 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 2, 1);
4911 aAddr
.IncCol(-1); // cell C3
4912 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D3 should have shifted left to C3.", pNote
, m_pDoc
->GetNote(aAddr
));
4914 // Insert a text where the note is.
4915 m_pDoc
->SetString(aAddr
, u
"Note is here."_ustr
);
4917 // Delete row 1. This should shift the note from C3 to C2.
4918 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 1);
4919 aAddr
.IncRow(-1); // C2
4920 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at C3 should have shifted up to C2.", pNote
, m_pDoc
->GetNote(aAddr
));
4922 m_pDoc
->DeleteTab(0);
4925 CPPUNIT_TEST_FIXTURE(Test
, testNoteDeleteRow
)
4927 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4929 // We need a drawing layer in order to create caption objects.
4930 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4932 ScAddress
aPos(1, 1, 0);
4933 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
4934 pNote
->SetText(aPos
, u
"Hello"_ustr
);
4935 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
4937 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
4939 // test with IsBlockEmpty
4940 CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc
->IsEmptyData(0, 0, 100, 100, 0));
4941 CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
4943 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
4945 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
4947 // Set values and notes into B3:B4.
4948 aPos
= ScAddress(1,2,0); // B3
4949 m_pDoc
->SetString(aPos
, u
"First"_ustr
);
4950 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, u
"First Note"_ustr
, false, false);
4952 aPos
= ScAddress(1,3,0); // B4
4953 m_pDoc
->SetString(aPos
, u
"Second"_ustr
);
4954 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, u
"Second Note"_ustr
, false, false);
4957 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4958 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4959 aMark
.SelectOneTable(0);
4960 rDocFunc
.DeleteCells(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0), &aMark
, DelCellCmd::CellsUp
, true);
4962 // Check to make sure the notes have shifted upward.
4963 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
4964 CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote
);
4965 CPPUNIT_ASSERT_EQUAL(u
"First Note"_ustr
, pNote
->GetText());
4966 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4967 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4968 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
4969 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
4970 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
4974 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4975 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
4976 m_pDoc
->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
4979 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
4980 CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote
);
4981 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4982 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4983 CPPUNIT_ASSERT_EQUAL(u
"First Note"_ustr
, 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(u
"Second Note"_ustr
, pNote
->GetText());
4989 rDocFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
4991 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
4992 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
4993 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
4994 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
4995 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
4997 // Undo and check the result.
4999 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5000 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5001 CPPUNIT_ASSERT_EQUAL(u
"First Note"_ustr
, pNote
->GetText());
5002 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5003 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
5004 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
5006 m_pDoc
->DeleteTab(0);
5009 CPPUNIT_TEST_FIXTURE(Test
, testNoteDeleteCol
)
5011 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
5013 // We need a drawing layer in order to create caption objects.
5014 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5016 ScAddress
rAddr(1, 1, 0);
5017 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5018 pNote
->SetText(rAddr
, u
"Hello"_ustr
);
5019 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
5021 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
5023 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
5025 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
5027 m_pDoc
->DeleteTab(0);
5030 CPPUNIT_TEST_FIXTURE(Test
, testNoteLifeCycle
)
5032 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5034 // We need a drawing layer in order to create caption objects.
5035 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5037 ScAddress
aPos(1,1,0);
5038 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5039 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote
);
5041 pNote
->SetText(aPos
, u
"New note"_ustr
);
5042 std::unique_ptr
<ScPostIt
> pNote2
= m_pDoc
->ReleaseNote(aPos
);
5043 CPPUNIT_ASSERT_EQUAL_MESSAGE("This note instance is expected to be identical to the original.", pNote
, pNote2
.get());
5044 CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc
->HasNote(aPos
));
5046 // Modify the internal state of the note instance to make sure it's really
5048 pNote
->SetText(aPos
, u
"New content"_ustr
);
5050 // Re-insert the note back to the same place.
5051 m_pDoc
->SetNote(aPos
, std::move(pNote2
));
5052 SdrCaptionObj
* pCaption
= pNote
->GetOrCreateCaption(aPos
);
5053 CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption
);
5054 CPPUNIT_ASSERT_EQUAL_MESSAGE("This caption should belong to the drawing layer of the document.",
5055 m_pDoc
->GetDrawLayer(), static_cast<ScDrawLayer
*>(&pCaption
->getSdrModelFromSdrObject()));
5057 // Copy B2 with note to a clipboard.
5059 ScClipParam
aClipParam(aPos
, false);
5060 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5061 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
5062 aMarkData
.SelectOneTable(0);
5063 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMarkData
, false, true);
5065 ScPostIt
* pClipNote
= aClipDoc
.GetNote(aPos
);
5066 CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote
);
5067 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note on the clipboard should share the same caption object from the original.",
5068 pCaption
, pClipNote
->GetCaption());
5071 // Move B2 to B3 with note, which creates an ScUndoDragDrop, and Undo.
5073 ScAddress
aOrigPos(aPos
);
5074 ScAddress
aMovePos(1,2,0);
5075 ScPostIt
* pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5076 const SdrCaptionObj
* pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5077 bool const bCut
= true; // like Drag&Drop
5078 bool bRecord
= true; // record Undo
5079 bool const bPaint
= false; // don't care about
5080 bool bApi
= true; // API to prevent dialogs
5081 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
5082 bool bMoveDone
= rDocFunc
.MoveBlock(ScRange(aOrigPos
, aOrigPos
), aMovePos
, bCut
, bRecord
, bPaint
, bApi
);
5083 CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone
);
5085 // Verify the note move.
5086 ScPostIt
* pGoneNote
= m_pDoc
->GetNote(aOrigPos
);
5087 CPPUNIT_ASSERT_MESSAGE("Failed to move the note from source.", !pGoneNote
);
5088 ScPostIt
* pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5089 CPPUNIT_ASSERT_MESSAGE("Failed to move the note to destination.", pMoveNote
);
5091 // The caption object should not be identical, it was newly created upon
5092 // Drop from clipboard.
5093 // pOrigCaption is a dangling pointer.
5094 const SdrCaptionObj
* pMoveCaption
= pMoveNote
->GetOrCreateCaption(aMovePos
);
5095 CPPUNIT_ASSERT_MESSAGE("Captions identical after move.", pOrigCaption
!= pMoveCaption
);
5097 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5098 CPPUNIT_ASSERT(pUndoMgr
);
5099 pUndoMgr
->Undo(); // this should not crash ... tdf#92995
5101 // Verify the note move Undo.
5102 pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5103 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move from destination.", !pMoveNote
);
5104 pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5105 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move to source.", pOrigNote
);
5107 // The caption object still should not be identical.
5108 // pMoveCaption is a dangling pointer.
5109 pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5110 CPPUNIT_ASSERT_MESSAGE("Captions identical after move undo.", pOrigCaption
!= pMoveCaption
);
5113 // Create a note at B4, merge B4 and B5 with ScUndoMerge, and Undo.
5115 ScAddress
aPosB4(1,3,0);
5116 ScPostIt
* pNoteB4
= m_pDoc
->GetOrCreateNote(aPosB4
);
5117 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B4.", pNoteB4
);
5118 const SdrCaptionObj
* pCaptionB4
= pNoteB4
->GetOrCreateCaption(aPosB4
);
5119 ScCellMergeOption
aCellMergeOption(1,3,2,3);
5120 rDocFunc
.MergeCells( aCellMergeOption
, true /*bContents*/, bRecord
, bApi
, false /*bEmptyMergedCells*/ );
5122 SfxUndoManager
* pMergeUndoManager
= m_pDoc
->GetUndoManager();
5123 CPPUNIT_ASSERT(pMergeUndoManager
);
5124 pMergeUndoManager
->Undo(); // this should not crash ... tdf#105667
5126 // Undo contained the original caption object pointer which was still alive
5127 // at B4 after the merge and not cloned nor recreated during Undo.
5128 ScPostIt
* pUndoNoteB4
= m_pDoc
->GetNote(aPosB4
);
5129 CPPUNIT_ASSERT_MESSAGE("No cell comment at B4 after Undo.", pUndoNoteB4
);
5130 const SdrCaptionObj
* pUndoCaptionB4
= pUndoNoteB4
->GetCaption();
5131 CPPUNIT_ASSERT_EQUAL_MESSAGE("Captions not identical after Merge Undo.", pCaptionB4
, pUndoCaptionB4
);
5134 // In a second document copy a note from B5 to clipboard, close the
5135 // document and then paste the note into this document.
5137 ScDocShellRef xDocSh2
;
5138 getNewDocShell(xDocSh2
);
5139 ScDocument
* pDoc2
= &xDocSh2
->GetDocument();
5140 pDoc2
->InsertTab(0, u
"OtherSheet1"_ustr
);
5141 pDoc2
->InitDrawLayer(xDocSh2
.get());
5143 ScAddress
aPosB5(1,4,0);
5144 ScPostIt
* pOtherNoteB5
= pDoc2
->GetOrCreateNote(aPosB5
);
5145 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B5.", pOtherNoteB5
);
5146 const SdrCaptionObj
* pOtherCaptionB5
= pOtherNoteB5
->GetOrCreateCaption(aPosB5
);
5147 CPPUNIT_ASSERT_MESSAGE("No caption at B5.", pOtherCaptionB5
);
5149 ScDocument
aClipDoc2(SCDOCMODE_CLIP
);
5150 copyToClip( pDoc2
, aPosB5
, &aClipDoc2
);
5152 // There's no ScTransferObject involved in the "fake" clipboard copy
5153 // and ScDocument dtor asking IsClipboardSource() gets no, so emulate
5154 // the part that normally is responsible for forgetting the caption
5156 aClipDoc2
.ClosingClipboardSource();
5158 pDoc2
->DeleteTab(0);
5162 pasteFromClip( m_pDoc
, aPosB5
, &aClipDoc2
); // should not crash... tdf#104967
5163 ScPostIt
* pNoteB5
= m_pDoc
->GetNote(aPosB5
);
5164 CPPUNIT_ASSERT_MESSAGE("Failed to paste cell comment at B5.", pNoteB5
);
5165 const SdrCaptionObj
* pCaptionB5
= pNoteB5
->GetOrCreateCaption(aPosB5
);
5166 CPPUNIT_ASSERT_MESSAGE("No caption at pasted B5.", pCaptionB5
);
5167 // Do not test if pCaptionB5 != pOtherCaptionB5 because since pDoc2
5168 // has been closed and the caption been deleted objects *may* be
5169 // allocated at the very same memory location.
5172 m_pDoc
->DeleteTab(0);
5175 CPPUNIT_TEST_FIXTURE(Test
, testNoteCopyPaste
)
5177 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5179 // We need a drawing layer in order to create caption objects.
5180 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5182 // Insert in B2 a text and cell comment.
5183 ScAddress
aPos(1,1,0);
5184 m_pDoc
->SetString(aPos
, u
"Text"_ustr
);
5185 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5186 CPPUNIT_ASSERT(pNote
);
5187 pNote
->SetText(aPos
, u
"Note1"_ustr
);
5189 // Insert in B4 a number and cell comment.
5191 m_pDoc
->SetValue(aPos
, 1.1);
5192 pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5193 CPPUNIT_ASSERT(pNote
);
5194 pNote
->SetText(aPos
, u
"Note2"_ustr
);
5196 // Copy B2:B4 to clipboard.
5197 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5198 aMark
.SelectOneTable(0);
5199 ScRange
aCopyRange(1,1,0,1,3,0);
5200 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5201 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
5202 ScClipParam
aClipParam(aCopyRange
, false);
5203 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMark
, false, false);
5205 // Make sure the notes are in the clipboard.
5206 pNote
= aClipDoc
.GetNote(ScAddress(1,1,0));
5207 CPPUNIT_ASSERT(pNote
);
5208 CPPUNIT_ASSERT_EQUAL(u
"Note1"_ustr
, pNote
->GetText());
5210 pNote
= aClipDoc
.GetNote(ScAddress(1,3,0));
5211 CPPUNIT_ASSERT(pNote
);
5212 CPPUNIT_ASSERT_EQUAL(u
"Note2"_ustr
, pNote
->GetText());
5214 // Paste to B6:B8 but only cell notes.
5215 ScRange
aDestRange(1,5,0,1,7,0);
5216 m_pDoc
->CopyFromClip(aDestRange
, aMark
, InsertDeleteFlags::NOTE
, nullptr, &aClipDoc
);
5218 // Make sure the notes are there.
5219 pNote
= m_pDoc
->GetNote(ScAddress(1,5,0));
5220 CPPUNIT_ASSERT(pNote
);
5221 CPPUNIT_ASSERT_EQUAL(u
"Note1"_ustr
, pNote
->GetText());
5223 pNote
= m_pDoc
->GetNote(ScAddress(1,7,0));
5224 CPPUNIT_ASSERT(pNote
);
5225 CPPUNIT_ASSERT_EQUAL(u
"Note2"_ustr
, pNote
->GetText());
5227 // Test that GetNotesInRange includes the end of its range
5228 // and so can find the note
5229 std::vector
<sc::NoteEntry
> aNotes
;
5230 m_pDoc
->GetNotesInRange(ScRange(1,7,0), aNotes
);
5231 CPPUNIT_ASSERT_EQUAL(size_t(1), aNotes
.size());
5233 m_pDoc
->DeleteTab(0);
5237 CPPUNIT_TEST_FIXTURE(Test
, testNoteContainsNotesInRange
)
5239 m_pDoc
->InsertTab(0, u
"PostIts"_ustr
);
5241 // We need a drawing layer in order to create caption objects.
5242 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5244 ScAddress
aAddr(2, 2, 0); // cell C3
5246 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in a document that doesn't have any.",
5247 !m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5249 m_pDoc
->GetOrCreateNote(aAddr
);
5251 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in range that doesn't have any.",
5252 !m_pDoc
->ContainsNotesInRange(ScRange(ScAddress(0, 0, 0), ScAddress(0, 1, 0))));
5253 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies on border of range.",
5254 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5255 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies in inner area of range.",
5256 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), ScAddress(3, 3, 0)))));
5259 CPPUNIT_TEST_FIXTURE(Test
, testAreasWithNotes
)
5261 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
5263 // We need a drawing layer in order to create caption objects.
5264 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5266 ScAddress
rAddr(1, 5, 0);
5267 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5268 pNote
->SetText(rAddr
, u
"Hello"_ustr
);
5269 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
5270 ScAddress
rAddrMin(2, 2, 0);
5271 ScPostIt
* pNoteMin
= m_pDoc
->GetOrCreateNote(rAddrMin
);
5272 pNoteMin
->SetText(rAddrMin
, u
"Hello"_ustr
);
5278 // only cell notes (empty content)
5280 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5282 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5283 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col for notes", static_cast<SCCOL
>(1), col
);
5284 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row for notes", static_cast<SCROW
>(2), row
);
5286 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5288 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5289 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5290 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row for notes", static_cast<SCROW
>(5), row
);
5293 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5295 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5296 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5297 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row for notes", static_cast<SCROW
>(5), row
);
5300 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5301 CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound
);
5304 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5305 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5306 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(5), row
);
5308 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5309 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5310 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(2), row
);
5312 dataFound
= m_pDoc
->GetPrintAreaVer(0,20,21,row
, bNotes
); // cols 20 & 21
5313 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer found", !dataFound
);
5314 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(0), row
);
5317 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // col 0 & 1
5318 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound
);
5320 // now add cells with value, check that notes are taken into account in good cases
5322 m_pDoc
->SetString(0, 3, 0, u
"Some Text"_ustr
);
5323 m_pDoc
->SetString(3, 3, 0, u
"Some Text"_ustr
);
5325 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5327 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5328 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col", static_cast<SCCOL
>(0), col
);
5329 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row", static_cast<SCROW
>(2), row
);
5331 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5333 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5334 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col", static_cast<SCCOL
>(3), col
);
5335 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row", static_cast<SCROW
>(5), row
);
5338 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5340 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5341 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5342 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(5), row
);
5345 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5346 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5347 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5348 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(3), row
);
5351 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5352 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5353 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(5), row
);
5355 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5356 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5357 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5360 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5361 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5362 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5364 m_pDoc
->DeleteTab(0);
5367 CPPUNIT_TEST_FIXTURE(Test
, testAnchoredRotatedShape
)
5369 m_pDoc
->InsertTab(0, u
"TestTab"_ustr
);
5371 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
5372 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
5373 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
5374 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
5376 m_pDoc
->InitDrawLayer();
5377 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
5378 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
5379 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
5380 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
5381 m_pDoc
->SetRowHeightRange(0, m_pDoc
->MaxRow(), 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5382 constexpr tools::Long TOLERANCE
= 30; //30 hmm
5383 for ( SCCOL nCol
= 0; nCol
< m_pDoc
->MaxCol(); ++nCol
)
5384 m_pDoc
->SetColWidth(nCol
, 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5387 tools::Rectangle
aRect( 4000, 5000, 10000, 7000 );
5389 tools::Rectangle
aRotRect( 6000, 3000, 8000, 9000 );
5390 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aRect
);
5391 pPage
->InsertObject(pObj
.get());
5392 Point
aRef1(pObj
->GetSnapRect().Center());
5393 Degree100 nAngle
= 9000_deg100
; //90 deg.
5394 double nSin
= 1.0; // sin(90 deg)
5395 double nCos
= 0.0; // cos(90 deg)
5396 pObj
->Rotate(aRef1
,nAngle
,nSin
,nCos
);
5398 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
5400 tools::Rectangle aSnap
= pObj
->GetSnapRect();
5401 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5402 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5403 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Left(), aSnap
.Left(), TOLERANCE
);
5404 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Top(), aSnap
.Top(), TOLERANCE
);
5406 ScDrawObjData aAnchor
;
5407 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pObj
.get() );
5408 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
5410 aAnchor
.maStart
= pData
->maStart
;
5411 aAnchor
.maEnd
= pData
->maEnd
;
5413 m_pDoc
->SetDrawPageSize(0);
5415 // increase row 5 by 2000 hmm
5416 m_pDoc
->SetRowHeight(5, 0, o3tl::toTwips(3000, o3tl::Length::mm100
));
5417 // increase col 6 by 1000 hmm
5418 m_pDoc
->SetColWidth(6, 0, o3tl::toTwips(2000, o3tl::Length::mm100
));
5420 aRotRect
.setWidth( aRotRect
.GetWidth() + 1000 );
5421 aRotRect
.setHeight( aRotRect
.GetHeight() + 2000 );
5423 m_pDoc
->SetDrawPageSize(0);
5425 aSnap
= pObj
->GetSnapRect();
5427 // ensure that width and height have been adjusted accordingly
5428 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5429 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5431 // ensure that anchor start and end addresses haven't changed
5432 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Row(), pData
->maStart
.Row() ); // start row 0
5433 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Col(), pData
->maStart
.Col() ); // start column 5
5434 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Row(), pData
->maEnd
.Row() ); // end row 3
5435 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Col(), pData
->maEnd
.Col() ); // end col 7
5437 m_pDoc
->DeleteTab(0);
5440 CPPUNIT_TEST_FIXTURE(Test
, testCellTextWidth
)
5442 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5444 ScAddress
aTopCell(0, 0, 0);
5447 std::unique_ptr
<ScColumnTextWidthIterator
> pIter(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5448 CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter
->hasCell());
5450 // Sheet only has one cell.
5451 m_pDoc
->SetString(0, 0, 0, u
"Only one cell"_ustr
);
5452 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5453 CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter
->hasCell());
5454 CPPUNIT_ASSERT_EQUAL(SCROW(0), pIter
->getPos());
5456 // Setting a text width here should commit it to the column.
5457 sal_uInt16 nTestVal
= 432;
5458 pIter
->setValue(nTestVal
);
5459 CPPUNIT_ASSERT_EQUAL(nTestVal
, m_pDoc
->GetTextWidth(aTopCell
));
5461 // Set values to row 2 through 6.
5462 for (SCROW i
= 2; i
<= 6; ++i
)
5463 m_pDoc
->SetString(0, i
, 0, u
"foo"_ustr
);
5465 // Set values to row 10 through 18.
5466 for (SCROW i
= 10; i
<= 18; ++i
)
5467 m_pDoc
->SetString(0, i
, 0, u
"foo"_ustr
);
5471 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5472 SCROW aRows
[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
5473 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5475 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5476 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5478 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5482 // Specify start and end rows (6 - 16)
5483 ScAddress aStart
= aTopCell
;
5485 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aStart
, 16));
5486 SCROW aRows
[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
5487 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5489 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5490 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5492 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5495 // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
5496 clearRange(m_pDoc
, ScRange(0, 3, 0, 0, 17, 0));
5499 // Full range again.
5500 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5501 SCROW aRows
[] = { 0, 2, 18 };
5502 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5504 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5505 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5507 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5510 // Delete row 2 which shifts all cells below row 2 upward. After this, we
5511 // should only have cells at rows 0 and 17.
5512 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), MAXTAB
, 2, 1);
5514 // Full range again.
5515 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5516 SCROW aRows
[] = { 0, 17 };
5517 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5519 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5520 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5522 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5525 m_pDoc
->DeleteTab(0);
5528 static bool checkEditTextIterator(sc::EditTextIterator
& rIter
, const char** pChecks
)
5530 const EditTextObject
* pText
= rIter
.first();
5531 const char* p
= *pChecks
;
5533 for (int i
= 0; i
< 100; ++i
) // cap it to 100 loops.
5536 // No more edit cells. The check string array should end too.
5537 return p
== nullptr;
5540 // More edit cell, but no more check string. Bad.
5543 if (pText
->GetParagraphCount() != 1)
5544 // For this test, we don't handle multi-paragraph text.
5547 if (pText
->GetText(0) != OUString::createFromAscii(p
))
5548 // Text differs from what's expected.
5551 pText
= rIter
.next();
5559 CPPUNIT_TEST_FIXTURE(Test
, testEditTextIterator
)
5561 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5564 // First, try with an empty sheet.
5565 sc::EditTextIterator
aIter(*m_pDoc
,0);
5566 const char* pChecks
[] = { nullptr };
5567 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5570 ScFieldEditEngine
& rEditEngine
= m_pDoc
->GetEditEngine();
5573 // Only set one edit cell.
5574 rEditEngine
.SetTextCurrentDefaults(u
"A2"_ustr
);
5575 m_pDoc
->SetEditText(ScAddress(0,1,0), rEditEngine
.CreateTextObject());
5576 sc::EditTextIterator
aIter(*m_pDoc
,0);
5577 const char* pChecks
[] = { "A2", nullptr };
5578 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5582 // Add a series of edit cells.
5583 rEditEngine
.SetTextCurrentDefaults(u
"A5"_ustr
);
5584 m_pDoc
->SetEditText(ScAddress(0,4,0), rEditEngine
.CreateTextObject());
5585 rEditEngine
.SetTextCurrentDefaults(u
"A6"_ustr
);
5586 m_pDoc
->SetEditText(ScAddress(0,5,0), rEditEngine
.CreateTextObject());
5587 rEditEngine
.SetTextCurrentDefaults(u
"A7"_ustr
);
5588 m_pDoc
->SetEditText(ScAddress(0,6,0), rEditEngine
.CreateTextObject());
5589 sc::EditTextIterator
aIter(*m_pDoc
,0);
5590 const char* pChecks
[] = { "A2", "A5", "A6", "A7", nullptr };
5591 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5595 // Add more edit cells to column C. Skip column B.
5596 rEditEngine
.SetTextCurrentDefaults(u
"C1"_ustr
);
5597 m_pDoc
->SetEditText(ScAddress(2,0,0), rEditEngine
.CreateTextObject());
5598 rEditEngine
.SetTextCurrentDefaults(u
"C3"_ustr
);
5599 m_pDoc
->SetEditText(ScAddress(2,2,0), rEditEngine
.CreateTextObject());
5600 rEditEngine
.SetTextCurrentDefaults(u
"C4"_ustr
);
5601 m_pDoc
->SetEditText(ScAddress(2,3,0), rEditEngine
.CreateTextObject());
5602 sc::EditTextIterator
aIter(*m_pDoc
,0);
5603 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5604 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5608 // Add some numeric, string and formula cells. This shouldn't affect the outcome.
5609 m_pDoc
->SetString(ScAddress(0,99,0), u
"=ROW()"_ustr
);
5610 m_pDoc
->SetValue(ScAddress(1,3,0), 1.2);
5611 m_pDoc
->SetString(ScAddress(2,4,0), u
"Simple string"_ustr
);
5612 sc::EditTextIterator
aIter(*m_pDoc
,0);
5613 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5614 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5617 m_pDoc
->DeleteTab(0);
5620 CPPUNIT_TEST_FIXTURE(Test
, testImportStream
)
5622 sc::AutoCalcSwitch
aAC(*m_pDoc
, true); // turn on auto calc.
5623 sc::UndoSwitch
aUndo(*m_pDoc
, true); // enable undo.
5625 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5627 m_pDoc
->SetString(ScAddress(0,1,0), u
"=SUM(A1:C1)"_ustr
); // A2
5629 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5631 // CSV import options.
5632 ScAsciiOptions aOpt
;
5633 aOpt
.SetFieldSeps(u
","_ustr
);
5635 // Import values to A1:C1.
5636 ScImportExport
aObj(*m_pDoc
, ScAddress(0,0,0));
5637 aObj
.SetImportBroadcast(true);
5638 aObj
.SetExtOptions(aOpt
);
5639 aObj
.ImportString(u
"1,2,3"_ustr
, SotClipboardFormatId::STRING
);
5641 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5642 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5643 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5645 // Formula value should have been updated.
5646 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5648 // Undo, and check the result.
5649 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5650 CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr
);
5653 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5654 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5655 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5657 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5659 // Redo, and check the result.
5662 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5663 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5664 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5666 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5670 m_pDoc
->DeleteTab(0);
5673 CPPUNIT_TEST_FIXTURE(Test
, testDeleteContents
)
5675 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
5676 sc::UndoSwitch
aUndoSwitch(*m_pDoc
, true); // enable undo.
5678 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5680 m_pDoc
->SetValue(ScAddress(3,1,0), 1.0);
5681 m_pDoc
->SetValue(ScAddress(3,2,0), 1.0);
5682 m_pDoc
->SetValue(ScAddress(3,3,0), 1.0);
5683 m_pDoc
->SetValue(ScAddress(3,4,0), 1.0);
5684 m_pDoc
->SetValue(ScAddress(3,5,0), 1.0);
5685 m_pDoc
->SetValue(ScAddress(3,6,0), 1.0);
5686 m_pDoc
->SetValue(ScAddress(3,7,0), 1.0);
5687 m_pDoc
->SetValue(ScAddress(3,8,0), 1.0);
5688 m_pDoc
->SetString(ScAddress(3,15,0), u
"=SUM(D2:D15)"_ustr
);
5690 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5693 ScRange
aRange(3,1,0,3,5,0);
5694 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5695 aMark
.SelectOneTable(0);
5696 aMark
.SetMarkArea(aRange
);
5698 ScDocumentUniquePtr
pUndoDoc(new ScDocument(SCDOCMODE_UNDO
));
5699 pUndoDoc
->InitUndo(*m_pDoc
, 0, 0);
5700 m_pDoc
->CopyToDocument(aRange
, InsertDeleteFlags::CONTENTS
, false, *pUndoDoc
, &aMark
);
5701 ScUndoDeleteContents
aUndo(m_xDocShell
.get(), aMark
, aRange
, std::move(pUndoDoc
), false, InsertDeleteFlags::CONTENTS
, true);
5703 clearRange(m_pDoc
, aRange
);
5704 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5707 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5710 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5712 m_pDoc
->DeleteTab(0);
5715 CPPUNIT_TEST_FIXTURE(Test
, testTransliterateText
)
5717 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5719 // Set texts to A1:A3.
5720 m_pDoc
->SetString(ScAddress(0,0,0), u
"Mike"_ustr
);
5721 m_pDoc
->SetString(ScAddress(0,1,0), u
"Noah"_ustr
);
5722 m_pDoc
->SetString(ScAddress(0,2,0), u
"Oscar"_ustr
);
5724 // Change them to uppercase.
5725 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5726 aMark
.SetMarkArea(ScRange(0,0,0,0,2,0));
5727 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5728 rFunc
.TransliterateText(
5729 aMark
, TransliterationFlags::LOWERCASE_UPPERCASE
, true);
5731 CPPUNIT_ASSERT_EQUAL(u
"MIKE"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
5732 CPPUNIT_ASSERT_EQUAL(u
"NOAH"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
5733 CPPUNIT_ASSERT_EQUAL(u
"OSCAR"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
5735 // Test the undo and redo.
5736 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5737 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
5740 CPPUNIT_ASSERT_EQUAL(u
"Mike"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
5741 CPPUNIT_ASSERT_EQUAL(u
"Noah"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
5742 CPPUNIT_ASSERT_EQUAL(u
"Oscar"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
5745 CPPUNIT_ASSERT_EQUAL(u
"MIKE"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
5746 CPPUNIT_ASSERT_EQUAL(u
"NOAH"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
5747 CPPUNIT_ASSERT_EQUAL(u
"OSCAR"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
5749 m_pDoc
->DeleteTab(0);
5752 CPPUNIT_TEST_FIXTURE(Test
, testFormulaToValue
)
5754 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5755 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5757 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5759 std::vector
<std::vector
<const char*>> aData
= {
5760 { "=1", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5761 { "=2", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5762 { "=3", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5763 { "=4", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5764 { "=5", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5765 { "=6", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5768 ScAddress
aPos(1,2,0); // B3
5769 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5770 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
5773 // Expected output table content. 0 = empty cell
5774 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5775 { "1", "2", "TRUE" },
5776 { "2", "4", "TRUE" },
5777 { "3", "6", "TRUE" },
5778 { "4", "8", "TRUE" },
5779 { "5", "10", "TRUE" },
5780 { "6", "12", "TRUE" },
5783 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5784 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5787 // Convert B5:C6 to static values, and check the result.
5788 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5789 ScRange
aConvRange(1,4,0,2,5,0); // B5:C6
5790 rFunc
.ConvertFormulaToValue(aConvRange
, false);
5793 // Expected output table content. 0 = empty cell
5794 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5795 { "1", "2", "TRUE" },
5796 { "2", "4", "TRUE" },
5797 { "3", "6", "FALSE" },
5798 { "4", "8", "FALSE" },
5799 { "5", "10", "TRUE" },
5800 { "6", "12", "TRUE" },
5803 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5804 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5807 // Make sure that B3:B4 and B7:B8 are formula cells.
5808 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5809 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5810 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5811 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5813 // Make sure that B5:C6 are numeric cells.
5814 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5815 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5816 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5817 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5819 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5820 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5821 CPPUNIT_ASSERT(pFC
);
5822 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5823 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5824 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5825 CPPUNIT_ASSERT(pFC
);
5826 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5827 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5830 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5831 CPPUNIT_ASSERT(pUndoMgr
);
5835 // Expected output table content. 0 = empty cell
5836 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5837 { "1", "2", "TRUE" },
5838 { "2", "4", "TRUE" },
5839 { "3", "6", "TRUE" },
5840 { "4", "8", "TRUE" },
5841 { "5", "10", "TRUE" },
5842 { "6", "12", "TRUE" },
5845 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "After undo");
5846 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5849 // B3:B8 should all be (ungrouped) formula cells.
5850 for (SCROW i
= 2; i
<= 7; ++i
)
5852 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,i
,0));
5853 CPPUNIT_ASSERT(pFC
);
5854 CPPUNIT_ASSERT(!pFC
->IsShared());
5857 // C3:C8 should be shared formula cells.
5858 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5859 CPPUNIT_ASSERT(pFC
);
5860 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5861 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedLength());
5866 // Expected output table content. 0 = empty cell
5867 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5868 { "1", "2", "TRUE" },
5869 { "2", "4", "TRUE" },
5870 { "3", "6", "FALSE" },
5871 { "4", "8", "FALSE" },
5872 { "5", "10", "TRUE" },
5873 { "6", "12", "TRUE" },
5876 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5877 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5880 // Make sure that B3:B4 and B7:B8 are formula cells.
5881 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5882 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5883 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5884 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5886 // Make sure that B5:C6 are numeric cells.
5887 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5888 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5889 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5890 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5892 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5893 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5894 CPPUNIT_ASSERT(pFC
);
5895 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5896 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5897 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5898 CPPUNIT_ASSERT(pFC
);
5899 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5900 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5902 // Undo again and make sure the recovered formulas in C5:C6 still track B5:B6.
5904 m_pDoc
->SetValue(ScAddress(1,4,0), 10);
5905 m_pDoc
->SetValue(ScAddress(1,5,0), 11);
5906 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
5907 CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc
->GetValue(ScAddress(2,5,0)));
5909 m_pDoc
->DeleteTab(0);
5912 CPPUNIT_TEST_FIXTURE(Test
, testFormulaToValue2
)
5914 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5915 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5917 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5919 std::vector
<std::vector
<const char*>> aData
= {
5920 { "=1", "=ISFORMULA(RC[-1])" },
5921 { "=2", "=ISFORMULA(RC[-1])" },
5922 { "3", "=ISFORMULA(RC[-1])" },
5923 { "=4", "=ISFORMULA(RC[-1])" },
5924 { "=5", "=ISFORMULA(RC[-1])" },
5927 // Insert data into B2:C6.
5928 ScAddress
aPos(1,1,0); // B2
5929 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5930 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
5933 // Expected output table content. 0 = empty cell
5934 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5942 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5943 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5946 // Convert B3:B5 to a value.
5947 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5948 ScRange
aConvRange(1,2,0,1,4,0); // B3:B5
5949 rFunc
.ConvertFormulaToValue(aConvRange
, false);
5952 // Expected output table content. 0 = empty cell
5953 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5961 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5962 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5966 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5967 CPPUNIT_ASSERT(pUndoMgr
);
5971 // Expected output table content. 0 = empty cell
5972 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5980 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5981 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5984 m_pDoc
->DeleteTab(0);
5987 CPPUNIT_TEST_FIXTURE(Test
, testColumnFindEditCells
)
5989 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5991 // Test the basics with real edit cells, using Column A.
5993 SCROW nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
5994 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
5995 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,0,0));
5996 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
5997 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,10,0));
5998 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6000 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
6001 rEE
.SetTextCurrentDefaults(u
"Test"_ustr
);
6002 m_pDoc
->SetEditText(ScAddress(0,0,0), rEE
.CreateTextObject());
6003 const EditTextObject
* pObj
= m_pDoc
->GetEditText(ScAddress(0,0,0));
6004 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell here.", pObj
);
6006 ScRange
aRange(0,0,0,0,0,0);
6007 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6008 CPPUNIT_ASSERT_EQUAL_MESSAGE("There is an edit cell here.", SCROW(0), nResRow
);
6010 aRange
.aStart
.SetRow(1);
6011 aRange
.aEnd
.SetRow(1);
6012 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6013 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6015 aRange
.aStart
.SetRow(2);
6016 aRange
.aEnd
.SetRow(4);
6017 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6018 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6020 aRange
.aStart
.SetRow(0);
6021 aRange
.aEnd
.SetRow(m_pDoc
->MaxRow());
6022 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6023 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an edit cell in specified range.", SCROW(0), nResRow
);
6025 m_pDoc
->SetString(ScAddress(0,0,0), u
"Test"_ustr
);
6026 m_pDoc
->SetValue(ScAddress(0,2,0), 1.0);
6027 ScRefCellValue aCell
;
6028 aCell
.assign(*m_pDoc
, ScAddress(0,0,0));
6029 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a string cell.", CELLTYPE_STRING
, aCell
.getType());
6030 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
6031 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6032 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
6033 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a numeric cell.", CELLTYPE_VALUE
, aCell
.getType());
6034 aCell
.assign(*m_pDoc
, ScAddress(0,3,0));
6035 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6037 aRange
.aStart
.SetRow(1);
6038 aRange
.aEnd
.SetRow(1);
6039 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6040 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6042 // Test with non-edit cell but with ambiguous script type.
6044 m_pDoc
->SetString(ScAddress(1,11,0), u
"Some text"_ustr
);
6045 m_pDoc
->SetString(ScAddress(1,12,0), u
"Some text"_ustr
);
6046 m_pDoc
->SetString(ScAddress(1,13,0), u
"Other text"_ustr
);
6048 m_pDoc
->SetScriptType(ScAddress(1,11,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6049 m_pDoc
->SetScriptType(ScAddress(1,12,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6050 m_pDoc
->SetScriptType(ScAddress(1,13,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6052 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(1,11,0));
6053 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(11), nResRow
);
6054 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(1,12,0));
6055 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), nResRow
);
6057 for (SCROW i
= 0; i
<= 5; ++i
)
6058 m_pDoc
->SetString(ScAddress(2,i
,0), u
"Text"_ustr
);
6060 m_pDoc
->SetScriptType(ScAddress(2,5,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6062 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(2,1,0));
6063 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(-1), nResRow
);
6065 m_pDoc
->DeleteTab(0);
6069 CPPUNIT_TEST_FIXTURE(Test
, testSetFormula
)
6071 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6073 static struct aInputs
6077 const char* aFormula1
; // Represents the formula that is input to SetFormula function.
6078 const char* aFormula2
; // Represents the formula that is actually stored in the cell.
6079 formula::FormulaGrammar::Grammar
const eGram
;
6082 { 5 , 4 , "=SUM($D$2:$F$3)" ,"=SUM($D$2:$F$3)" , formula::FormulaGrammar::Grammar::GRAM_ENGLISH
},
6083 { 5 , 5 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE
},
6084 { 6 , 6 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE_XL_A1
},
6085 { 7 , 8 , "=[.A1]-[.$C2]+[.G$3]-[.$F$4]","=A1-$C2+G$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_ODFF
}
6088 for(size_t i
= 0; i
< SAL_N_ELEMENTS(aTest
); ++i
)
6090 m_pDoc
->SetFormula(ScAddress(aTest
[i
].nCol
, aTest
[i
].nRow
, 0), OUString::createFromAscii(aTest
[i
].aFormula1
), aTest
[i
].eGram
);
6091 OUString aBuffer
= m_pDoc
->GetFormula(aTest
[i
].nCol
, aTest
[i
].nRow
, 0);
6093 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to set formula", OUString::createFromAscii(aTest
[i
].aFormula2
), aBuffer
);
6096 m_pDoc
->DeleteTab(0);
6099 CPPUNIT_TEST_FIXTURE(Test
, testMultipleDataCellsInRange
)
6101 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6103 ScRange
aRange(1,2,0); // B3
6104 sc::MultiDataCellState aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6105 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::Empty
, aState
.meState
);
6107 // Set a numeric value to B3.
6108 m_pDoc
->SetValue(ScAddress(1,2,0), 1.0);
6109 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6110 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6111 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6112 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6114 // Set another numeric value to B4.
6115 m_pDoc
->SetValue(ScAddress(1,3,0), 2.0);
6116 aRange
.aEnd
.SetRow(3); // B3:B4
6117 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6118 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6119 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6120 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6122 // Set the query range to B4:B5. Now it should only report one cell, with
6123 // B4 being the first non-empty cell.
6124 aRange
.aStart
.SetRow(3);
6125 aRange
.aEnd
.SetRow(4);
6126 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6127 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6128 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6129 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6131 // Set the query range to A1:C3. The first non-empty cell should be B3.
6132 aRange
= ScRange(0,0,0,2,2,0);
6133 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6134 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6135 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6136 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6138 // Set string cells to D4 and F5, and query D3:F5. D4 should be the first
6140 m_pDoc
->SetString(ScAddress(3,3,0), u
"foo"_ustr
);
6141 m_pDoc
->SetString(ScAddress(5,4,0), u
"bar"_ustr
);
6142 aRange
= ScRange(3,2,0,5,4,0);
6143 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6144 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6145 CPPUNIT_ASSERT_EQUAL(SCCOL(3), aState
.mnCol1
);
6146 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6148 // TODO : add more test cases as needed.
6150 m_pDoc
->DeleteTab(0);
6153 CPPUNIT_TEST_FIXTURE(Test
, testFormulaWizardSubformula
)
6155 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6157 m_pDoc
->SetString(ScAddress(1,0,0), u
"=1"_ustr
); // B1
6158 m_pDoc
->SetString(ScAddress(1,1,0), u
"=1/0"_ustr
); // B2
6159 m_pDoc
->SetString(ScAddress(1,2,0), u
"=gibberish"_ustr
); // B3
6161 ScSimpleFormulaCalculator
aFCell1( *m_pDoc
, ScAddress(0,0,0), u
"=B1:B3"_ustr
, true );
6162 FormulaError nErrCode
= aFCell1
.GetErrCode();
6163 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell1
.IsMatrix() );
6164 CPPUNIT_ASSERT_EQUAL( u
"{1|#DIV/0!|#NAME?}"_ustr
, aFCell1
.GetString().getString() );
6166 m_pDoc
->SetString(ScAddress(1,0,0), u
"=NA()"_ustr
); // B1
6167 m_pDoc
->SetString(ScAddress(1,1,0), u
"2"_ustr
); // B2
6168 m_pDoc
->SetString(ScAddress(1,2,0), u
"=1+2"_ustr
); // B3
6169 ScSimpleFormulaCalculator
aFCell2( *m_pDoc
, ScAddress(0,0,0), u
"=B1:B3"_ustr
, true );
6170 nErrCode
= aFCell2
.GetErrCode();
6171 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell2
.IsMatrix() );
6172 CPPUNIT_ASSERT_EQUAL( u
"{#N/A|2|3}"_ustr
, aFCell2
.GetString().getString() );
6174 m_pDoc
->DeleteTab(0);
6177 CPPUNIT_TEST_FIXTURE(Test
, testDiagonalBorders
)
6179 m_pDoc
->InsertTab(0, u
"Diagonal"_ustr
);
6182 const editeng::SvxBorderLine
* pLine
;
6183 const ScPatternAttr
* pPat
;
6185 // diagonal down border
6186 ::editeng::SvxBorderLine
dDownBorderLine(nullptr, 1);
6187 SvxLineItem
dDownLineItem(ATTR_BORDER_TLBR
);
6188 dDownLineItem
.SetLine(&dDownBorderLine
);
6190 // set diagonal down border to cell(A1)
6191 m_pDoc
->ApplyAttr(0, 0, 0, dDownLineItem
);
6194 pPat
= m_pDoc
->GetPattern(aPos
);
6195 CPPUNIT_ASSERT(pPat
);
6197 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6198 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6200 // diagonal up border
6201 ::editeng::SvxBorderLine
dUpBorderLine(nullptr, 1);
6202 SvxLineItem
dUpLineItem(ATTR_BORDER_BLTR
);
6203 dUpLineItem
.SetLine(&dUpBorderLine
);
6205 // set diagonal up border to cell(A2)
6206 m_pDoc
->ApplyAttr(0, 1, 0, dUpLineItem
);
6209 pPat
= m_pDoc
->GetPattern(aPos
);
6210 CPPUNIT_ASSERT(pPat
);
6212 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6213 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6215 // diagonal down and up border in the same cell (A5)
6216 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6217 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6219 // test if both borders are applied successfully in the same cell (A5)
6221 pPat
= m_pDoc
->GetPattern(aPos
);
6222 CPPUNIT_ASSERT(pPat
);
6224 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6225 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6226 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6227 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6229 // test if both borders are removed successfully
6230 dDownLineItem
.SetLine(nullptr);
6231 dUpLineItem
.SetLine(nullptr);
6233 // SetLine(nullptr) should remove the lines from (A5)
6234 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6235 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6237 pPat
= m_pDoc
->GetPattern(aPos
);
6238 CPPUNIT_ASSERT(pPat
);
6240 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6241 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was not expected, but is found!", !pLine
);
6242 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6243 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was not expected, but is found!", !pLine
);
6245 m_pDoc
->DeleteTab(0);
6248 CPPUNIT_TEST_FIXTURE(Test
, testWholeDocBorders
)
6250 m_pDoc
->InsertTab(0, u
"Borders"_ustr
);
6252 // Set outside border to be on all sides, and inside borders to be only vertical.
6253 // This should result in edge borders of the spreadsheets being set, but internal
6254 // borders between cells should be only vertical, not horizontal.
6255 ::editeng::SvxBorderLine
line(nullptr, 50, SvxBorderLineStyle::SOLID
);
6256 SvxBoxItem
borderItem(ATTR_BORDER
);
6257 borderItem
.SetLine(&line
, SvxBoxItemLine::LEFT
);
6258 borderItem
.SetLine(&line
, SvxBoxItemLine::RIGHT
);
6259 borderItem
.SetLine(&line
, SvxBoxItemLine::TOP
);
6260 borderItem
.SetLine(&line
, SvxBoxItemLine::BOTTOM
);
6261 SvxBoxInfoItem
boxInfoItem(ATTR_BORDER
);
6262 boxInfoItem
.SetLine(&line
, SvxBoxInfoItemLine::VERT
);
6264 ScMarkData
mark( m_pDoc
->GetSheetLimits(), ScRange( 0, 0, 0, m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 ));
6265 m_pDoc
->ApplySelectionFrame( mark
, borderItem
, &boxInfoItem
);
6267 const ScPatternAttr
* attr
;
6268 attr
= m_pDoc
->GetPattern( 0, 0, 0 );
6269 CPPUNIT_ASSERT(attr
);
6270 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6271 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6272 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6273 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6275 attr
= m_pDoc
->GetPattern( 1, 0, 0 );
6276 CPPUNIT_ASSERT(attr
);
6277 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6278 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6279 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6280 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6282 attr
= m_pDoc
->GetPattern( 0, 1, 0 );
6283 CPPUNIT_ASSERT(attr
);
6284 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6285 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6286 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6287 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6289 attr
= m_pDoc
->GetPattern( 1, 1, 0 );
6290 CPPUNIT_ASSERT(attr
);
6291 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6292 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6293 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6294 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6296 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), 0, 0 );
6297 CPPUNIT_ASSERT(attr
);
6298 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6299 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6300 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6301 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6303 attr
= m_pDoc
->GetPattern( 0, m_pDoc
->MaxRow(), 0 );
6304 CPPUNIT_ASSERT(attr
);
6305 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6306 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6307 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6308 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6310 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 );
6311 CPPUNIT_ASSERT(attr
);
6312 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6313 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6314 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6315 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6317 m_pDoc
->DeleteTab(0);
6320 CPPUNIT_TEST_FIXTURE(Test
, testSetStringAndNote
)
6322 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6324 // We need a drawing layer in order to create caption objects.
6325 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
6328 ScAddress
aAdrA1 (0, 0, 0);
6329 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
6330 pNote
->SetText(aAdrA1
, u
"Hello world in A1"_ustr
);
6332 m_pDoc
->SetString(0, 0, 0, u
""_ustr
);
6334 pNote
= m_pDoc
->GetNote(aAdrA1
);
6335 CPPUNIT_ASSERT(pNote
);
6337 m_pDoc
->DeleteTab(0);
6340 CPPUNIT_TEST_FIXTURE(Test
, testUndoDataAnchor
)
6342 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
6343 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 1 sheets to begin with",
6344 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
6346 m_pDoc
->InitDrawLayer();
6347 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
6348 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
6349 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
6350 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
6352 // Insert an object.
6353 tools::Rectangle
aObjRect(2,1000,100,1100);
6354 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
6355 pPage
->InsertObject(pObj
.get());
6356 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
6359 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
6360 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6362 ScAddress aOldStart
= pData
->maStart
;
6363 ScAddress aOldEnd
= pData
->maEnd
;
6365 // Get non rotated anchor data
6366 ScDrawObjData
* pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6367 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6369 ScAddress aNOldStart
= pNData
->maStart
;
6370 ScAddress aNOldEnd
= pNData
->maEnd
;
6371 CPPUNIT_ASSERT_EQUAL(aOldStart
, aNOldStart
);
6372 CPPUNIT_ASSERT_EQUAL(aOldEnd
, aNOldEnd
);
6374 //pDrawLayer->BeginCalcUndo(false);
6375 // Insert a new row at row 3.
6376 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
6377 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6378 aMark
.SelectOneTable(0);
6379 rFunc
.InsertCells(ScRange( 0, aOldStart
.Row() - 1, 0, m_pDoc
->MaxCol(), aOldStart
.Row(), 0 ), &aMark
, INS_INSROWS_BEFORE
, true, true);
6381 pData
= ScDrawLayer::GetObjData(pObj
.get());
6382 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6384 ScAddress aNewStart
= pData
->maStart
;
6385 ScAddress aNewEnd
= pData
->maEnd
;
6387 // Get non rotated anchor data
6388 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6389 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6391 ScAddress aNNewStart
= pNData
->maStart
;
6392 ScAddress aNNewEnd
= pNData
->maEnd
;
6393 CPPUNIT_ASSERT_EQUAL(aNewStart
, aNNewStart
);
6394 CPPUNIT_ASSERT_EQUAL(aNewEnd
, aNNewEnd
);
6395 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart
!= aOldStart
);
6396 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewEnd
!= aOldEnd
);
6397 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewStart
!= aNOldStart
);
6398 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewEnd
!= aNOldEnd
);
6400 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6401 CPPUNIT_ASSERT(pUndoMgr
);
6405 ScAnchorType oldType
= ScDrawLayer::GetAnchorType(*pObj
);
6406 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to check state SCA_CELL.", SCA_CELL
, oldType
);
6409 pData
= ScDrawLayer::GetObjData(pObj
.get());
6410 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6412 // Get non rotated anchor data
6413 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6414 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6416 // Check if data has moved to new rows
6417 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aOldStart
);
6418 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aOldEnd
);
6420 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNOldStart
);
6421 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNOldEnd
);
6426 pData
= ScDrawLayer::GetObjData(pObj
.get());
6427 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6429 // Get non rotated anchor data
6430 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6431 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6433 // Check if data has moved to new rows
6434 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aNewStart
);
6435 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aNewEnd
);
6437 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNNewStart
);
6438 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNNewEnd
);
6440 m_pDoc
->DeleteTab(0);
6444 CPPUNIT_TEST_FIXTURE(Test
, testEmptyCalcDocDefaults
)
6446 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCellCount() );
6447 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetFormulaGroupCount() );
6448 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCodeCount() );
6449 CPPUNIT_ASSERT_EQUAL( int(CharCompressType::NONE
), static_cast<int>(m_pDoc
->GetAsianCompression()) );
6451 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasPrintRange() );
6452 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInVBAMode() );
6453 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasNotes() );
6454 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6456 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedFonts() );
6457 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedUsedFontsOnly() );
6458 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptLatin() );
6459 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptAsian() );
6460 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptComplex() );
6461 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedded() );
6463 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDocEditable() );
6464 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocProtected() );
6465 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocVisible() );
6466 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUserInteractionEnabled() );
6468 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasAnyCalcNotification() );
6469 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAutoCalcShellDisabled() );
6470 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsForcedFormulaPending() );
6471 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalculatingFormulaTree() );
6473 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipOrUndo() );
6474 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboard() );
6475 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsUndo() );
6476 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUndoEnabled() );
6477 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6478 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboardSource() );
6479 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInsertingFromOtherDoc() );
6480 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->PastingDrawFromOtherDoc() );
6482 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAdjustHeightLocked() );
6483 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsExecuteLinkEnabled() );
6484 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChangeReadOnlyEnabled() );
6486 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IdleCalcTextWidth() );
6487 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsIdleEnabled() );
6488 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDetectiveDirty() );
6489 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasLinkFormulaNeedingCheck() );
6490 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChartListenerCollectionNeedsUpdate() );
6492 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasRangeOverflow() );
6493 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsImportingXML() );
6494 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalcingAfterLoad() );
6495 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetNoListening() );
6497 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianCompression() );
6498 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetAsianKerning() );
6499 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianKerning() );
6501 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreter() );
6502 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreterTableOp() );
6503 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInDtorClear() );
6504 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsExpandRefs() );
6505 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInLinkUpdate() );
6507 SCTAB tab
= m_pDoc
->GetVisibleTab();
6509 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsVisible(tab
) );
6510 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDefaultTabBgColor(tab
) );
6511 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasTable(tab
) );
6513 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsActiveScenario(tab
) );
6514 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasCalcNotification(tab
) );
6515 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasManualBreaks(tab
) );
6518 void Test::checkPrecisionAsShown( OUString
& rCode
, double fValue
, double fExpectedRoundVal
)
6520 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
6521 sal_uInt32 nFormat
= pFormatter
->GetEntryKey( rCode
);
6522 if ( nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
6524 sal_Int32 nCheckPos
= 0;
6525 SvNumFormatType nType
;
6526 pFormatter
->PutEntry( rCode
, nCheckPos
, nType
, nFormat
);
6527 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), nCheckPos
);
6529 double fRoundValue
= m_pDoc
->RoundValueAsShown( fValue
, nFormat
);
6530 OString aMessage
= "Format \"" +
6531 OUStringToOString( rCode
, RTL_TEXTENCODING_ASCII_US
) +
6532 "\" is not correctly rounded";
6533 CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage
.getStr(), fExpectedRoundVal
, fRoundValue
);
6536 CPPUNIT_TEST_FIXTURE(Test
, testPrecisionAsShown
)
6538 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6540 // Turn on "precision as shown" option.
6541 setCalcAsShown( m_pDoc
, true);
6544 double fValue
, fExpectedRoundVal
;
6545 { // decimal rounding
6548 fExpectedRoundVal
= 0.33;
6549 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6550 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6552 fExpectedRoundVal
= 10.0;
6553 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6554 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6556 { // thousand rounding tdf#106253
6558 fValue
= 4.0e9
/ 7.0;
6559 fExpectedRoundVal
= 571e6
;
6560 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6561 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6562 aCode
= "\"k\"[$$-409]* #,;[RED]-\"k\"[$$-409]* #,";
6563 fValue
= 4.0e8
/ 7.0;
6564 fExpectedRoundVal
= 57.143e6
;
6565 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6566 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6568 { // percent rounding
6571 fExpectedRoundVal
= 0.5714;
6572 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6573 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6574 fValue
= 40.0 / 7.0;
6575 fExpectedRoundVal
= 5.7143;
6576 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6577 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6579 { // scientific rounding
6581 fValue
= 400000.0 / 7.0;
6582 fExpectedRoundVal
= 57100.0;
6583 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6584 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6585 fValue
= 4.0 / 70000.0;
6586 fExpectedRoundVal
= 5.71e-5;
6587 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6588 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6589 // engineering rounding tdf#106252
6590 aCode
= "##0.000E0";
6591 fValue
= 400000.0 / 7.0;
6592 fExpectedRoundVal
= 57.143e3
;
6593 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6594 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6595 fValue
= 4000000.0 / 7.0;
6596 fExpectedRoundVal
= 571.429e3
;
6597 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6598 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6599 fValue
= 40000000.0 / 7.0;
6600 fExpectedRoundVal
= 5.714e6
;
6601 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6602 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6603 fValue
= 4.0 / 70000.0;
6604 fExpectedRoundVal
= 57.143e-6;
6605 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6606 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6607 fValue
= 4.0 / 7000.0;
6608 fExpectedRoundVal
= 571.429e-6;
6609 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6610 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6611 fValue
= 4.0 / 700.0;
6612 fExpectedRoundVal
= 5.714e-3;
6613 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6614 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6615 aCode
= "##?0.0#E0";
6616 fValue
= 400000.0 / 7.0;
6617 fExpectedRoundVal
= 5.71e4
;
6618 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6619 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6620 fValue
= 4000000.0 / 7.0;
6621 fExpectedRoundVal
= 57.14e4
;
6622 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6623 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6624 fValue
= 40000000.0 / 7.0;
6625 fExpectedRoundVal
= 571.43e4
;
6626 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6627 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6628 fValue
= 400000000.0 / 7.0;
6629 fExpectedRoundVal
= 5714.29e4
;
6630 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6631 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6632 fValue
= 4.0 / 70000.0;
6633 fExpectedRoundVal
= 5714.29e-8;
6634 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6635 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6636 fValue
= 4.0 / 7000.0;
6637 fExpectedRoundVal
= 5.71e-4;
6638 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6639 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6640 fValue
= 4.0 / 700.0;
6641 fExpectedRoundVal
= 57.14e-4;
6642 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6643 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6644 fValue
= 4.0 / 70.0;
6645 fExpectedRoundVal
= 571.43e-4;
6646 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6647 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6649 { // fraction rounding tdf#105657
6652 fExpectedRoundVal
= 1.0/3.0;
6653 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6654 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6659 fExpectedRoundVal
= 0.35;
6660 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6661 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6663 { // several sub-formats tdf#106052
6664 aCode
= "0.00;-0.000";
6666 fExpectedRoundVal
= 0.33;
6667 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6669 fExpectedRoundVal
= -0.333;
6670 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6673 setCalcAsShown( m_pDoc
, false);
6674 m_pDoc
->DeleteTab(0);
6677 CPPUNIT_TEST_FIXTURE(Test
, testProtectedSheetEditByRow
)
6679 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6680 m_pDoc
->InsertTab(0, u
"Protected"_ustr
);
6683 // Remove protected flags from rows 2-5.
6684 ScPatternAttr
aAttr(m_pDoc
->getCellAttributeHelper());
6685 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6686 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 4, 0, aAttr
);
6688 // Protect the sheet without any options.
6689 ScTableProtection aProtect
;
6690 aProtect
.setProtected(true);
6691 m_pDoc
->SetTabProtection(0, &aProtect
);
6693 // Try to delete row 3. It should fail.
6694 ScRange
aRow3(0,2,0,m_pDoc
->MaxCol(),2,0);
6695 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6696 aMark
.SelectOneTable(0);
6697 bool bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6698 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should fail.", !bDeleted
);
6700 // Protect the sheet but allow row deletion.
6701 aProtect
.setOption(ScTableProtection::DELETE_ROWS
, true);
6702 m_pDoc
->SetTabProtection(0, &aProtect
);
6704 // Now we should be able to delete row 3.
6705 bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6706 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should succeed.", bDeleted
);
6708 // But, row deletion should still fail on a protected row.
6709 ScRange
aRow10(0,9,0,m_pDoc
->MaxCol(),9,0);
6710 bDeleted
= rDocFunc
.DeleteCells(aRow10
, &aMark
, DelCellCmd::Rows
, true);
6711 CPPUNIT_ASSERT_MESSAGE("deletion of row 10 should not be allowed.", !bDeleted
);
6713 // Try inserting a new row. It should fail.
6714 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6715 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6717 // Allow row insertions.
6718 aProtect
.setOption(ScTableProtection::INSERT_ROWS
, true);
6719 m_pDoc
->SetTabProtection(0, &aProtect
);
6721 bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6722 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should succeed.", bInserted
);
6724 // Row insertion is allowed even when the rows above and below have protected flags set.
6725 bInserted
= rDocFunc
.InsertCells(aRow10
, &aMark
, INS_INSROWS_AFTER
, true, true);
6726 CPPUNIT_ASSERT_MESSAGE("row insertion at row 10 should succeed.", bInserted
);
6729 m_pDoc
->InsertTab(1, u
"Matrix"_ustr
); // This sheet is unprotected.
6732 // Insert matrix into B2:C3.
6733 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6734 aMark
.SelectOneTable(1);
6735 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, u
"={1;2|3;4}"_ustr
);
6737 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6738 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6739 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6740 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6742 // Try to insert a row at row 3. It should fail because of matrix's presence.
6744 ScRange
aRow3(0,2,1,m_pDoc
->MaxCol(),2,1);
6745 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_BEFORE
, true, true);
6746 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6749 m_pDoc
->DeleteTab(1);
6750 m_pDoc
->DeleteTab(0);
6753 CPPUNIT_TEST_FIXTURE(Test
, testProtectedSheetEditByColumn
)
6755 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6756 m_pDoc
->InsertTab(0, u
"Protected"_ustr
);
6759 // Remove protected flags from columns B to E.
6760 ScPatternAttr
aAttr(m_pDoc
->getCellAttributeHelper());
6761 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6762 m_pDoc
->ApplyPatternAreaTab(1, 0, 4, m_pDoc
->MaxRow(), 0, aAttr
);
6764 // Protect the sheet without any options.
6765 ScTableProtection aProtect
;
6766 aProtect
.setProtected(true);
6767 m_pDoc
->SetTabProtection(0, &aProtect
);
6769 // Try to delete column C. It should fail.
6770 ScRange
aCol3(2,0,0,2,m_pDoc
->MaxRow(),0);
6771 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6772 aMark
.SelectOneTable(0);
6773 bool bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6774 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should fail.", !bDeleted
);
6776 // Protect the sheet but allow column deletion.
6777 aProtect
.setOption(ScTableProtection::DELETE_COLUMNS
, true);
6778 m_pDoc
->SetTabProtection(0, &aProtect
);
6780 // Now we should be able to delete column C.
6781 bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6782 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should succeed.", bDeleted
);
6784 // But, column deletion should still fail on a protected column.
6785 ScRange
aCol10(9,0,0,9,m_pDoc
->MaxRow(),0);
6786 bDeleted
= rDocFunc
.DeleteCells(aCol10
, &aMark
, DelCellCmd::Cols
, true);
6787 CPPUNIT_ASSERT_MESSAGE("deletion of column 10 should not be allowed.", !bDeleted
);
6789 // Try inserting a new column. It should fail.
6790 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6791 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should fail.", !bInserted
);
6793 // Allow column insertions.
6794 aProtect
.setOption(ScTableProtection::INSERT_COLUMNS
, true);
6795 m_pDoc
->SetTabProtection(0, &aProtect
);
6797 bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6798 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should succeed.", bInserted
);
6800 // Column insertion is allowed even when the columns above and below have protected flags set.
6801 bInserted
= rDocFunc
.InsertCells(aCol10
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6802 CPPUNIT_ASSERT_MESSAGE("column insertion at column 10 should succeed.", bInserted
);
6805 m_pDoc
->InsertTab(1, u
"Matrix"_ustr
); // This sheet is unprotected.
6808 // Insert matrix into B2:C3.
6809 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6810 aMark
.SelectOneTable(1);
6811 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, u
"={1;2|3;4}"_ustr
);
6813 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6814 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6815 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6816 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6818 // Try to insert a column at column C. It should fail because of matrix's presence.
6820 ScRange
aCol3(2,0,1,2,m_pDoc
->MaxRow(),1);
6821 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_BEFORE
, true, true);
6822 CPPUNIT_ASSERT_MESSAGE("column insertion at column C should fail.", !bInserted
);
6825 m_pDoc
->DeleteTab(1);
6826 m_pDoc
->DeleteTab(0);
6829 CPPUNIT_TEST_FIXTURE(Test
, testInsertColumnsWithFormulaCells
)
6831 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
6833 std::set
<SCCOL
> aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6834 CPPUNIT_ASSERT_MESSAGE("empty sheet should contain no formula cells.", aCols
.empty());
6836 auto equals
= [](const std::set
<SCCOL
>& left
, const std::set
<SCCOL
>& right
)
6838 return left
== right
;
6841 // insert formula cells in columns 2, 4 and 6.
6842 m_pDoc
->SetFormula(ScAddress(2, 2, 0), u
"=1"_ustr
, m_pDoc
->GetGrammar());
6843 m_pDoc
->SetFormula(ScAddress(4, 2, 0), u
"=1"_ustr
, m_pDoc
->GetGrammar());
6844 m_pDoc
->SetFormula(ScAddress(6, 2, 0), u
"=1"_ustr
, m_pDoc
->GetGrammar());
6846 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6848 std::set
<SCCOL
> aExpected
= { 2, 4, 6 };
6849 CPPUNIT_ASSERT_MESSAGE("Columns 2, 4 and 6 should contain formula cells.", equals(aExpected
, aCols
));
6851 // Insert 2 columns at column A to shift everything to right by 2.
6852 m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 0, 2);
6854 aExpected
= { 4, 6, 8 };
6855 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6856 CPPUNIT_ASSERT_MESSAGE("Columns 4, 6 and 8 should contain formula cells.", equals(aExpected
, aCols
));
6860 m_pDoc
->CheckIntegrity(0);
6862 catch (const std::exception
& e
)
6864 std::ostringstream os
;
6865 os
<< "document integrity check failed: " << e
.what();
6866 CPPUNIT_FAIL(os
.str());
6869 m_pDoc
->DeleteTab(0);
6872 CPPUNIT_TEST_FIXTURE(Test
, testDocumentModelAccessor_getDocumentCurrencies
)
6874 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
6876 // Check document currencies - expect 0
6877 auto pAccessor
= m_xDocShell
->GetDocumentModelAccessor();
6878 CPPUNIT_ASSERT(pAccessor
);
6879 CPPUNIT_ASSERT_EQUAL(size_t(0), pAccessor
->getDocumentCurrencies().size());
6881 // Set a currency to a cell
6883 m_pDoc
->SetValue(ScAddress(0, 0, 0), 2.0);
6885 OUString aCode
= u
"#.##0,00[$€-424]"_ustr
;
6887 sal_Int32 nCheckPos
;
6888 SvNumFormatType eType
;
6891 m_pDoc
->GetFormatTable()->PutEntry(aCode
, nCheckPos
, eType
, nFormat
, LANGUAGE_SLOVENIAN
);
6892 CPPUNIT_ASSERT_EQUAL(SvNumFormatType::CURRENCY
, eType
);
6894 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
6895 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
6896 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
6897 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
); // A1.
6899 CPPUNIT_ASSERT_EQUAL(u
"2,00€"_ustr
, m_pDoc
->GetString(ScAddress(0, 0, 0)));
6902 // Check document currencies again
6903 auto aCurrencyIDs
= pAccessor
->getDocumentCurrencies();
6904 CPPUNIT_ASSERT_EQUAL(size_t(1), aCurrencyIDs
.size());
6906 CPPUNIT_ASSERT_EQUAL(LANGUAGE_SLOVENIAN
, aCurrencyIDs
[0].eLanguage
);
6907 CPPUNIT_ASSERT_EQUAL(u
"-424"_ustr
, aCurrencyIDs
[0].aExtension
);
6908 CPPUNIT_ASSERT_EQUAL(u
"€"_ustr
, aCurrencyIDs
[0].aSymbol
);
6910 // Set the same currency to 2 more cells
6912 m_pDoc
->SetValue(ScAddress(1, 1, 0), 5.0);
6913 m_pDoc
->SetValue(ScAddress(2, 2, 0), 7.0);
6915 OUString aCode
= u
"#.##0,00[$€-424]"_ustr
;
6917 sal_Int32 nCheckPos
;
6918 SvNumFormatType eType
;
6921 m_pDoc
->GetFormatTable()->PutEntry(aCode
, nCheckPos
, eType
, nFormat
, LANGUAGE_SLOVENIAN
);
6922 CPPUNIT_ASSERT_EQUAL(SvNumFormatType::CURRENCY
, eType
);
6924 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
6925 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
6926 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
6927 m_pDoc
->ApplyPattern(1, 1, 0, aNewAttrs
); // B2.
6928 m_pDoc
->ApplyPattern(2, 2, 0, aNewAttrs
); // C3.
6930 CPPUNIT_ASSERT_EQUAL(u
"5,00€"_ustr
, m_pDoc
->GetString(ScAddress(1, 1, 0)));
6931 CPPUNIT_ASSERT_EQUAL(u
"7,00€"_ustr
, m_pDoc
->GetString(ScAddress(2, 2, 0)));
6934 // Check document currencies again - should be 1 entry only
6935 aCurrencyIDs
= pAccessor
->getDocumentCurrencies();
6936 CPPUNIT_ASSERT_EQUAL(size_t(1), aCurrencyIDs
.size());
6938 CPPUNIT_ASSERT_EQUAL(LANGUAGE_SLOVENIAN
, aCurrencyIDs
[0].eLanguage
);
6939 CPPUNIT_ASSERT_EQUAL(u
"-424"_ustr
, aCurrencyIDs
[0].aExtension
);
6940 CPPUNIT_ASSERT_EQUAL(u
"€"_ustr
, aCurrencyIDs
[0].aSymbol
);
6944 CPPUNIT_PLUGIN_IMPLEMENT();
6946 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */