Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / qa / unit / ucalc_condformat.cxx
blob53072640324e898bbfe941d5066bf32079c691d0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include "helper/qahelper.hxx"
12 #include <conditio.hxx>
13 #include <colorscale.hxx>
15 #include <hints.hxx>
16 #include <globstr.hrc>
17 #include <scresid.hxx>
18 #include <docfunc.hxx>
19 #include <scitems.hxx>
20 #include <attrib.hxx>
21 #include <fillinfo.hxx>
22 #include <compiler.hxx>
23 #include <undomanager.hxx>
25 #include <svl/sharedstringpool.hxx>
27 namespace {
29 struct PaintListener : public SfxListener
31 bool mbPaintAllMergedCell = false;
32 virtual void Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) override
34 const ScPaintHint* pPaintHint = dynamic_cast<const ScPaintHint*>(&rHint);
35 if (pPaintHint)
37 if (pPaintHint->GetStartCol() == 0 && pPaintHint->GetEndCol() == 0
38 && pPaintHint->GetStartRow() == 0 && pPaintHint->GetEndRow() == 1)
40 mbPaintAllMergedCell = true;
46 struct ScDataBarLengthData
48 double nVal;
49 double nLength;
52 void testDataBarLengthImpl(ScDocument* pDoc, const ScDataBarLengthData* pData, const ScRange& rRange,
53 double nMinVal, ScColorScaleEntryType eMinType,
54 double nMaxVal, ScColorScaleEntryType eMaxType,
55 double nZeroPos, databar::ScAxisPosition eAxisPos)
57 std::unique_ptr<ScConditionalFormat> pFormat(new ScConditionalFormat(1, pDoc));
58 ScRangeList aRangeList(rRange);
59 pFormat->SetRange(aRangeList);
61 SCCOL nCol = rRange.aStart.Col();
63 ScDataBarFormat* pDatabar = new ScDataBarFormat(pDoc);
64 pFormat->AddEntry(pDatabar);
66 ScDataBarFormatData* pFormatData = new ScDataBarFormatData();
67 pFormatData->meAxisPosition = eAxisPos;
69 pFormatData->mpLowerLimit.reset(new ScColorScaleEntry());
70 pFormatData->mpLowerLimit->SetValue(nMinVal);
71 pFormatData->mpLowerLimit->SetType(eMinType);
72 pFormatData->mpUpperLimit.reset(new ScColorScaleEntry());
73 pFormatData->mpUpperLimit->SetValue(nMaxVal);
74 pFormatData->mpUpperLimit->SetType(eMaxType);
75 pDatabar->SetDataBarData(pFormatData);
77 for (size_t i = 0; pData[i].nLength != -200; ++i)
79 pDoc->SetValue(nCol, i, 0, pData[i].nVal);
82 for (size_t i = 0; pData[i].nLength != -200; ++i)
84 std::unique_ptr<ScDataBarInfo> xInfo(pDatabar->GetDataBarInfo(ScAddress(nCol, i, 0)));
85 CPPUNIT_ASSERT(xInfo);
86 ASSERT_DOUBLES_EQUAL(pData[i].nLength, xInfo->mnLength);
87 ASSERT_DOUBLES_EQUAL(nZeroPos, xInfo->mnZero);
91 sal_uInt32 addSingleCellCondFormat(ScDocument* pDoc, const ScAddress& rAddr, sal_uInt32 nKey, const OUString& rCondition)
93 auto pFormat = std::make_unique<ScConditionalFormat>(nKey, pDoc);
94 ScRange aCondFormatRange(rAddr);
95 ScRangeList aRangeList(aCondFormatRange);
96 pFormat->SetRange(aRangeList);
98 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct, rCondition, "",
99 *pDoc, ScAddress(0,0,0), ScResId(STR_STYLENAME_RESULT));
100 pFormat->AddEntry(pEntry);
101 return pDoc->AddCondFormat(std::move(pFormat), 0);
106 class TestCondformat : public ScUcalcTestBase
110 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatINSDEL)
112 // fdo#62206
113 m_pDoc->InsertTab(0, "Test");
114 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
116 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
117 ScRangeList aRangeList(ScRange(0,0,0,0,3,0));
118 pFormat->SetRange(aRangeList);
119 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
120 pFormat->AddEntry(pEntry);
122 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
123 auto pFormatTmp = pFormat.get();
124 pList->InsertNew(std::move(pFormat));
126 m_pDoc->InsertCol(0,0,m_pDoc->MaxRow(),0,0,2);
127 const ScRangeList& rRange = pFormatTmp->GetRange();
128 CPPUNIT_ASSERT_EQUAL(static_cast<const ScRangeList&>(ScRange(2,0,0,2,3,0)), rRange);
130 OUString aExpr = pEntry->GetExpression(ScAddress(2,0,0), 0);
131 CPPUNIT_ASSERT_EQUAL(OUString("D2"), aExpr);
133 m_pDoc->DeleteTab(0);
136 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatInsertCol)
138 m_pDoc->InsertTab(0, "Test");
139 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
141 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
142 ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
143 pFormat->SetRange(aRangeList);
145 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
146 pFormat->AddEntry(pEntry);
148 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
149 auto pFormatTmp = pFormat.get();
150 pList->InsertNew(std::move(pFormat));
152 m_pDoc->InsertCol(0,0,m_pDoc->MaxRow(),0,4,2);
153 const ScRangeList& rRange = pFormatTmp->GetRange();
154 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,5,3,0)), rRange);
156 m_pDoc->DeleteTab(0);
159 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatInsertRow)
161 m_pDoc->InsertTab(0, "Test");
162 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
164 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
165 ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
166 pFormat->SetRange(aRangeList);
168 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
169 pFormat->AddEntry(pEntry);
171 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
172 auto pFormatTmp = pFormat.get();
173 pList->InsertNew(std::move(pFormat));
175 m_pDoc->InsertRow(0,0,m_pDoc->MaxCol(),0,4,2);
176 const ScRangeList& rRange = pFormatTmp->GetRange();
177 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,3,5,0)), rRange);
179 m_pDoc->DeleteTab(0);
182 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatInsertDeleteSheets)
184 m_pDoc->InsertTab(0, "Test");
186 // Add a conditional format to B2:B4.
187 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
188 pFormat->SetRange(ScRange(1,1,0,1,3,0));
190 auto pFormatTmp = pFormat.get();
191 sal_uLong nKey = m_pDoc->AddCondFormat(std::move(pFormat), 0);
193 // Add condition in which if the value equals 2, set the "Result" style.
194 ScCondFormatEntry* pEntry = new ScCondFormatEntry(
195 ScConditionMode::Equal, "=2", "" , *m_pDoc, ScAddress(0,0,0), ScResId(STR_STYLENAME_RESULT));
196 pFormatTmp->AddEntry(pEntry);
198 // Apply the format to the range.
199 m_pDoc->AddCondFormatData(pFormatTmp->GetRange(), 0, nKey);
201 // Make sure this conditional format entry is really there.
202 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
203 CPPUNIT_ASSERT(pList);
204 const ScConditionalFormat* pCheck = pList->GetFormat(nKey);
205 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong conditional format instance.", pCheck, const_cast<const ScConditionalFormat*>(pFormatTmp));
207 // ... and its range is B2:B4.
208 ScRangeList aCheckRange = pCheck->GetRange();
209 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
210 const ScRange* pRange = &aCheckRange[0];
211 CPPUNIT_ASSERT(pRange);
212 CPPUNIT_ASSERT_EQUAL_MESSAGE("Format should be applied to B2:B4.", ScRange(1,1,0,1,3,0), *pRange);
214 ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
216 // Insert a new sheet at the left.
217 bool bInserted = rFunc.InsertTable(0, "Inserted", true, true);
218 CPPUNIT_ASSERT(bInserted);
220 pList = m_pDoc->GetCondFormList(1);
221 CPPUNIT_ASSERT(pList);
222 pCheck = pList->GetFormat(nKey);
223 CPPUNIT_ASSERT(pCheck);
225 // Make sure the range also got shifted.
226 aCheckRange = pCheck->GetRange();
227 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
228 pRange = &aCheckRange[0];
229 CPPUNIT_ASSERT(pRange);
230 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);
232 // Delete the sheet to the left.
233 bool bDeleted = rFunc.DeleteTable(0, true);
234 CPPUNIT_ASSERT(bDeleted);
236 pList = m_pDoc->GetCondFormList(0);
237 CPPUNIT_ASSERT(pList);
238 pCheck = pList->GetFormat(nKey);
239 CPPUNIT_ASSERT(pCheck);
241 // Make sure the range got shifted back.
242 aCheckRange = pCheck->GetRange();
243 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
244 pRange = &aCheckRange[0];
245 CPPUNIT_ASSERT(pRange);
246 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);
248 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
249 CPPUNIT_ASSERT(pUndoMgr);
251 // Undo and re-check.
252 pUndoMgr->Undo();
254 pList = m_pDoc->GetCondFormList(1);
255 CPPUNIT_ASSERT(pList);
256 pCheck = pList->GetFormat(nKey);
257 CPPUNIT_ASSERT(pCheck);
259 aCheckRange = pCheck->GetRange();
260 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a single range.", size_t(1), aCheckRange.size());
261 pRange = &aCheckRange[0];
262 CPPUNIT_ASSERT(pRange);
263 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);
265 #if 0 // TODO : Undo of sheet insertion currently depends on the presence of
266 // view shell, and crashes when executed during cppunit run.
268 // Undo again and re-check.
269 pUndoMgr->Undo();
271 pList = m_pDoc->GetCondFormList(0);
272 CPPUNIT_ASSERT(pList);
273 pCheck = pList->GetFormat(nKey);
274 CPPUNIT_ASSERT(pCheck);
276 // Make sure the range got shifted back.
277 aCheckRange = pCheck->GetRange();
278 CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
279 pRange = aCheckRange[0];
280 CPPUNIT_ASSERT(pRange);
281 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));
282 #else
283 m_pDoc->DeleteTab(1);
284 #endif
286 m_pDoc->DeleteTab(0);
289 CPPUNIT_TEST_FIXTURE(TestCondformat, testDataBarCondCopyPaste)
291 m_pDoc->InsertTab(0, "Test");
293 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
294 ScRange aCondFormatRange(0, 0, 0, 2, 0, 0);
295 ScRangeList aRangeList(aCondFormatRange);
296 pFormat->SetRange(aRangeList);
298 ScDataBarFormat* pDatabar = new ScDataBarFormat(m_pDoc);
299 ScDataBarFormatData* pFormatData = new ScDataBarFormatData();
300 pFormatData->meAxisPosition = databar::AUTOMATIC;
301 pFormatData->maPositiveColor = COL_BLUE;
302 pFormatData->mxNegativeColor = COL_GREEN;
303 pFormatData->mbGradient = true;
305 pDatabar->SetDataBarData(pFormatData);
306 pFormat->AddEntry(pDatabar);
308 sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
310 ScDocument aClipDoc(SCDOCMODE_CLIP);
311 copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
313 ScRange aTargetRange(0, 3, 0, 2, 3, 0);
314 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
316 // Pasting the same conditional format must modify existing format, making its range
317 // combined of previous range and newly pasted range having the conditional format.
318 // No new conditional formats must be created.
319 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
320 aRangeList.Join(aTargetRange);
321 for (SCCOL nCol = 0; nCol < 3; ++nCol)
323 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(nCol, 3, 0);
324 CPPUNIT_ASSERT(pPastedFormat);
325 CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
327 sal_uLong nPastedKey = pPastedFormat->GetKey();
328 CPPUNIT_ASSERT_EQUAL(nIndex, nPastedKey);
330 const SfxPoolItem* pItem = m_pDoc->GetAttr(nCol, 3, 0, ATTR_CONDITIONAL);
331 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
332 CPPUNIT_ASSERT(pCondFormatItem);
333 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
334 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front());
337 m_pDoc->DeleteTab(0);
340 CPPUNIT_TEST_FIXTURE(TestCondformat, testColorScaleInMergedCell)
342 m_pDoc->InsertTab(0, "Test");
343 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
345 // Add a conditional format to A1.
346 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
347 pFormat->SetRange(ScRange(0, 0, 0, 0, 0, 0));
348 auto pFormatTmp = pFormat.get();
349 sal_uLong nKey = m_pDoc->AddCondFormat(std::move(pFormat), 0);
351 // Add color scale entries.
352 // The coloring is based on the value. (BLUE (x <= 0), GREEN (x == 1), RED (x >= 2))
353 ScColorScaleFormat* pColorScaleFormat = new ScColorScaleFormat(m_pDoc);
354 ScColorScaleEntry* pEntryBlue = new ScColorScaleEntry(0, COL_BLUE);
355 ScColorScaleEntry* pEntryGreen = new ScColorScaleEntry(1, COL_GREEN);
356 ScColorScaleEntry* pEntryRed = new ScColorScaleEntry(2, COL_RED);
357 pColorScaleFormat->AddEntry(pEntryBlue);
358 pColorScaleFormat->AddEntry(pEntryGreen);
359 pColorScaleFormat->AddEntry(pEntryRed);
361 pFormatTmp->AddEntry(pColorScaleFormat);
363 // Apply the format to the range.
364 m_pDoc->AddCondFormatData(pFormatTmp->GetRange(), 0, nKey);
366 m_pDoc->DoMerge(0, 0, 0, 1, 0); // A1:A2
367 CPPUNIT_ASSERT(m_pDoc->IsMerged(ScAddress(0, 0, 0)));
369 ScTableInfo aTabInfo(0, 2, false);
370 m_pDoc->FillInfo(aTabInfo, 0, 0, 0, 1, 0, 1, 1, false, false);
371 RowInfo* pRowInfo = aTabInfo.mpRowInfo.get();
373 RowInfo* pRowInfoA1 = &pRowInfo[1];
374 ScCellInfo* pCellInfoA1 = &pRowInfoA1->cellInfo(0);
375 // Check if there is a color scale in A1.
376 CPPUNIT_ASSERT_EQUAL_MESSAGE("There is no color scale in cell A1!", true,
377 pCellInfoA1->mxColorScale.has_value());
379 RowInfo* pRowInfoA2 = &pRowInfo[2];
380 ScCellInfo* pCellInfoA2 = &pRowInfoA2->cellInfo(0);
381 // Check if there is a color scale in A2.
382 CPPUNIT_ASSERT_EQUAL_MESSAGE("There is no color scale in cell A2!", true,
383 pCellInfoA2->mxColorScale.has_value());
385 // Check that cells A1 and A2 have the same color scale. (GREEN)
386 CPPUNIT_ASSERT(pCellInfoA1->mxColorScale.value().IsRGBEqual(pCellInfoA2->mxColorScale.value()));
388 m_pDoc->DeleteTab(0);
392 CPPUNIT_TEST_FIXTURE(TestCondformat, testColorScaleCondCopyPaste)
394 m_pDoc->InsertTab(0, "Test");
396 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
397 ScRange aCondFormatRange(0, 0, 0, 2, 0, 0);
398 ScRangeList aRangeList(aCondFormatRange);
399 pFormat->SetRange(aRangeList);
401 ScColorScaleFormat* pColorScaleFormat = new ScColorScaleFormat(m_pDoc);
402 ScColorScaleEntry* pEntryBlue = new ScColorScaleEntry(0, COL_BLUE);
403 ScColorScaleEntry* pEntryGreen = new ScColorScaleEntry(1, COL_GREEN);
404 ScColorScaleEntry* pEntryRed = new ScColorScaleEntry(2, COL_RED);
405 pColorScaleFormat->AddEntry(pEntryBlue);
406 pColorScaleFormat->AddEntry(pEntryGreen);
407 pColorScaleFormat->AddEntry(pEntryRed);
409 pFormat->AddEntry(pColorScaleFormat);
410 sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
412 ScDocument aClipDoc(SCDOCMODE_CLIP);
413 copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
415 ScRange aTargetRange(0, 3, 0, 2, 3, 0);
416 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
418 // Pasting the same conditional format must modify existing format, making its range
419 // combined of previous range and newly pasted range having the conditional format.
420 // No new conditional formats must be created.
421 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
422 aRangeList.Join(aTargetRange);
423 for (SCCOL nCol = 0; nCol < 3; ++nCol)
425 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(nCol, 3, 0);
426 CPPUNIT_ASSERT(pPastedFormat);
427 CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
429 sal_uLong nPastedKey = pPastedFormat->GetKey();
430 CPPUNIT_ASSERT_EQUAL(nIndex, nPastedKey);
432 const SfxPoolItem* pItem = m_pDoc->GetAttr(nCol, 3, 0, ATTR_CONDITIONAL);
433 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
434 CPPUNIT_ASSERT(pCondFormatItem);
435 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
436 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front());
439 m_pDoc->DeleteTab(0);
442 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPaste)
444 m_pDoc->InsertTab(0, "Test");
446 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
447 ScRange aCondFormatRange(0,0,0,3,3,0);
448 ScRangeList aRangeList(aCondFormatRange);
449 pFormat->SetRange(aRangeList);
451 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
452 pFormat->AddEntry(pEntry);
453 sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
455 ScDocument aClipDoc(SCDOCMODE_CLIP);
456 copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
458 ScRange aTargetRange(4,4,0,7,7,0);
459 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
461 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(7,7,0);
462 CPPUNIT_ASSERT(pPastedFormat);
464 // Pasting the same conditional format must modify existing format, making its range
465 // combined of previous range and newly pasted range having the conditional format.
466 // No new conditional formats must be created.
467 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
468 aRangeList.Join(aTargetRange);
469 CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
470 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pPastedFormat->GetKey());
471 const SfxPoolItem* pItem = m_pDoc->GetAttr( 7, 7, 0, ATTR_CONDITIONAL );
472 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
474 CPPUNIT_ASSERT(pCondFormatItem);
475 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
476 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front());
478 m_pDoc->DeleteTab(0);
481 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSingleCell)
483 //e.g. fdo#82503
484 m_pDoc->InsertTab(0, "Test");
486 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
487 ScRange aCondFormatRange(0,0,0,3,3,0);
488 ScRangeList aRangeList(aCondFormatRange);
489 pFormat->SetRange(aRangeList);
491 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
492 pFormat->AddEntry(pEntry);
493 sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
495 ScDocument aClipDoc(SCDOCMODE_CLIP);
496 copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
498 ScRange aTargetRange(4,4,0,4,4,0);
499 pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
501 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(4,4,0);
502 CPPUNIT_ASSERT(pPastedFormat);
504 // Pasting the same conditional format must modify existing format, making its range
505 // combined of previous range and newly pasted range having the conditional format.
506 // No new conditional formats must be created.
507 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
508 aRangeList.Join(aTargetRange);
509 CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
510 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pPastedFormat->GetKey());
511 const SfxPoolItem* pItem = m_pDoc->GetAttr( 4, 4, 0, ATTR_CONDITIONAL );
512 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
514 CPPUNIT_ASSERT(pCondFormatItem);
515 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
516 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front() );
518 m_pDoc->DeleteTab(0);
521 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSingleCellToRange)
523 //e.g. fdo#82503
524 m_pDoc->InsertTab(0, "Test");
526 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
527 ScRange aCondFormatRange(0,0,0,3,3,0);
528 ScRangeList aRangeList(aCondFormatRange);
529 pFormat->SetRange(aRangeList);
531 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
532 pFormat->AddEntry(pEntry);
533 sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
535 ScDocument aClipDoc(SCDOCMODE_CLIP);
536 copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
537 ScRange aTargetRange(4,4,0,5,8,0);
538 pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
540 // Pasting the same conditional format must modify existing format, making its range
541 // combined of previous range and newly pasted range having the conditional format.
542 // No new conditional formats must be created.
543 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
544 aRangeList.Join(aTargetRange);
545 for(SCROW nRow = 4; nRow <= 8; ++nRow)
547 for (SCCOL nCol = 4; nCol <= 5; ++nCol)
549 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(nCol, nRow, 0);
550 CPPUNIT_ASSERT(pPastedFormat);
552 CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
553 sal_uLong nPastedKey = pPastedFormat->GetKey();
554 CPPUNIT_ASSERT_EQUAL(nIndex, nPastedKey);
555 const SfxPoolItem* pItem = m_pDoc->GetAttr( nCol, nRow, 0, ATTR_CONDITIONAL );
556 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
558 CPPUNIT_ASSERT(pCondFormatItem);
559 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
560 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front() );
564 m_pDoc->DeleteTab(0);
567 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSingleCellIntoSameFormatRange)
569 // e.g., tdf#95295
570 m_pDoc->InsertTab(0, "Test");
572 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
573 ScRange aCondFormatRange(0, 0, 0, 3, 3, 0);
574 ScRangeList aRangeList(aCondFormatRange);
575 pFormat->SetRange(aRangeList);
577 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct, "=B2", "", *m_pDoc, ScAddress(0, 0, 0), ScResId(STR_STYLENAME_RESULT));
578 pFormat->AddEntry(pEntry);
579 sal_uLong nIndex = m_pDoc->AddCondFormat(std::move(pFormat), 0);
581 ScDocument aClipDoc(SCDOCMODE_CLIP);
582 copyToClip(m_pDoc, ScRange(1, 1, 0, 1, 1, 0), &aClipDoc);
584 ScRange aTargetRange(2, 2, 0, 2, 2, 0);
585 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
587 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(2, 2, 0);
588 CPPUNIT_ASSERT(pPastedFormat);
590 // Pasting the same conditional format into the same range must not modify existing format,
591 // since it already covers the pasted range. No new conditional formats must be created.
592 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
593 CPPUNIT_ASSERT_EQUAL(aRangeList, pPastedFormat->GetRange());
594 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pPastedFormat->GetKey());
595 const SfxPoolItem* pItem = m_pDoc->GetAttr(2, 2, 0, ATTR_CONDITIONAL);
596 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
598 CPPUNIT_ASSERT(pCondFormatItem);
599 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
600 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nIndex), pCondFormatItem->GetCondFormatData().front());
602 m_pDoc->DeleteTab(0);
605 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSingleRowToRange)
607 //e.g. tdf#106242
608 m_pDoc->InsertTab(0, "Test");
610 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
611 ScRange aCondFormatRange(0,0,0,0,0,0);
612 ScRangeList aRangeList(aCondFormatRange);
613 pFormat->SetRange(aRangeList);
615 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
616 pFormat->AddEntry(pEntry);
617 auto pFormatTmp = pFormat.get();
618 m_pDoc->AddCondFormat(std::move(pFormat), 0);
620 ScDocument aClipDoc(SCDOCMODE_CLIP);
621 copyToClip(m_pDoc, ScRange(0,0,0,m_pDoc->MaxCol(),0,0), &aClipDoc);
622 ScRange aTargetRange(0,4,0,m_pDoc->MaxCol(),4,0);
623 pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
625 ScConditionalFormat* pNewFormat = m_pDoc->GetCondFormat(0, 4, 0);
626 CPPUNIT_ASSERT(pNewFormat);
627 CPPUNIT_ASSERT_EQUAL(pNewFormat->GetKey(), pFormatTmp->GetKey());
629 for (SCCOL nCol = 1; nCol <= m_pDoc->MaxCol(); ++nCol)
631 ScConditionalFormat* pNewFormat2 = m_pDoc->GetCondFormat(nCol, 4, 0);
632 CPPUNIT_ASSERT(!pNewFormat2);
635 m_pDoc->DeleteTab(0);
638 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSingleRowToRange2)
640 m_pDoc->InsertTab(0, "Test");
642 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
643 ScRange aCondFormatRange(0,0,0,0,0,0);
644 ScRangeList aRangeList(aCondFormatRange);
645 pFormat->SetRange(aRangeList);
647 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
648 pFormat->AddEntry(pEntry);
649 m_pDoc->AddCondFormat(std::move(pFormat), 0);
651 ScDocument aClipDoc(SCDOCMODE_CLIP);
652 copyToClip(m_pDoc, ScRange(0,0,0,3,0,0), &aClipDoc);
653 ScRange aTargetRange(0,4,0,m_pDoc->MaxCol(),4,0);
654 pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
656 for (SCCOL nCol = 0; nCol <= m_pDoc->MaxCol(); ++nCol)
658 ScConditionalFormat* pNewFormat = m_pDoc->GetCondFormat(nCol, 4, 0);
659 if (nCol % 4 == 0)
660 CPPUNIT_ASSERT(pNewFormat);
661 else
662 CPPUNIT_ASSERT(!pNewFormat);
665 m_pDoc->DeleteTab(0);
668 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSheetBetweenDoc)
670 m_pDoc->InsertTab(0, "Test");
672 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
673 ScRange aCondFormatRange(0,0,0,3,3,0);
674 ScRangeList aRangeList(aCondFormatRange);
675 pFormat->SetRange(aRangeList);
677 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
678 pFormat->AddEntry(pEntry);
679 m_pDoc->AddCondFormat(std::move(pFormat), 0);
681 ScDocument aDoc;
682 aDoc.TransferTab(*m_pDoc, 0, 0);
684 ScConditionalFormatList* pList = aDoc.GetCondFormList(0);
685 CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
687 m_pDoc->DeleteTab(0);
690 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondCopyPasteSheet)
692 m_pDoc->InsertTab(0, "Test");
694 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
695 ScRange aCondFormatRange(0,0,0,3,3,0);
696 ScRangeList aRangeList(aCondFormatRange);
697 pFormat->SetRange(aRangeList);
699 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct,"=B2","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
700 pFormat->AddEntry(pEntry);
701 m_pDoc->AddCondFormat(std::move(pFormat), 0);
703 m_pDoc->CopyTab(0, SC_TAB_APPEND);
705 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(1);
706 CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
708 ScConditionalFormat& rFormat = **pList->begin();
709 const ScRangeList& rRange = rFormat.GetRange();
710 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,1,3,3,1)), rRange);
711 sal_uInt32 nKey = rFormat.GetKey();
712 const SfxPoolItem* pItem = m_pDoc->GetAttr( 2, 2, 1, ATTR_CONDITIONAL );
713 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
715 CPPUNIT_ASSERT(pCondFormatItem);
716 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
717 CPPUNIT_ASSERT_EQUAL( nKey, pCondFormatItem->GetCondFormatData().front() );
719 m_pDoc->DeleteTab(1);
720 m_pDoc->DeleteTab(0);
723 CPPUNIT_TEST_FIXTURE(TestCondformat, testIconSet)
725 m_pDoc->InsertTab(0, "Test");
726 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
728 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
729 ScRangeList aRangeList(ScRange(0,0,0,0,0,0));
730 pFormat->SetRange(aRangeList);
732 ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc);
733 ScIconSetFormatData* pData = new ScIconSetFormatData;
734 pData->m_Entries.emplace_back(new ScColorScaleEntry(0, COL_BLUE));
735 pData->m_Entries.emplace_back(new ScColorScaleEntry(1, COL_GREEN));
736 pData->m_Entries.emplace_back(new ScColorScaleEntry(2, COL_RED));
737 pEntry->SetIconSetData(pData);
739 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
740 pList->InsertNew(std::move(pFormat));
742 static struct {
743 double nVal; sal_Int32 nIndex;
744 } const aTests[] = {
745 { -1.0, 0 },
746 { 0.0, 0 },
747 { 1.0, 1 },
748 { 2.0, 2 },
749 { 3.0, 2 }
751 for(size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
753 m_pDoc->SetValue(0,0,0,aTests[i].nVal);
754 std::unique_ptr<ScIconSetInfo> pInfo = pEntry->GetIconSetInfo(ScAddress(0,0,0));
755 CPPUNIT_ASSERT_EQUAL(aTests[i].nIndex, pInfo->nIconIndex);
758 delete pEntry;
759 m_pDoc->DeleteTab(0);
762 CPPUNIT_TEST_FIXTURE(TestCondformat, testDataBarLengthAutomaticAxis)
764 m_pDoc->InsertTab(0, "Test");
766 static const ScDataBarLengthData aValues[] = {
767 { 2, 0 },
768 { 3, 0 },
769 { 4, 25.0 },
770 { 5, 50.0 },
771 { 6, 75.0 },
772 { 7, 100.0 },
773 { 8, 100.0 },
774 { 9, 100.0 },
775 { 0, -200 }
778 testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,7,0),
779 3, COLORSCALE_VALUE, 7, COLORSCALE_VALUE, 0.0, databar::AUTOMATIC);
781 static const ScDataBarLengthData aValues2[] = {
782 { -6, -100 },
783 { -5, -100 },
784 { -4, -100 },
785 { -3, -75.0 },
786 { -2, -50.0 },
787 { -1, -25.0 },
788 { 0, 0.0 },
789 { 1, 12.5 },
790 { 2, 25.0 },
791 { 3, 37.5 },
792 { 4, 50.0 },
793 { 5, 62.5 },
794 { 6, 75.0 },
795 { 7, 87.5 },
796 { 8, 100.0 },
797 { 9, 100.0 },
798 { 0, -200 }
800 testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
801 -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 1.0/3.0 * 100, databar::AUTOMATIC);
803 static const ScDataBarLengthData aValues3[] = {
804 { 2, 0.0 },
805 { 3, 25.0 },
806 { 4, 50.0 },
807 { 6, 100.0 },
808 { 0, -200 }
810 testDataBarLengthImpl(m_pDoc, aValues3, ScRange(2,0,0,2,3,0),
811 0, COLORSCALE_MIN, 0, COLORSCALE_MAX, 0, databar::AUTOMATIC);
813 static const ScDataBarLengthData aValues4[] = {
814 { 2, 40.0 },
815 { 3, 60.0 },
816 { 4, 80.0 },
817 { 5, 100.0 },
818 { 0, -200 }
820 testDataBarLengthImpl(m_pDoc, aValues4, ScRange(3,0,0,3,3,0),
821 0, COLORSCALE_AUTO, 0, COLORSCALE_AUTO, 0, databar::AUTOMATIC);
823 m_pDoc->DeleteTab(0);
826 CPPUNIT_TEST_FIXTURE(TestCondformat, testDataBarLengthMiddleAxis)
828 m_pDoc->InsertTab(0, "Test");
830 static const ScDataBarLengthData aValues[] = {
831 { 1, 25.0 },
832 { 2, 25.0 },
833 { 3, 37.5 },
834 { 4, 50.0 },
835 { 5, 62.5 },
836 { 6, 75.0 },
837 { 7, 87.5 },
838 { 8, 100.0 },
839 { 9, 100.0 },
840 { 0, -200 }
843 testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,8,0),
844 2, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
846 static const ScDataBarLengthData aValues2[] = {
847 { -6, -50 },
848 { -5, -50 },
849 { -4, -50 },
850 { -3, -37.5 },
851 { -2, -25.0 },
852 { -1, -12.5 },
853 { 0, 0.0 },
854 { 1, 12.5 },
855 { 2, 25.0 },
856 { 3, 37.5 },
857 { 4, 50.0 },
858 { 5, 62.5 },
859 { 6, 75.0 },
860 { 7, 87.5 },
861 { 8, 100.0 },
862 { 9, 100.0 },
863 { 0, -200 }
865 testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
866 -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
868 m_pDoc->DeleteTab(0);
871 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatEndsWithStr)
873 m_pDoc->InsertTab(0, "Test");
875 // case insensitive matching
876 ScConditionEntry aEntry(ScConditionMode::EndsWith, "\"teststring\"", "", *m_pDoc, ScAddress(),
877 "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
879 svl::SharedStringPool& rStringPool = m_pDoc->GetSharedStringPool();
880 svl::SharedString aStr = rStringPool.intern("SimpleTestString");
881 ScRefCellValue aVal(&aStr);
882 ScAddress aPos(0, 0, 0);
884 bool bValid = aEntry.IsCellValid(aVal, aPos);
885 CPPUNIT_ASSERT(bValid);
887 m_pDoc->DeleteTab(0);
890 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatEndsWithVal)
892 m_pDoc->InsertTab(0, "Test");
894 ScConditionEntry aEntry(ScConditionMode::EndsWith, "2", "", *m_pDoc, ScAddress(),
895 "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
897 for (sal_Int32 i = 0; i < 15; ++i)
899 ScRefCellValue aVal(i);
900 ScAddress aPos(0, 0, 0);
902 bool bValid = aEntry.IsCellValid(aVal, aPos);
903 bool bShouldBeValid = (i % 10) == 2;
904 CPPUNIT_ASSERT_EQUAL(bShouldBeValid, bValid);
907 m_pDoc->DeleteTab(0);
910 CPPUNIT_TEST_FIXTURE(TestCondformat, testFormulaListenerSingleCellToSingleCell)
912 m_pDoc->InsertTab(0, "test");
914 ScCompiler aCompiler(*m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
916 std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
918 ScFormulaListener aListener(*m_pDoc);
920 aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
922 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
923 CPPUNIT_ASSERT(aListener.NeedsRepaint());
925 m_pDoc->DeleteTab(0);
928 CPPUNIT_TEST_FIXTURE(TestCondformat, testFormulaListenerSingleCellToMultipleCells)
930 m_pDoc->InsertTab(0, "test");
932 ScCompiler aCompiler(*m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
934 std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
936 ScFormulaListener aListener(*m_pDoc);
938 aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
940 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
941 CPPUNIT_ASSERT(aListener.NeedsRepaint());
943 m_pDoc->DeleteTab(0);
946 CPPUNIT_TEST_FIXTURE(TestCondformat, testFormulaListenerMultipleCellsToSingleCell)
948 m_pDoc->InsertTab(0, "test");
950 ScCompiler aCompiler(*m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
952 std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
954 ScFormulaListener aListener(*m_pDoc);
956 aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
958 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
959 CPPUNIT_ASSERT(aListener.NeedsRepaint());
961 m_pDoc->DeleteTab(0);
964 CPPUNIT_TEST_FIXTURE(TestCondformat, testFormulaListenerMultipleCellsToMultipleCells)
966 m_pDoc->InsertTab(0, "test");
968 ScCompiler aCompiler(*m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
970 std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
972 ScFormulaListener aListener(*m_pDoc);
974 aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
976 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
977 CPPUNIT_ASSERT(aListener.NeedsRepaint());
979 m_pDoc->DeleteTab(0);
982 CPPUNIT_TEST_FIXTURE(TestCondformat, testFormulaListenerUpdateInsertTab)
984 m_pDoc->InsertTab(0, "test");
986 ScCompiler aCompiler(*m_pDoc, ScAddress(10, 10, 0), formula::FormulaGrammar::GRAM_ENGLISH);
987 std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
989 ScFormulaListener aListener(*m_pDoc);
990 aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 0));
991 CPPUNIT_ASSERT(!aListener.NeedsRepaint());
993 m_pDoc->InsertTab(0, "new_tab");
995 // check that the listener has moved to the new sheet
996 m_pDoc->SetValue(ScAddress(0, 0, 1), 1.0);
997 CPPUNIT_ASSERT(aListener.NeedsRepaint());
999 // check that we are not listening to the old sheet
1000 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
1001 CPPUNIT_ASSERT(!aListener.NeedsRepaint());
1003 m_pDoc->DeleteTab(0);
1006 CPPUNIT_TEST_FIXTURE(TestCondformat, testFormulaListenerUpdateDeleteTab)
1008 m_pDoc->InsertTab(0, "test");
1009 m_pDoc->InsertTab(0, "to_delete");
1011 ScCompiler aCompiler(*m_pDoc, ScAddress(10, 10, 1), formula::FormulaGrammar::GRAM_ENGLISH);
1012 std::unique_ptr<ScTokenArray> pTokenArray(aCompiler.CompileString("A1"));
1014 ScFormulaListener aListener(*m_pDoc);
1015 aListener.addTokenArray(pTokenArray.get(), ScAddress(10, 10, 1));
1016 CPPUNIT_ASSERT(!aListener.NeedsRepaint());
1018 m_pDoc->DeleteTab(0);
1020 // check that the listener has moved
1021 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
1022 CPPUNIT_ASSERT(aListener.NeedsRepaint());
1024 m_pDoc->DeleteTab(0);
1027 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUpdateMoveTab)
1029 m_pDoc->InsertTab(0, "test");
1030 m_pDoc->InsertTab(1, "Test2");
1032 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", *m_pDoc, ScAddress(10, 10, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1034 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1035 pFormat->SetRange(ScRange(10, 10, 0, 10, 12, 0));
1036 auto pFormatTmp = pFormat.get();
1037 m_pDoc->AddCondFormat(std::move(pFormat), 0);
1039 pFormatTmp->AddEntry(pEntry);
1041 // the conditional format should listen to A1:A3
1042 for (SCROW nRow = 0; nRow < 3; ++nRow)
1044 m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1045 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1048 m_pDoc->MoveTab(0, 1);
1050 // the conditional format should listen to A1:A3 on the second sheet
1051 for (SCROW nRow = 0; nRow < 3; ++nRow)
1053 m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
1054 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1056 m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1057 CPPUNIT_ASSERT(!pEntry->NeedsRepaint());
1060 m_pDoc->DeleteTab(1);
1061 m_pDoc->DeleteTab(0);
1064 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUpdateInsertTab)
1066 m_pDoc->InsertTab(0, "test");
1068 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", *m_pDoc, ScAddress(10, 10, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1070 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1071 pFormat->SetRange(ScRange(10, 10, 0, 10, 12, 0));
1072 auto pFormatTmp = pFormat.get();
1073 m_pDoc->AddCondFormat(std::move(pFormat), 0);
1075 pFormatTmp->AddEntry(pEntry);
1077 // the conditional format should listen to A1:A3
1078 for (SCROW nRow = 0; nRow < 3; ++nRow)
1080 m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1081 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1083 m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
1084 CPPUNIT_ASSERT(!pEntry->NeedsRepaint());
1087 m_pDoc->InsertTab(0, "test2");
1089 // the conditional format should listen to A1:A3 on the second sheet
1090 for (SCROW nRow = 0; nRow < 3; ++nRow)
1092 m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
1093 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1095 m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1096 CPPUNIT_ASSERT(!pEntry->NeedsRepaint());
1099 m_pDoc->DeleteTab(1);
1100 m_pDoc->DeleteTab(0);
1103 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUpdateDeleteTab)
1105 m_pDoc->InsertTab(0, "test");
1106 m_pDoc->InsertTab(1, "Test2");
1108 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", *m_pDoc, ScAddress(10, 10, 1), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1110 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1111 pFormat->SetRange(ScRange(10, 10, 1, 10, 12, 1));
1112 auto pFormatTmp = pFormat.get();
1113 m_pDoc->AddCondFormat(std::move(pFormat), 1);
1115 pFormatTmp->AddEntry(pEntry);
1117 // the conditional format should listen to A1:A3 on the second sheet
1118 for (SCROW nRow = 0; nRow < 3; ++nRow)
1120 m_pDoc->SetValue(ScAddress(0, nRow, 1), 1.0);
1121 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1124 m_pDoc->DeleteTab(0);
1126 // the conditional format should listen to A1:A3 on the second sheet
1127 for (SCROW nRow = 0; nRow < 3; ++nRow)
1129 m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1130 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1133 m_pDoc->DeleteTab(0);
1136 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUpdateReference)
1138 m_pDoc->InsertTab(0, "test");
1139 m_pDoc->InsertTab(1, "Test2");
1141 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "A1", "", *m_pDoc, ScAddress(10, 10, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1143 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1144 pFormat->SetRange(ScRange(10, 10, 0, 10, 12, 0));
1145 auto pFormatTmp = pFormat.get();
1146 m_pDoc->AddCondFormat(std::move(pFormat), 0);
1148 pFormatTmp->AddEntry(pEntry);
1150 // the conditional format should listen to A1:A3
1151 for (SCROW nRow = 0; nRow < 3; ++nRow)
1153 m_pDoc->SetValue(ScAddress(0, nRow, 0), 1.0);
1154 CPPUNIT_ASSERT(pEntry->NeedsRepaint());
1157 m_pDoc->DeleteTab(1);
1158 m_pDoc->DeleteTab(0);
1161 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUpdateReferenceDelRow)
1163 m_pDoc->InsertTab(0, "test");
1165 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "B6", "", *m_pDoc, ScAddress(0, 5, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1167 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1168 pFormat->SetRange(ScRange(0, 5, 0, 0, 5, 0));
1169 auto pFormatTmp = pFormat.get();
1170 m_pDoc->AddCondFormat(std::move(pFormat), 0);
1172 pFormatTmp->AddEntry(pEntry);
1174 m_pDoc->DeleteRow(0, 0, m_pDoc->MaxCol(), 0, 4, 1);
1176 OUString aStr = pEntry->GetExpression(ScAddress(0, 4, 0), 0);
1177 CPPUNIT_ASSERT_EQUAL(OUString("B5"), aStr);
1179 m_pDoc->DeleteTab(0);
1182 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUpdateReferenceInsRow)
1184 m_pDoc->InsertTab(0, "test");
1186 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "B6", "", *m_pDoc, ScAddress(0, 5, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1188 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1189 pFormat->SetRange(ScRange(0, 5, 0, 0, 5, 0));
1190 auto pFormatTmp = pFormat.get();
1191 m_pDoc->AddCondFormat(std::move(pFormat), 0);
1193 pFormatTmp->AddEntry(pEntry);
1195 m_pDoc->InsertRow(0, 0, m_pDoc->MaxCol(), 0, 4, 1);
1197 OUString aStr = pEntry->GetExpression(ScAddress(0, 6, 0), 0);
1198 CPPUNIT_ASSERT_EQUAL(OUString("B7"), aStr);
1200 m_pDoc->DeleteTab(0);
1203 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatUndoList)
1205 m_pDoc->InsertTab(0, "test");
1207 ScConditionEntry* pEntry = new ScConditionEntry(ScConditionMode::Equal, "B6", "", *m_pDoc, ScAddress(0, 5, 0), "", "", formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::GRAM_DEFAULT);
1209 auto pFormat = std::make_unique<ScConditionalFormat>(0, m_pDoc);
1210 pFormat->AddEntry(pEntry);
1211 pFormat->SetRange(ScRange(0, 0, 0, 0, 5, 0));
1212 auto pFormatTmp = pFormat.get();
1213 m_pDoc->AddCondFormat(std::move(pFormat), 0);
1214 m_pDoc->AddCondFormatData(pFormatTmp->GetRange(), 0, pFormatTmp->GetKey());
1216 ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
1218 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
1219 for (SCROW nRow = 0; nRow <= 5; ++nRow)
1220 CPPUNIT_ASSERT(m_pDoc->GetCondFormat(0, nRow, 0));
1222 ScConditionalFormatList* pNewList = new ScConditionalFormatList();
1224 rFunc.SetConditionalFormatList(pNewList, 0);
1226 CPPUNIT_ASSERT_EQUAL(size_t(0), m_pDoc->GetCondFormList(0)->size());
1227 for (SCROW nRow = 0; nRow <= 5; ++nRow)
1228 CPPUNIT_ASSERT(!m_pDoc->GetCondFormat(0, nRow, 0));
1230 m_pDoc->GetUndoManager()->Undo();
1232 CPPUNIT_ASSERT_EQUAL(size_t(1), m_pDoc->GetCondFormList(0)->size());
1233 for (SCROW nRow = 0; nRow <= 5; ++nRow)
1234 CPPUNIT_ASSERT(m_pDoc->GetCondFormat(0, nRow, 0));
1236 m_pDoc->GetUndoManager()->Redo();
1238 CPPUNIT_ASSERT_EQUAL(size_t(0), m_pDoc->GetCondFormList(0)->size());
1239 for (SCROW nRow = 0; nRow <= 5; ++nRow)
1240 CPPUNIT_ASSERT(!m_pDoc->GetCondFormat(0, nRow, 0));
1242 m_pDoc->DeleteTab(0);
1245 CPPUNIT_TEST_FIXTURE(TestCondformat, testMultipleSingleCellCondFormatCopyPaste)
1247 m_pDoc->InsertTab(0, "Test");
1249 sal_uInt32 nFirstCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(0, 0, 0), 1, "=A2");
1250 sal_uInt32 nSecondCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(1, 0, 0), 2, "=B3");
1252 ScDocument aClipDoc(SCDOCMODE_CLIP);
1253 copyToClip(m_pDoc, ScRange(0,0,0,2,0,0), &aClipDoc);
1254 ScRange aTargetRange(2,4,0,7,4,0);
1255 pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
1257 for (SCCOL nCol = 2; nCol <= 7; ++nCol)
1259 ScConditionalFormat* pFormat = m_pDoc->GetCondFormat(nCol, 4, 0);
1260 if (((nCol - 2) % 3) == 0)
1262 CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nFirstCondFormatKey);
1264 else if (((nCol - 2) % 3) == 1)
1266 CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nSecondCondFormatKey);
1268 else
1270 CPPUNIT_ASSERT(!pFormat);
1274 m_pDoc->DeleteTab(0);
1277 CPPUNIT_TEST_FIXTURE(TestCondformat, testDeduplicateMultipleCondFormats)
1279 m_pDoc->InsertTab(0, "Test");
1281 sal_uInt32 nFirstCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(0, 0, 0), 1, "=B2");
1282 sal_uInt32 nSecondCondFormatKey = addSingleCellCondFormat(m_pDoc, ScAddress(1, 0, 0), 2, "=B2");
1284 ScDocument aClipDoc(SCDOCMODE_CLIP);
1285 copyToClip(m_pDoc, ScRange(0,0,0,2,0,0), &aClipDoc);
1286 ScRange aTargetRange(2,4,0,7,4,0);
1287 pasteOneCellFromClip(m_pDoc, aTargetRange, &aClipDoc);
1289 for (SCCOL nCol = 2; nCol <= 7; ++nCol)
1291 ScConditionalFormat* pFormat = m_pDoc->GetCondFormat(nCol, 4, 0);
1292 if (((nCol - 2) % 3) == 0)
1294 CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nFirstCondFormatKey);
1296 else if (((nCol - 2) % 3) == 1)
1298 CPPUNIT_ASSERT_EQUAL(pFormat->GetKey(), nSecondCondFormatKey);
1300 else
1302 CPPUNIT_ASSERT(!pFormat);
1306 m_pDoc->DeleteTab(0);
1309 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatListenToOwnRange)
1311 m_pDoc->InsertTab(0, "Test");
1313 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
1315 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
1316 ScRangeList aRangeList(ScRange(0,0,0,10,0,0));
1317 pFormat->SetRange(aRangeList);
1319 ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc);
1320 ScIconSetFormatData* pData = new ScIconSetFormatData;
1321 pData->m_Entries.emplace_back(new ScColorScaleEntry(0, COL_BLUE));
1322 pData->m_Entries.emplace_back(new ScColorScaleEntry(1, COL_GREEN));
1323 pData->m_Entries.emplace_back(new ScColorScaleEntry(2, COL_RED));
1324 pEntry->SetIconSetData(pData);
1325 pEntry->SetParent(pFormat.get());
1327 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
1328 pFormat->AddEntry(pEntry);
1329 pList->InsertNew(std::move(pFormat));
1331 bool bFirstCallbackCalled = false;
1332 std::function<void()> aFirstCallback = [&]() {bFirstCallbackCalled = true;};
1333 pData->m_Entries[0]->SetType(COLORSCALE_PERCENT);
1334 pData->m_Entries[0]->SetRepaintCallback(aFirstCallback);
1336 m_pDoc->SetValue(0, 0, 0, -1.0);
1338 CPPUNIT_ASSERT(bFirstCallbackCalled);
1340 m_pDoc->DeleteTab(0);
1343 CPPUNIT_TEST_FIXTURE(TestCondformat, testCondFormatVolatileFunctionRecalc)
1345 m_pDoc->InsertTab(0, "Test");
1347 m_pDoc->SetValue(0, 0, 0, 0.5);
1349 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
1351 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
1352 ScRangeList aRangeList(ScRange(0,0,0,10,0,0));
1353 pFormat->SetRange(aRangeList);
1355 ScCondFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Greater,"RAND()","",*m_pDoc,ScAddress(0,0,0),ScResId(STR_STYLENAME_RESULT));
1356 pEntry->SetParent(pFormat.get());
1358 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
1359 pFormat->AddEntry(pEntry);
1360 auto pFormatTmp = pFormat.get();
1361 pList->InsertNew(std::move(pFormat));
1363 ScRefCellValue aCell(*m_pDoc, ScAddress(0, 0, 0));
1364 bool bValid = pEntry->IsCellValid(aCell, ScAddress(0, 0, 0));
1366 bool bNewValid = bValid;
1367 // chance of a random failure is 0.5^100, anyone hitting that will get a beer from me
1368 for (size_t i = 0; i < 100; ++i)
1370 pFormatTmp->CalcAll();
1371 bNewValid = pEntry->IsCellValid(aCell, ScAddress(0, 0, 0));
1373 if (bValid != bNewValid)
1374 break;
1377 CPPUNIT_ASSERT(bValid != bNewValid);
1379 m_pDoc->DeleteTab(0);
1382 CPPUNIT_TEST_FIXTURE(TestCondformat, testConditionStyleInMergedCell)
1384 m_pDoc->InsertTab(0, "Test");
1386 PaintListener aListener;
1387 aListener.StartListening(*m_xDocShell);
1389 m_pDoc->DoMerge(0, 0, 0, 1, 0); // A1:A2
1390 CPPUNIT_ASSERT(m_pDoc->IsMerged(ScAddress(0, 0, 0)));
1392 m_pDoc->SetValue(ScAddress(0, 0, 0), 1.0);
1394 // Add a conditional format.
1395 auto pFormat = std::make_unique<ScConditionalFormat>(1, m_pDoc);
1396 pFormat->SetRange(ScRange(0, 0, 0, 0, 0, 0));
1398 // Add condition in which if the value equals 1, set the "Good" style.
1399 ScCondFormatEntry* pEntry = new ScCondFormatEntry(
1400 ScConditionMode::Equal, "=1", "", *m_pDoc, ScAddress(0, 0, 0), ScResId(STR_STYLENAME_GOOD));
1401 pFormat->AddEntry(pEntry);
1403 // Apply the format to the range.
1404 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
1406 ScDocFunc& rFunc = m_xDocShell->GetDocFunc();
1407 sal_uInt32 nOldFormat = pFormat->GetKey();
1408 const ScRangeList& rRangeList = pFormat->GetRange();
1409 rFunc.ReplaceConditionalFormat(nOldFormat, std::move(pFormat), 0, rRangeList);
1411 CPPUNIT_ASSERT_EQUAL(true, aListener.mbPaintAllMergedCell);
1413 m_pDoc->DeleteTab(0);
1416 CPPUNIT_PLUGIN_IMPLEMENT();
1418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */