1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #include <memory>
11 #include "ucalc.hxx"
12 #include "helper/qahelper.hxx"
13 
14 #include <conditio.hxx>
15 #include <colorscale.hxx>
16 
17 #include <clipparam.hxx>
18 #include <globstr.hrc>
19 #include <scresid.hxx>
20 #include <docfunc.hxx>
21 #include <scitems.hxx>
22 #include <attrib.hxx>
23 #include <fillinfo.hxx>
24 #include <compiler.hxx>
25 #include <tokenarray.hxx>
26 
27 #include <svl/sharedstringpool.hxx>
28 
testCopyPasteSkipEmptyConditionalFormatting()29 void Test::testCopyPasteSkipEmptyConditionalFormatting()
30 {
31     m_pDoc->InsertTab(0, "Test");
32 
33     ScRange aDestRange(0,0,0,1,2,0);
34     ScRange aSrcRange(3,3,0,5,4,0);
35 
36     ScMarkData aMark(MAXROW, MAXCOL);
37     aMark.SetMarkArea(aDestRange);
38 
39     m_pDoc->SetValue(0,0,0,1);
40     m_pDoc->SetValue(1,0,0,1);
41     m_pDoc->SetValue(0,1,0,1);
42     m_pDoc->SetValue(0,2,0,1);
43     m_pDoc->SetValue(1,2,0,1);
44 
45     //create conditional formatting for A1:B3
46     ScConditionalFormatList* pCondFormatList = new ScConditionalFormatList();
47     m_pDoc->SetCondFormList(pCondFormatList, 0);
48 
49     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
50     pFormat->SetRange(aDestRange);
51     sal_uLong nCondFormatKey = m_pDoc->AddCondFormat(std::move(pFormat), 0);
52 
53     // Prepare a clipboard content interleaved with empty cells.
54     ScDocument aClipDoc(SCDOCMODE_CLIP);
55     aClipDoc.ResetClip(m_pDoc, &aMark);
56     ScClipParam aParam(aSrcRange, false);
57     aClipDoc.SetClipParam(aParam);
58     aClipDoc.SetValue(3,3,0,2);
59     aClipDoc.SetValue(4,3,0,2);
60     aClipDoc.SetValue(4,4,0,2);
61     aClipDoc.SetValue(3,5,0,2);
62     aClipDoc.SetValue(4,5,0,2);
63 
64     auto pClipFormat = std::make_unique<ScConditionalFormat>(2, &aClipDoc);
65     pClipFormat->SetRange(aSrcRange);
66     aClipDoc.AddCondFormat(std::move(pClipFormat), 0);
67 
68     // Create undo document.
69     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
70     pUndoDoc->InitUndo(m_pDoc, 0, 0);
71     m_pDoc->CopyToDocument(aDestRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc, &aMark);
72 
73     // Paste clipboard content onto A1:A5 but skip empty cells.
74     m_pDoc->CopyFromClip(aDestRange, aMark, InsertDeleteFlags::CONTENTS, pUndoDoc, &aClipDoc, true, false, false, true/*bSkipEmpty*/);
75 
76     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
77     CPPUNIT_ASSERT_EQUAL(size_t(2), pList->size());
78     CPPUNIT_ASSERT(m_pDoc->GetCondFormat(1,1,0));
79     // empty cell in copy area does not overwrite conditional formatting
80     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nCondFormatKey), m_pDoc->GetCondFormat(1,1,0)->GetKey());
81     for(SCCOL nCol = 0; nCol <= 1; ++nCol)
82     {
83         for(SCROW nRow = 0; nRow <= 2; ++nRow)
84         {
85             if(nRow == 1 && nCol == 1)
86                 continue;
87 
88             CPPUNIT_ASSERT(m_pDoc->GetCondFormat(nCol, nRow, 0));
89             CPPUNIT_ASSERT(nCondFormatKey != m_pDoc->GetCondFormat(nCol, nRow, 0)->GetKey());
90         }
91     }
92     m_pDoc->DeleteTab(0);
93 }
94 
testCondFormatINSDEL()95 void Test::testCondFormatINSDEL()
96 {
97     // fdo#62206
98     m_pDoc->InsertTab(0, "Test");
99     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
100 
101     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
102     ScRangeList aRangeList(ScRange(0,0,0,0,3,0));
103     pFormat->SetRange(aRangeList);
104     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
105     pFormat->AddEntry(pEntry);
106 
107     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
108     auto pFormatTmp = pFormat.get();
109     pList->InsertNew(std::move(pFormat));
110 
111     m_pDoc->InsertCol(0,0,MAXROW,0,0,2);
112     const ScRangeList& rRange = pFormatTmp->GetRange();
113     CPPUNIT_ASSERT_EQUAL(static_cast<const ScRangeList&>(ScRange(2,0,0,2,3,0)), rRange);
114 
115     OUString aExpr = pEntry->GetExpression(ScAddress(2,0,0), 0);
116     CPPUNIT_ASSERT_EQUAL(OUString("D2"), aExpr);
117 
118     m_pDoc->DeleteTab(0);
119 }
120 
testCondFormatInsertCol()121 void Test::testCondFormatInsertCol()
122 {
123     m_pDoc->InsertTab(0, "Test");
124     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
125 
126     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
127     ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
128     pFormat->SetRange(aRangeList);
129 
130     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
131     pFormat->AddEntry(pEntry);
132 
133     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
134     auto pFormatTmp = pFormat.get();
135     pList->InsertNew(std::move(pFormat));
136 
137     m_pDoc->InsertCol(0,0,MAXROW,0,4,2);
138     const ScRangeList& rRange = pFormatTmp->GetRange();
139     CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,5,3,0)), rRange);
140 
141     m_pDoc->DeleteTab(0);
142 }
143 
testCondFormatInsertRow()144 void Test::testCondFormatInsertRow()
145 {
146     m_pDoc->InsertTab(0, "Test");
147     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
148 
149     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
150     ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
151     pFormat->SetRange(aRangeList);
152 
153     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
154     pFormat->AddEntry(pEntry);
155 
156     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
157     auto pFormatTmp = pFormat.get();
158     pList->InsertNew(std::move(pFormat));
159 
160     m_pDoc->InsertRow(0,0,MAXCOL,0,4,2);
161     const ScRangeList& rRange = pFormatTmp->GetRange();
162     CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,3,5,0)), rRange);
163 
164     m_pDoc->DeleteTab(0);
165 }
166 
testCondFormatInsertDeleteSheets()167 void Test::testCondFormatInsertDeleteSheets()
168 {
169     m_pDoc->InsertTab(0, "Test");
170 
171     // Add a conditional format to B2:B4.
172     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
173     pFormat->SetRange(ScRange(1,1,0,1,3,0));
174 
175     auto pFormatTmp = pFormat.get();
176     sal_uLong nKey = m_pDoc->AddCondFormat(std::move(pFormat), 0);
177 
178     // Add condition in which if the value equals 2, set the "Result" style.
179     ScCondFormatEntry* pEntry = new ScCondFormatEntry(
180         ScConditionMode::Equal, "=2", "" , m_pDoc, ScAddress(0,0,0), ScResId(STR_STYLENAME_RESULT));
181     pFormatTmp->AddEntry(pEntry);
182 
183     // Apply the format to the range.
184     m_pDoc->AddCondFormatData(pFormatTmp->GetRange(), 0, nKey);
185 
186     // Make sure this conditional format entry is really there.
187     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
188     CPPUNIT_ASSERT(pList);
189     const ScConditionalFormat* pCheck = pList->GetFormat(nKey);
190     CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong conditional format instance.", pCheck, const_cast<const ScConditionalFormat*>(pFormatTmp));
191 
192     // ... and its range is B2:B4.
193     ScRangeList aCheckRange = pCheck->GetRange();
194     CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
195     const ScRange* pRange = &aCheckRange[0];
196     CPPUNIT_ASSERT(pRange);
197     CPPUNIT_ASSERT_EQUAL_MESSAGE("Format should be applied to B2:B4.", ScRange(1,1,0,1,3,0), *pRange);
198 
199     ScDocFunc& rFunc = getDocShell().GetDocFunc();
200 
201     // Insert a new sheet at the left.
202     bool bInserted = rFunc.InsertTable(0, "Inserted", true, true);
203     CPPUNIT_ASSERT(bInserted);
204 
205     pList = m_pDoc->GetCondFormList(1);
206     CPPUNIT_ASSERT(pList);
207     pCheck = pList->GetFormat(nKey);
208     CPPUNIT_ASSERT(pCheck);
209 
210     // Make sure the range also got shifted.
211     aCheckRange = pCheck->GetRange();
212     CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
213     pRange = &aCheckRange[0];
214     CPPUNIT_ASSERT(pRange);
215     CPPUNIT_ASSERT_EQUAL_MESSAGE("Format should be applied to B2:B4 on the 2nd sheet after the sheet insertion.", ScRange(1,1,1,1,3,1), *pRange);
216 
217     // Delete the sheet to the left.
218     bool bDeleted = rFunc.DeleteTable(0, true);
219     CPPUNIT_ASSERT(bDeleted);
220 
221     pList = m_pDoc->GetCondFormList(0);
222     CPPUNIT_ASSERT(pList);
223     pCheck = pList->GetFormat(nKey);
224     CPPUNIT_ASSERT(pCheck);
225 
226     // Make sure the range got shifted back.
227     aCheckRange = pCheck->GetRange();
228     CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
229     pRange = &aCheckRange[0];
230     CPPUNIT_ASSERT(pRange);
231     CPPUNIT_ASSERT_EQUAL_MESSAGE("Format should be applied to B2:B4 on the 1st sheet after the sheet removal.", ScRange(1,1,0,1,3,0), *pRange);
232 
233     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
234     CPPUNIT_ASSERT(pUndoMgr);
235 
236     // Undo and re-check.
237     pUndoMgr->Undo();
238 
239     pList = m_pDoc->GetCondFormList(1);
240     CPPUNIT_ASSERT(pList);
241     pCheck = pList->GetFormat(nKey);
242     CPPUNIT_ASSERT(pCheck);
243 
244     aCheckRange = pCheck->GetRange();
245     CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
246     pRange = &aCheckRange[0];
247     CPPUNIT_ASSERT(pRange);
248     CPPUNIT_ASSERT_EQUAL_MESSAGE("Format should be applied to B2:B4 on the 2nd sheet after the undo of the sheet removal.", ScRange(1,1,1,1,3,1), *pRange);
249 
250 #if 0 // TODO : Undo of sheet insertion currently depends on the presence of
251       // view shell, and crashes when executed during cppunit run.
252 
253     // Undo again and re-check.
254     pUndoMgr->Undo();
255 
256     pList = m_pDoc->GetCondFormList(0);
257     CPPUNIT_ASSERT(pList);
258     pCheck = pList->GetFormat(nKey);
259     CPPUNIT_ASSERT(pCheck);
260 
261     // Make sure the range got shifted back.
262     aCheckRange = pCheck->GetRange();
263     CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
264     pRange = aCheckRange[0];
265     CPPUNIT_ASSERT(pRange);
266     CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 1st sheet after the undo of sheet insertion.", *pRange == ScRange(1,1,0,1,3,0));
267 #else
268     m_pDoc->DeleteTab(1);
269 #endif
270 
271     m_pDoc->DeleteTab(0);
272 }
273 
testCondCopyPaste()274 void Test::testCondCopyPaste()
275 {
276     m_pDoc->InsertTab(0, "Test");
277 
278     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
279     ScRange aCondFormatRange(0,0,0,3,3,0);
280     ScRangeList aRangeList(aCondFormatRange);
281     pFormat->SetRange(aRangeList);
282 
283     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
284     pFormat->AddEntry(pEntry);
285     sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
286 
287     ScDocument aClipDoc(SCDOCMODE_CLIP);
288     copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
289 
290     ScRange aTargetRange(4,4,0,7,7,0);
291     pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
292 
293     ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(7,7,0);
294     CPPUNIT_ASSERT(pPastedFormat);
295 
296     // Pasting the same conditional format must modify existing format, making its range
297     // combined of previous range and newly pasted range having the conditional format.
298     // No new conditional formats must be created.
299     CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
300     aRangeList.Join(aTargetRange);
301     CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
302     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pPastedFormat->GetKey());
303     const SfxPoolItem* pItem = m_pDoc->GetAttr( 7, 7, 0, ATTR_CONDITIONAL );
304     const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
305 
306     CPPUNIT_ASSERT(pCondFormatItem);
307     CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
308     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front());
309 
310     m_pDoc->DeleteTab(0);
311 }
312 
testCondCopyPasteSingleCell()313 void Test::testCondCopyPasteSingleCell()
314 {
315     m_pDoc->InsertTab(0, "Test");
316 
317     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
318     ScRange aCondFormatRange(0,0,0,3,3,0);
319     ScRangeList aRangeList(aCondFormatRange);
320     pFormat->SetRange(aRangeList);
321 
322     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
323     pFormat->AddEntry(pEntry);
324     sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
325 
326     ScDocument aClipDoc(SCDOCMODE_CLIP);
327     copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
328 
329     ScRange aTargetRange(4,4,0,4,4,0);
330     pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
331 
332     ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(4,4,0);
333     CPPUNIT_ASSERT(pPastedFormat);
334 
335     // Pasting the same conditional format must modify existing format, making its range
336     // combined of previous range and newly pasted range having the conditional format.
337     // No new conditional formats must be created.
338     CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
339     aRangeList.Join(aTargetRange);
340     CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
341     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pPastedFormat->GetKey());
342     const SfxPoolItem* pItem = m_pDoc->GetAttr( 4, 4, 0, ATTR_CONDITIONAL );
343     const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
344 
345     CPPUNIT_ASSERT(pCondFormatItem);
346     CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
347     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front() );
348 
349     m_pDoc->DeleteTab(0);
350 }
351 
testCondCopyPasteSingleCellToRange()352 void Test::testCondCopyPasteSingleCellToRange()
353 {
354     m_pDoc->InsertTab(0, "Test");
355 
356     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
357     ScRange aCondFormatRange(0,0,0,3,3,0);
358     ScRangeList aRangeList(aCondFormatRange);
359     pFormat->SetRange(aRangeList);
360 
361     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
362     pFormat->AddEntry(pEntry);
363     sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
364 
365     ScDocument aClipDoc(SCDOCMODE_CLIP);
366     copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
367     ScRange aTargetRange(4,4,0,5,8,0);
368     pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
369 
370     // Pasting the same conditional format must modify existing format, making its range
371     // combined of previous range and newly pasted range having the conditional format.
372     // No new conditional formats must be created.
373     CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
374     aRangeList.Join(aTargetRange);
375     for(SCROW nRow = 4; nRow <= 8; ++nRow)
376     {
377         for (SCCOL nCol = 4; nCol <= 5; ++nCol)
378         {
379             ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(nCol, nRow, 0);
380             CPPUNIT_ASSERT(pPastedFormat);
381 
382             CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
383             sal_uLong nPastedKey = pPastedFormat->GetKey();
384             CPPUNIT_ASSERT_EQUAL(nIndex, nPastedKey);
385             const SfxPoolItem* pItem = m_pDoc->GetAttr( nCol, nRow, 0, ATTR_CONDITIONAL );
386             const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
387 
388             CPPUNIT_ASSERT(pCondFormatItem);
389             CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
390             CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front() );
391         }
392     }
393 
394     m_pDoc->DeleteTab(0);
395 }
396 
testCondCopyPasteSingleCellIntoSameFormatRange()397 void Test::testCondCopyPasteSingleCellIntoSameFormatRange()
398 {
399     m_pDoc->InsertTab(0, "Test");
400 
401     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
402     ScRange aCondFormatRange(0, 0, 0, 3, 3, 0);
403     ScRangeList aRangeList(aCondFormatRange);
404     pFormat->SetRange(aRangeList);
405 
406     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct, "=B2", "", m_pDoc, ScAddress(0, 0, 0), ScResId(STR_STYLENAME_RESULT));
407     pFormat->AddEntry(pEntry);
408     sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
409 
410     ScDocument aClipDoc(SCDOCMODE_CLIP);
411     copyToClip(m_pDoc, ScRange(1, 1, 0, 1, 1, 0), &aClipDoc);
412 
413     ScRange aTargetRange(2, 2, 0, 2, 2, 0);
414     pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
415 
416     ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(2, 2, 0);
417     CPPUNIT_ASSERT(pPastedFormat);
418 
419     // Pasting the same conditional format into the same range must not modify existing format,
420     // since it already covers the pasted range. No new conditional formats must be created.
421     CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
422     CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
423     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pPastedFormat->GetKey());
424     const SfxPoolItem* pItem = m_pDoc->GetAttr(2, 2, 0, ATTR_CONDITIONAL);
425     const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
426 
427     CPPUNIT_ASSERT(pCondFormatItem);
428     CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
429     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front());
430 
431     m_pDoc->DeleteTab(0);
432 }
433 
testCondCopyPasteSingleRowToRange()434 void Test::testCondCopyPasteSingleRowToRange()
435 {
436     m_pDoc->InsertTab(0, "Test");
437 
438     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
439     ScRange aCondFormatRange(0,0,0,0,0,0);
440     ScRangeList aRangeList(aCondFormatRange);
441     pFormat->SetRange(aRangeList);
442 
443     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
444     pFormat->AddEntry(pEntry);
445     auto pFormatTmp = pFormat.get();
446     m_pDoc->AddCondFormat(std::move(pFormat), 0);
447 
448     ScDocument aClipDoc(SCDOCMODE_CLIP);
449     copyToClip(m_pDoc, ScRange(0,0,0,MAXCOL,0,0), &aClipDoc);
450     ScRange aTargetRange(0,4,0,MAXCOL,4,0);
451     pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
452 
453     ScConditionalFormat* pNewFormat = m_pDoc->GetCondFormat(0, 4, 0);
454     CPPUNIT_ASSERT(pNewFormat);
455     CPPUNIT_ASSERT_EQUAL(pNewFormat->GetKey(), pFormatTmp->GetKey());
456 
457     for (SCCOL nCol = 1; nCol <= MAXCOL; ++nCol)
458     {
459         ScConditionalFormat* pNewFormat2 = m_pDoc->GetCondFormat(nCol, 4, 0);
460         CPPUNIT_ASSERT(!pNewFormat2);
461     }
462 
463     m_pDoc->DeleteTab(0);
464 }
465 
testCondCopyPasteSingleRowToRange2()466 void Test::testCondCopyPasteSingleRowToRange2()
467 {
468     m_pDoc->InsertTab(0, "Test");
469 
470     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
471     ScRange aCondFormatRange(0,0,0,0,0,0);
472     ScRangeList aRangeList(aCondFormatRange);
473     pFormat->SetRange(aRangeList);
474 
475     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
476     pFormat->AddEntry(pEntry);
477     m_pDoc->AddCondFormat(std::move(pFormat), 0);
478 
479     ScDocument aClipDoc(SCDOCMODE_CLIP);
480     copyToClip(m_pDoc, ScRange(0,0,0,3,0,0), &aClipDoc);
481     ScRange aTargetRange(0,4,0,MAXCOL,4,0);
482     pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
483 
484     for (SCCOL nCol = 0; nCol <= MAXCOL; ++nCol)
485     {
486         ScConditionalFormat* pNewFormat = m_pDoc->GetCondFormat(nCol, 4, 0);
487         if (nCol % 4 == 0)
488             CPPUNIT_ASSERT(pNewFormat);
489         else
490             CPPUNIT_ASSERT(!pNewFormat);
491     }
492 
493     m_pDoc->DeleteTab(0);
494 }
495 
testCondCopyPasteSheetBetweenDoc()496 void Test::testCondCopyPasteSheetBetweenDoc()
497 {
498     m_pDoc->InsertTab(0, "Test");
499 
500     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
501     ScRange aCondFormatRange(0,0,0,3,3,0);
502     ScRangeList aRangeList(aCondFormatRange);
503     pFormat->SetRange(aRangeList);
504 
505     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
506     pFormat->AddEntry(pEntry);
507     m_pDoc->AddCondFormat(std::move(pFormat), 0);
508 
509     ScDocument aDoc;
510     aDoc.TransferTab(m_pDoc, 0, 0);
511 
512     ScConditionalFormatList* pList = aDoc.GetCondFormList(0);
513     CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
514 
515     m_pDoc->DeleteTab(0);
516 }
517 
testCondCopyPasteSheet()518 void Test::testCondCopyPasteSheet()
519 {
520     m_pDoc->InsertTab(0, "Test");
521 
522     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
523     ScRange aCondFormatRange(0,0,0,3,3,0);
524     ScRangeList aRangeList(aCondFormatRange);
525     pFormat->SetRange(aRangeList);
526 
527     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
528     pFormat->AddEntry(pEntry);
529     m_pDoc->AddCondFormat(std::move(pFormat), 0);
530 
531     m_pDoc->CopyTab(0, SC_TAB_APPEND);
532 
533     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(1);
534     CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
535 
536     ScConditionalFormat& rFormat = **pList->begin();
537     const ScRangeList& rRange = rFormat.GetRange();
538     CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,1,3,3,1)), rRange);
539     sal_uInt32 nKey = rFormat.GetKey();
540     const SfxPoolItem* pItem = m_pDoc->GetAttr( 2, 2, 1, ATTR_CONDITIONAL );
541     const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
542 
543     CPPUNIT_ASSERT(pCondFormatItem);
544     CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
545     CPPUNIT_ASSERT_EQUAL( nKey, pCondFormatItem->GetCondFormatData().front() );
546 
547     m_pDoc->DeleteTab(1);
548     m_pDoc->DeleteTab(0);
549 }
550 
testIconSet()551 void Test::testIconSet()
552 {
553     m_pDoc->InsertTab(0, "Test");
554     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
555 
556     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
557     ScRangeList aRangeList(ScRange(0,0,0,0,0,0));
558     pFormat->SetRange(aRangeList);
559 
560     ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc);
561     ScIconSetFormatData* pData = new ScIconSetFormatData;
562     pData->m_Entries.push_back(std::make_unique<ScColorScaleEntry>(0, COL_BLUE));
563     pData->m_Entries.push_back(std::make_unique<ScColorScaleEntry>(1, COL_GREEN));
564     pData->m_Entries.push_back(std::make_unique<ScColorScaleEntry>(2, COL_RED));
565     pEntry->SetIconSetData(pData);
566 
567     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
568     pList->InsertNew(std::move(pFormat));
569 
570     static struct {
571         double nVal; sal_Int32 nIndex;
572     } const aTests[] = {
573         { -1.0, 0 },
574         { 0.0, 0 },
575         { 1.0, 1 },
576         { 2.0, 2 },
577         { 3.0, 2 }
578     };
579     for(size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
580     {
581         m_pDoc->SetValue(0,0,0,aTests[i].nVal);
582         std::unique_ptr<ScIconSetInfo> pInfo = pEntry->GetIconSetInfo(ScAddress(0,0,0));
583         CPPUNIT_ASSERT_EQUAL(aTests[i].nIndex, pInfo->nIconIndex);
584     }
585 
586     delete pEntry;
587     m_pDoc->DeleteTab(0);
588 }
589 
590 namespace {
591 
592 struct ScDataBarLengthData
593 {
594     double const nVal;
595     double const nLength;
596 };
597 
testDataBarLengthImpl(ScDocument * pDoc,const ScDataBarLengthData * pData,const ScRange & rRange,double nMinVal,ScColorScaleEntryType eMinType,double nMaxVal,ScColorScaleEntryType eMaxType,double nZeroPos,databar::ScAxisPosition eAxisPos)598 void testDataBarLengthImpl(ScDocument* pDoc, const ScDataBarLengthData* pData, const ScRange& rRange,
599         double nMinVal, ScColorScaleEntryType eMinType,
600         double nMaxVal, ScColorScaleEntryType eMaxType,
601         double nZeroPos, databar::ScAxisPosition eAxisPos)
602 {
603     std::unique_ptr<ScConditionalFormat> pFormat(new ScConditionalFormat(1, pDoc));
604     ScRangeList aRangeList(rRange);
605     pFormat->SetRange(aRangeList);
606 
607     SCCOL nCol = rRange.aStart.Col();
608 
609     ScDataBarFormat* pDatabar = new ScDataBarFormat(pDoc);
610     pFormat->AddEntry(pDatabar);
611 
612     ScDataBarFormatData* pFormatData = new ScDataBarFormatData();
613     pFormatData->meAxisPosition = eAxisPos;
614 
615     pFormatData->mpLowerLimit.reset(new ScColorScaleEntry());
616     pFormatData->mpLowerLimit->SetValue(nMinVal);
617     pFormatData->mpLowerLimit->SetType(eMinType);
618     pFormatData->mpUpperLimit.reset(new ScColorScaleEntry());
619     pFormatData->mpUpperLimit->SetValue(nMaxVal);
620     pFormatData->mpUpperLimit->SetType(eMaxType);
621     pDatabar->SetDataBarData(pFormatData);
622 
623     for (size_t i = 0; pData[i].nLength != -200; ++i)
624     {
625         pDoc->SetValue(nCol, i, 0, pData[i].nVal);
626     }
627 
628     for (size_t i = 0; pData[i].nLength != -200; ++i)
629     {
630         std::unique_ptr<ScDataBarInfo> xInfo(pDatabar->GetDataBarInfo(ScAddress(nCol, i, 0)));
631         CPPUNIT_ASSERT(xInfo);
632         ASSERT_DOUBLES_EQUAL(pData[i].nLength, xInfo->mnLength);
633         ASSERT_DOUBLES_EQUAL(nZeroPos, xInfo->mnZero);
634     }
635 }
636 
637 }
638 
testDataBarLengthAutomaticAxis()639 void Test::testDataBarLengthAutomaticAxis()
640 {
641     m_pDoc->InsertTab(0, "Test");
642 
643     static const ScDataBarLengthData aValues[] = {
644         { 2, 0 },
645         { 3, 0 },
646         { 4, 25.0 },
647         { 5, 50.0 },
648         { 6, 75.0 },
649         { 7, 100.0 },
650         { 8, 100.0 },
651         { 9, 100.0 },
652         { 0, -200 }
653     };
654 
655     testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,7,0),
656             3, COLORSCALE_VALUE, 7, COLORSCALE_VALUE, 0.0, databar::AUTOMATIC);
657 
658     static const ScDataBarLengthData aValues2[] = {
659         { -6, -100 },
660         { -5, -100 },
661         { -4, -100 },
662         { -3, -75.0 },
663         { -2, -50.0 },
664         { -1, -25.0 },
665         { 0, 0.0 },
666         { 1, 12.5 },
667         { 2, 25.0 },
668         { 3, 37.5 },
669         { 4, 50.0 },
670         { 5, 62.5 },
671         { 6, 75.0 },
672         { 7, 87.5 },
673         { 8, 100.0 },
674         { 9, 100.0 },
675         { 0, -200 }
676     };
677     testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
678             -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 1.0/3.0 * 100, databar::AUTOMATIC);
679 
680     static const ScDataBarLengthData aValues3[] = {
681         { 2, 0.0 },
682         { 3, 25.0 },
683         { 4, 50.0 },
684         { 6, 100.0 },
685         { 0, -200 }
686     };
687     testDataBarLengthImpl(m_pDoc, aValues3, ScRange(2,0,0,2,3,0),
688             0, COLORSCALE_MIN, 0, COLORSCALE_MAX, 0, databar::AUTOMATIC);
689 
690     static const ScDataBarLengthData aValues4[] = {
691         { 2, 40.0 },
692         { 3, 60.0 },
693         { 4, 80.0 },
694         { 5, 100.0 },
695         { 0, -200 }
696     };
697     testDataBarLengthImpl(m_pDoc, aValues4, ScRange(3,0,0,3,3,0),
698             0, COLORSCALE_AUTO, 0, COLORSCALE_AUTO, 0, databar::AUTOMATIC);
699 
700     m_pDoc->DeleteTab(0);
701 }
702 
testDataBarLengthMiddleAxis()703 void Test::testDataBarLengthMiddleAxis()
704 {
705     m_pDoc->InsertTab(0, "Test");
706 
707     static const ScDataBarLengthData aValues[] = {
708         { 1, 25.0 },
709         { 2, 25.0 },
710         { 3, 37.5 },
711         { 4, 50.0 },
712         { 5, 62.5 },
713         { 6, 75.0 },
714         { 7, 87.5 },
715         { 8, 100.0 },
716         { 9, 100.0 },
717         { 0, -200 }
718     };
719 
720     testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,8,0),
721             2, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
722 
723     static const ScDataBarLengthData aValues2[] = {
724         { -6, -50 },
725         { -5, -50 },
726         { -4, -50 },
727         { -3, -37.5 },
728         { -2, -25.0 },
729         { -1, -12.5 },
730         { 0, 0.0 },
731         { 1, 12.5 },
732         { 2, 25.0 },
733         { 3, 37.5 },
734         { 4, 50.0 },
735         { 5, 62.5 },
736         { 6, 75.0 },
737         { 7, 87.5 },
738         { 8, 100.0 },
739         { 9, 100.0 },
740         { 0, -200 }
741     };
742     testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
743             -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
744 
745     m_pDoc->DeleteTab(0);
746 }
747 
testCondFormatEndsWithStr()748 void Test::testCondFormatEndsWithStr()
749 {
750     m_pDoc->InsertTab(0, "Test");
751 
752     ScConditionEntry aEntry(ScConditionMode::EndsWith, "\"TestString\"", "", m_pDoc, ScAddress(),
753             "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
754 
755     svl::SharedStringPool& rStringPool = m_pDoc->GetSharedStringPool();
756     svl::SharedString aStr = rStringPool.intern("SimpleTestString");
757     ScRefCellValue aVal(&aStr);
758     ScAddress aPos(0, 0, 0);
759 
760     bool bValid = aEntry.IsCellValid(aVal, aPos);
761     CPPUNIT_ASSERT(bValid);
762 
763     m_pDoc->DeleteTab(0);
764 }
765 
testCondFormatEndsWithVal()766 void Test::testCondFormatEndsWithVal()
767 {
768     m_pDoc->InsertTab(0, "Test");
769 
770     ScConditionEntry aEntry(ScConditionMode::EndsWith, "2", "", m_pDoc, ScAddress(),
771             "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
772 
773     for (sal_Int32 i = 0; i < 15; ++i)
774     {
775         ScRefCellValue aVal(i);
776         ScAddress aPos(0, 0, 0);
777 
778         bool bValid = aEntry.IsCellValid(aVal, aPos);
779         bool bShouldBeValid = (i % 10) == 2;
780         CPPUNIT_ASSERT_EQUAL(bShouldBeValid, bValid);
781     }
782 
783     m_pDoc->DeleteTab(0);
784 }
785 
testFormulaListenerSingleCellToSingleCell()786 void Test::testFormulaListenerSingleCellToSingleCell()
787 {
788     m_pDoc->InsertTab(0, "test");
789 
790     ScCompiler aCompiler(m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
791 
792     std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
793 
794     ScFormulaListener aListener(m_pDoc);
795 
796     aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
797 
798     m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
799     CPPUNIT_ASSERT(aListener.NeedsRepaint());
800 
801     m_pDoc->DeleteTab(0);
802 }
803 
testFormulaListenerSingleCellToMultipleCells()804 void Test::testFormulaListenerSingleCellToMultipleCells()
805 {
806     m_pDoc->InsertTab(0, "test");
807 
808     ScCompiler aCompiler(m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
809 
810     std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
811 
812     ScFormulaListener aListener(m_pDoc);
813 
814     aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
815 
816     m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
817     CPPUNIT_ASSERT(aListener.NeedsRepaint());
818 
819     m_pDoc->DeleteTab(0);
820 }
821 
testFormulaListenerMultipleCellsToSingleCell()822 void Test::testFormulaListenerMultipleCellsToSingleCell()
823 {
824     m_pDoc->InsertTab(0, "test");
825 
826     ScCompiler aCompiler(m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
827 
828     std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
829 
830     ScFormulaListener aListener(m_pDoc);
831 
832     aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
833 
834     m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
835     CPPUNIT_ASSERT(aListener.NeedsRepaint());
836 
837     m_pDoc->DeleteTab(0);
838 }
839 
testFormulaListenerMultipleCellsToMultipleCells()840 void Test::testFormulaListenerMultipleCellsToMultipleCells()
841 {
842     m_pDoc->InsertTab(0, "test");
843 
844     ScCompiler aCompiler(m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
845 
846     std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
847 
848     ScFormulaListener aListener(m_pDoc);
849 
850     aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
851 
852     m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
853     CPPUNIT_ASSERT(aListener.NeedsRepaint());
854 
855     m_pDoc->DeleteTab(0);
856 }
857 
testFormulaListenerUpdateInsertTab()858 void Test::testFormulaListenerUpdateInsertTab()
859 {
860     m_pDoc->InsertTab(0, "test");
861 
862     ScCompiler aCompiler(m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
863     std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
864 
865     ScFormulaListener aListener(m_pDoc);
866     aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
867     CPPUNIT_ASSERT(!aListener.NeedsRepaint());
868 
869     m_pDoc->InsertTab(0, "new_tab");
870 
871     // check that the listener has moved to the new sheet
872     m_pDoc->SetValue(ScAddress(0, 0, 1), 1.0);
873     CPPUNIT_ASSERT(aListener.NeedsRepaint());
874 
875     // check that we are not listening to the old sheet
876     m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
877     CPPUNIT_ASSERT(!aListener.NeedsRepaint());
878 
879     m_pDoc->DeleteTab(0);
880 }
881 
testFormulaListenerUpdateDeleteTab()882 void Test::testFormulaListenerUpdateDeleteTab()
883 {
884     m_pDoc->InsertTab(0, "test");
885     m_pDoc->InsertTab(0, "to_delete");
886 
887     ScCompiler aCompiler(m_pDoc, ScAddress(10, 10, 1), formula::FormulaGrammar::GRAM_ENGLISH);
888     std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
889 
890     ScFormulaListener aListener(m_pDoc);
891     aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 1));
892     CPPUNIT_ASSERT(!aListener.NeedsRepaint());
893 
894     m_pDoc->DeleteTab(0);
895 
896     // check that the listener has moved
897     m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
898     CPPUNIT_ASSERT(aListener.NeedsRepaint());
899 
900     m_pDoc->DeleteTab(0);
901 }
902 
testCondFormatUpdateMoveTab()903 void Test::testCondFormatUpdateMoveTab()
904 {
905     m_pDoc->InsertTab(0, "test");
906     m_pDoc->InsertTab(1, "Test2");
907 
908     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", m_pDoc, ScAddress(10, 10, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
909 
910     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
911     pFormat->SetRange(ScRange(10, 10, 0, 10, 12, 0));
912     auto pFormatTmp = pFormat.get();
913     m_pDoc->AddCondFormat(std::move(pFormat), 0);
914 
915     pFormatTmp->AddEntry(pEntry);
916 
917     // the conditional format should listen to A1:A3
918     for (SCROW nRow = 0; nRow < 3; ++nRow)
919     {
920         m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
921         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
922     }
923 
924     m_pDoc->MoveTab(0, 1);
925 
926     // the conditional format should listen to A1:A3 on the second sheet
927     for (SCROW nRow = 0; nRow < 3; ++nRow)
928     {
929         m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
930         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
931 
932         m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
933         CPPUNIT_ASSERT(!pEntry->NeedsRepaint());
934     }
935 
936     m_pDoc->DeleteTab(1);
937     m_pDoc->DeleteTab(0);
938 }
939 
testCondFormatUpdateInsertTab()940 void Test::testCondFormatUpdateInsertTab()
941 {
942     m_pDoc->InsertTab(0, "test");
943 
944     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", m_pDoc, ScAddress(10, 10, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
945 
946     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
947     pFormat->SetRange(ScRange(10, 10, 0, 10, 12, 0));
948     auto pFormatTmp = pFormat.get();
949     m_pDoc->AddCondFormat(std::move(pFormat), 0);
950 
951     pFormatTmp->AddEntry(pEntry);
952 
953     // the conditional format should listen to A1:A3
954     for (SCROW nRow = 0; nRow < 3; ++nRow)
955     {
956         m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
957         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
958 
959         m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
960         CPPUNIT_ASSERT(!pEntry->NeedsRepaint());
961     }
962 
963     m_pDoc->InsertTab(0, "test2");
964 
965     // the conditional format should listen to A1:A3 on the second sheet
966     for (SCROW nRow = 0; nRow < 3; ++nRow)
967     {
968         m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
969         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
970 
971         m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
972         CPPUNIT_ASSERT(!pEntry->NeedsRepaint());
973     }
974 
975     m_pDoc->DeleteTab(1);
976     m_pDoc->DeleteTab(0);
977 }
978 
testCondFormatUpdateDeleteTab()979 void Test::testCondFormatUpdateDeleteTab()
980 {
981     m_pDoc->InsertTab(0, "test");
982     m_pDoc->InsertTab(1, "Test2");
983 
984     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", m_pDoc, ScAddress(10, 10, 1), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
985 
986     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
987     pFormat->SetRange(ScRange(10, 10, 1, 10, 12, 1));
988     auto pFormatTmp = pFormat.get();
989     m_pDoc->AddCondFormat(std::move(pFormat), 1);
990 
991     pFormatTmp->AddEntry(pEntry);
992 
993     // the conditional format should listen to A1:A3 on the second sheet
994     for (SCROW nRow = 0; nRow < 3; ++nRow)
995     {
996         m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
997         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
998     }
999 
1000     m_pDoc->DeleteTab(0);
1001 
1002     // the conditional format should listen to A1:A3 on the second sheet
1003     for (SCROW nRow = 0; nRow < 3; ++nRow)
1004     {
1005         m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1006         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1007     }
1008 
1009     m_pDoc->DeleteTab(0);
1010 }
1011 
testCondFormatUpdateReference()1012 void Test::testCondFormatUpdateReference()
1013 {
1014     m_pDoc->InsertTab(0, "test");
1015     m_pDoc->InsertTab(1, "Test2");
1016 
1017     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", m_pDoc, ScAddress(10, 10, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1018 
1019     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1020     pFormat->SetRange(ScRange(10, 10, 0, 10, 12, 0));
1021     auto pFormatTmp = pFormat.get();
1022     m_pDoc->AddCondFormat(std::move(pFormat), 0);
1023 
1024     pFormatTmp->AddEntry(pEntry);
1025 
1026     // the conditional format should listen to A1:A3
1027     for (SCROW nRow = 0; nRow < 3; ++nRow)
1028     {
1029         m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1030         CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1031     }
1032 
1033     m_pDoc->DeleteTab(1);
1034     m_pDoc->DeleteTab(0);
1035 }
1036 
testCondFormatUpdateReferenceDelRow()1037 void Test::testCondFormatUpdateReferenceDelRow()
1038 {
1039     m_pDoc->InsertTab(0, "test");
1040 
1041     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "B6", "", m_pDoc, ScAddress(0, 5, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1042 
1043     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1044     pFormat->SetRange(ScRange(0, 5, 0, 0, 5, 0));
1045     auto pFormatTmp = pFormat.get();
1046     m_pDoc->AddCondFormat(std::move(pFormat), 0);
1047 
1048     pFormatTmp->AddEntry(pEntry);
1049 
1050     m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 4, 1);
1051 
1052     OUString aStr = pEntry->GetExpression(ScAddress(0, 4, 0), 0);
1053     CPPUNIT_ASSERT_EQUAL(OUString("B5"), aStr);
1054 
1055     m_pDoc->DeleteTab(0);
1056 }
1057 
testCondFormatUpdateReferenceInsRow()1058 void Test::testCondFormatUpdateReferenceInsRow()
1059 {
1060     m_pDoc->InsertTab(0, "test");
1061 
1062     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "B6", "", m_pDoc, ScAddress(0, 5, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1063 
1064     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1065     pFormat->SetRange(ScRange(0, 5, 0, 0, 5, 0));
1066     auto pFormatTmp = pFormat.get();
1067     m_pDoc->AddCondFormat(std::move(pFormat), 0);
1068 
1069     pFormatTmp->AddEntry(pEntry);
1070 
1071     m_pDoc->InsertRow(0, 0, MAXCOL, 0, 4, 1);
1072 
1073     OUString aStr = pEntry->GetExpression(ScAddress(0, 6, 0), 0);
1074     CPPUNIT_ASSERT_EQUAL(OUString("B7"), aStr);
1075 
1076     m_pDoc->DeleteTab(0);
1077 }
1078 
testCondFormatUndoList()1079 void Test::testCondFormatUndoList()
1080 {
1081     m_pDoc->InsertTab(0, "test");
1082 
1083     ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "B6", "", m_pDoc, ScAddress(0, 5, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1084 
1085     auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1086     pFormat->AddEntry(pEntry);
1087     pFormat->SetRange(ScRange(0, 0, 0, 0, 5, 0));
1088     auto pFormatTmp = pFormat.get();
1089     m_pDoc->AddCondFormat(std::move(pFormat), 0);
1090     m_pDoc->AddCondFormatData(pFormatTmp->GetRange(), 0, pFormatTmp->GetKey());
1091 
1092     ScDocFunc& rFunc = getDocShell().GetDocFunc();
1093 
1094     CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
1095     for (SCROW nRow = 0; nRow <= 5; ++nRow)
1096         CPPUNIT_ASSERT(m_pDoc->GetCondFormat(0, nRow, 0));
1097 
1098     ScConditionalFormatList* pNewList = new ScConditionalFormatList();
1099 
1100     rFunc.SetConditionalFormatList(pNewList, 0);
1101 
1102     CPPUNIT_ASSERT_EQUAL(size_t(0), m_pDoc->GetCondFormList(0)->size());
1103     for (SCROW nRow = 0; nRow <= 5; ++nRow)
1104         CPPUNIT_ASSERT(!m_pDoc->GetCondFormat(0, nRow, 0));
1105 
1106     m_pDoc->GetUndoManager()->Undo();
1107 
1108     CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
1109     for (SCROW nRow = 0; nRow <= 5; ++nRow)
1110         CPPUNIT_ASSERT(m_pDoc->GetCondFormat(0, nRow, 0));
1111 
1112     m_pDoc->GetUndoManager()->Redo();
1113 
1114     CPPUNIT_ASSERT_EQUAL(size_t(0), m_pDoc->GetCondFormList(0)->size());
1115     for (SCROW nRow = 0; nRow <= 5; ++nRow)
1116         CPPUNIT_ASSERT(!m_pDoc->GetCondFormat(0, nRow, 0));
1117 
1118     m_pDoc->DeleteTab(0);
1119 }
1120 
1121 namespace {
1122 
addSingleCellCondFormat(ScDocument * pDoc,const ScAddress & rAddr,sal_uInt32 nKey,const OUString & rCondition)1123 sal_uInt32 addSingleCellCondFormat(ScDocument* pDoc, const ScAddress& rAddr, sal_uInt32 nKey, const OUString& rCondition)
1124 {
1125     auto pFormat = std::make_unique<ScConditionalFormat>(nKey, pDoc);
1126     ScRange aCondFormatRange(rAddr);
1127     ScRangeList aRangeList(aCondFormatRange);
1128     pFormat->SetRange(aRangeList);
1129 
1130     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct, rCondition, "",
1131             pDoc, ScAddress(0,0,0), ScResId(STR_STYLENAME_RESULT));
1132     pFormat->AddEntry(pEntry);
1133     return pDoc->AddCondFormat(std::move(pFormat), 0);
1134 }
1135 
1136 }
1137 
testMultipleSingleCellCondFormatCopyPaste()1138 void Test::testMultipleSingleCellCondFormatCopyPaste()
1139 {
1140     m_pDoc->InsertTab(0, "Test");
1141 
1142     sal_uInt32 nFirstCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(0, 0, 0), 1, "=A2");
1143     sal_uInt32 nSecondCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(1, 0, 0), 2, "=B3");
1144 
1145     ScDocument aClipDoc(SCDOCMODE_CLIP);
1146     copyToClip(m_pDoc, ScRange(0,0,0,2,0,0), &aClipDoc);
1147     ScRange aTargetRange(2,4,0,7,4,0);
1148     pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
1149 
1150     for (SCCOL nCol = 2; nCol <= 7; ++nCol)
1151     {
1152         ScConditionalFormat* pFormat = m_pDoc->GetCondFormat(nCol, 4, 0);
1153         if (((nCol - 2) % 3) == 0)
1154         {
1155             CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nFirstCondFormatKey);
1156         }
1157         else if (((nCol - 2) % 3) == 1)
1158         {
1159             CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nSecondCondFormatKey);
1160         }
1161         else
1162         {
1163             CPPUNIT_ASSERT(!pFormat);
1164         }
1165     }
1166 
1167     m_pDoc->DeleteTab(0);
1168 }
1169 
testDeduplicateMultipleCondFormats()1170 void Test::testDeduplicateMultipleCondFormats()
1171 {
1172     m_pDoc->InsertTab(0, "Test");
1173 
1174     sal_uInt32 nFirstCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(0, 0, 0), 1, "=B2");
1175     sal_uInt32 nSecondCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(1, 0, 0), 2, "=B2");
1176 
1177     ScDocument aClipDoc(SCDOCMODE_CLIP);
1178     copyToClip(m_pDoc, ScRange(0,0,0,2,0,0), &aClipDoc);
1179     ScRange aTargetRange(2,4,0,7,4,0);
1180     pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
1181 
1182     for (SCCOL nCol = 2; nCol <= 7; ++nCol)
1183     {
1184         ScConditionalFormat* pFormat = m_pDoc->GetCondFormat(nCol, 4, 0);
1185         if (((nCol - 2) % 3) == 0)
1186         {
1187             CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nFirstCondFormatKey);
1188         }
1189         else if (((nCol - 2) % 3) == 1)
1190         {
1191             CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nSecondCondFormatKey);
1192         }
1193         else
1194         {
1195             CPPUNIT_ASSERT(!pFormat);
1196         }
1197     }
1198 
1199     m_pDoc->DeleteTab(0);
1200 }
1201 
testCondFormatListenToOwnRange()1202 void Test::testCondFormatListenToOwnRange()
1203 {
1204     m_pDoc->InsertTab(0, "Test");
1205 
1206     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
1207 
1208     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
1209     ScRangeList aRangeList(ScRange(0,0,0,10,0,0));
1210     pFormat->SetRange(aRangeList);
1211 
1212     ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc);
1213     ScIconSetFormatData* pData = new ScIconSetFormatData;
1214     pData->m_Entries.push_back(std::make_unique<ScColorScaleEntry>(0, COL_BLUE));
1215     pData->m_Entries.push_back(std::make_unique<ScColorScaleEntry>(1, COL_GREEN));
1216     pData->m_Entries.push_back(std::make_unique<ScColorScaleEntry>(2, COL_RED));
1217     pEntry->SetIconSetData(pData);
1218     pEntry->SetParent(pFormat.get());
1219 
1220     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
1221     pFormat->AddEntry(pEntry);
1222     pList->InsertNew(std::move(pFormat));
1223 
1224     bool bFirstCallbackCalled = false;
1225     bool bSecondCallbackCalled = false;
1226     bool bThirdCallbackCalled = false;
1227     std::function<void()> aFirstCallback = [&]() {bFirstCallbackCalled = true;};
1228     std::function<void()> aSecondCallback = [&]() {bSecondCallbackCalled = true;};
1229     std::function<void()> aThirdCallback = [&]() {bThirdCallbackCalled = true;};
1230     pData->m_Entries[0]->SetType(COLORSCALE_PERCENT);
1231     pData->m_Entries[0]->SetRepaintCallback(aFirstCallback);
1232 
1233     m_pDoc->SetValue(0, 0, 0, -1.0);
1234 
1235     CPPUNIT_ASSERT(bFirstCallbackCalled);
1236 
1237     m_pDoc->DeleteTab(0);
1238 }
1239 
testCondFormatVolatileFunctionRecalc()1240 void Test::testCondFormatVolatileFunctionRecalc()
1241 {
1242     m_pDoc->InsertTab(0, "Test");
1243 
1244     m_pDoc->SetValue(0, 0, 0, 0.5);
1245 
1246     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
1247 
1248     auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
1249     ScRangeList aRangeList(ScRange(0,0,0,10,0,0));
1250     pFormat->SetRange(aRangeList);
1251 
1252     ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Greater,"RAND()","",m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
1253     pEntry->SetParent(pFormat.get());
1254 
1255     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
1256     pFormat->AddEntry(pEntry);
1257     auto pFormatTmp = pFormat.get();
1258     pList->InsertNew(std::move(pFormat));
1259 
1260     ScRefCellValue aCell(*m_pDoc, ScAddress(0, 0, 0));
1261     bool bValid = pEntry->IsCellValid(aCell, ScAddress(0, 0, 0));
1262 
1263     bool bNewValid = bValid;
1264     // chance of a random failure is 0.5^100, anyone hitting that will get a beer from me
1265     for (size_t i = 0; i < 100; ++i)
1266     {
1267         pFormatTmp->CalcAll();
1268         bNewValid = pEntry->IsCellValid(aCell, ScAddress(0, 0, 0));
1269 
1270         if (bValid != bNewValid)
1271             break;
1272     }
1273 
1274     CPPUNIT_ASSERT(bValid != bNewValid);
1275 
1276     m_pDoc->DeleteTab(0);
1277 }
1278 
1279 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1280