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 <colorscale.hxx>
12 #include <document.hxx>
13 #include <formulacell.hxx>
14 #include <fillinfo.hxx>
15 #include <bitmaps.hlst>
16 #include <tokenarray.hxx>
17 #include <refupdatecontext.hxx>
18 #include <refdata.hxx>
19
20 #include <formula/token.hxx>
21 #include <vcl/bitmapex.hxx>
22
23 #include <algorithm>
24 #include <cassert>
25 #include <string_view>
26
ScFormulaListener(ScFormulaCell * pCell)27 ScFormulaListener::ScFormulaListener(ScFormulaCell* pCell):
28 mbDirty(false),
29 mrDoc(pCell->GetDocument())
30 {
31 startListening( pCell->GetCode(), pCell->aPos );
32 }
33
ScFormulaListener(ScDocument & rDoc)34 ScFormulaListener::ScFormulaListener(ScDocument& rDoc):
35 mbDirty(false),
36 mrDoc(rDoc)
37 {
38 }
39
ScFormulaListener(ScDocument & rDoc,const ScRangeList & rRange)40 ScFormulaListener::ScFormulaListener(ScDocument& rDoc, const ScRangeList& rRange):
41 mbDirty(false),
42 mrDoc(rDoc)
43 {
44 startListening(rRange);
45 }
46
startListening(const ScTokenArray * pArr,const ScRange & rRange)47 void ScFormulaListener::startListening(const ScTokenArray* pArr, const ScRange& rRange)
48 {
49 if (!pArr || mrDoc.IsClipOrUndo())
50 return;
51
52 for ( auto t: pArr->References() )
53 {
54 switch (t->GetType())
55 {
56 case formula::svSingleRef:
57 {
58 ScAddress aCell = t->GetSingleRef()->toAbs(mrDoc, rRange.aStart);
59 ScAddress aCell2 = t->GetSingleRef()->toAbs(mrDoc, rRange.aEnd);
60 ScRange aRange(aCell, aCell2);
61 if (aRange.IsValid())
62 mrDoc.StartListeningArea(aRange, false, this);
63 }
64 break;
65 case formula::svDoubleRef:
66 {
67 const ScSingleRefData& rRef1 = *t->GetSingleRef();
68 const ScSingleRefData& rRef2 = *t->GetSingleRef2();
69 ScAddress aCell1 = rRef1.toAbs(mrDoc, rRange.aStart);
70 ScAddress aCell2 = rRef2.toAbs(mrDoc, rRange.aStart);
71 ScAddress aCell3 = rRef1.toAbs(mrDoc, rRange.aEnd);
72 ScAddress aCell4 = rRef2.toAbs(mrDoc, rRange.aEnd);
73 ScRange aRange1(aCell1, aCell3);
74 ScRange aRange2(aCell2, aCell4);
75 aRange1.ExtendTo(aRange2);
76 if (aRange1.IsValid())
77 {
78 if (t->GetOpCode() == ocColRowNameAuto)
79 { // automagically
80 if ( rRef1.IsColRel() )
81 { // ColName
82 aRange1.aEnd.SetRow(mrDoc.MaxRow());
83 }
84 else
85 { // RowName
86 aRange1.aEnd.SetCol(mrDoc.MaxCol());
87 }
88 }
89 mrDoc.StartListeningArea(aRange1, false, this);
90 }
91 }
92 break;
93 default:
94 ; // nothing
95 }
96 }
97 }
98
startListening(const ScRangeList & rRange)99 void ScFormulaListener::startListening(const ScRangeList& rRange)
100 {
101 if (mrDoc.IsClipOrUndo())
102 return;
103
104 size_t nLength = rRange.size();
105 for (size_t i = 0; i < nLength; ++i)
106 {
107 const ScRange& aRange = rRange[i];
108 mrDoc.StartListeningArea(aRange, false, this);
109 }
110 }
111
addTokenArray(const ScTokenArray * pArray,const ScRange & rRange)112 void ScFormulaListener::addTokenArray(const ScTokenArray* pArray, const ScRange& rRange)
113 {
114 startListening(pArray, rRange);
115 }
116
setCallback(const std::function<void ()> & aCallback)117 void ScFormulaListener::setCallback(const std::function<void()>& aCallback)
118 {
119 maCallbackFunction = aCallback;
120 }
121
stopListening()122 void ScFormulaListener::stopListening()
123 {
124 if (mrDoc.IsClipOrUndo())
125 return;
126
127 EndListeningAll();
128 }
129
~ScFormulaListener()130 ScFormulaListener::~ScFormulaListener()
131 {
132 stopListening();
133 }
134
Notify(const SfxHint & rHint)135 void ScFormulaListener::Notify(const SfxHint& rHint)
136 {
137 mbDirty = true;
138
139 if (rHint.GetId() == SfxHintId::Dying)
140 return;
141
142 if (maCallbackFunction)
143 maCallbackFunction();
144 }
145
NeedsRepaint() const146 bool ScFormulaListener::NeedsRepaint() const
147 {
148 bool bRet = mbDirty;
149 mbDirty = false;
150 return bRet;
151 }
152
ScColorScaleEntry()153 ScColorScaleEntry::ScColorScaleEntry():
154 mnVal(0),
155 mpFormat(nullptr),
156 meType(COLORSCALE_VALUE)
157 {
158 }
159
ScColorScaleEntry(double nVal,const Color & rCol,ScColorScaleEntryType eType)160 ScColorScaleEntry::ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType):
161 mnVal(nVal),
162 mpFormat(nullptr),
163 maColor(rCol),
164 meType(eType)
165 {
166 }
167
ScColorScaleEntry(const ScColorScaleEntry & rEntry)168 ScColorScaleEntry::ScColorScaleEntry(const ScColorScaleEntry& rEntry):
169 mnVal(rEntry.mnVal),
170 mpFormat(rEntry.mpFormat),
171 maColor(rEntry.maColor),
172 meType(rEntry.meType)
173 {
174 setListener();
175 if(rEntry.mpCell)
176 {
177 mpCell.reset(new ScFormulaCell(*rEntry.mpCell, rEntry.mpCell->GetDocument(), rEntry.mpCell->aPos, ScCloneFlags::NoMakeAbsExternal));
178 mpCell->StartListeningTo(mpCell->GetDocument());
179 mpListener.reset(new ScFormulaListener(mpCell.get()));
180 }
181 }
182
ScColorScaleEntry(ScDocument * pDoc,const ScColorScaleEntry & rEntry)183 ScColorScaleEntry::ScColorScaleEntry(ScDocument* pDoc, const ScColorScaleEntry& rEntry):
184 mnVal(rEntry.mnVal),
185 mpCell(),
186 mpFormat(rEntry.mpFormat),
187 maColor(rEntry.maColor),
188 meType(rEntry.meType)
189 {
190 setListener();
191 if(rEntry.mpCell)
192 {
193 mpCell.reset(new ScFormulaCell(*rEntry.mpCell, rEntry.mpCell->GetDocument(), rEntry.mpCell->aPos, ScCloneFlags::NoMakeAbsExternal));
194 mpCell->StartListeningTo( *pDoc );
195 mpListener.reset(new ScFormulaListener(mpCell.get()));
196 if (mpFormat)
197 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
198 }
199 }
200
~ScColorScaleEntry()201 ScColorScaleEntry::~ScColorScaleEntry() COVERITY_NOEXCEPT_FALSE
202 {
203 if(mpCell)
204 mpCell->EndListeningTo(mpCell->GetDocument());
205 }
206
SetFormula(const OUString & rFormula,ScDocument & rDoc,const ScAddress & rAddr,formula::FormulaGrammar::Grammar eGrammar)207 void ScColorScaleEntry::SetFormula( const OUString& rFormula, ScDocument& rDoc, const ScAddress& rAddr, formula::FormulaGrammar::Grammar eGrammar )
208 {
209 mpCell.reset(new ScFormulaCell( rDoc, rAddr, rFormula, eGrammar ));
210 mpCell->StartListeningTo( rDoc );
211 mpListener.reset(new ScFormulaListener(mpCell.get()));
212 if (mpFormat)
213 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
214 }
215
GetFormula() const216 const ScTokenArray* ScColorScaleEntry::GetFormula() const
217 {
218 if(mpCell)
219 {
220 return mpCell->GetCode();
221 }
222
223 return nullptr;
224 }
225
GetFormula(formula::FormulaGrammar::Grammar eGrammar) const226 OUString ScColorScaleEntry::GetFormula( formula::FormulaGrammar::Grammar eGrammar ) const
227 {
228 OUString aFormula;
229 if(mpCell)
230 {
231 mpCell->GetFormula(aFormula, eGrammar);
232 }
233
234 return aFormula;
235 }
236
GetValue() const237 double ScColorScaleEntry::GetValue() const
238 {
239 if(mpCell)
240 {
241 mpCell->Interpret();
242 if(mpCell->IsValue())
243 return mpCell->GetValue();
244
245 return std::numeric_limits<double>::max();
246 }
247
248 return mnVal;
249 }
250
SetValue(double nValue)251 void ScColorScaleEntry::SetValue(double nValue)
252 {
253 mnVal = nValue;
254 mpCell.reset();
255 setListener();
256 }
257
UpdateReference(const sc::RefUpdateContext & rCxt)258 void ScColorScaleEntry::UpdateReference( const sc::RefUpdateContext& rCxt )
259 {
260 if (!mpCell)
261 {
262 setListener();
263 return;
264 }
265
266 mpCell->UpdateReference(rCxt);
267 mpListener.reset(new ScFormulaListener(mpCell.get()));
268 SetRepaintCallback(mpFormat);
269 }
270
UpdateInsertTab(const sc::RefUpdateInsertTabContext & rCxt)271 void ScColorScaleEntry::UpdateInsertTab( const sc::RefUpdateInsertTabContext& rCxt )
272 {
273 if (!mpCell)
274 {
275 setListener();
276 return;
277 }
278
279 mpCell->UpdateInsertTab(rCxt);
280 mpListener.reset(new ScFormulaListener(mpCell.get()));
281 SetRepaintCallback(mpFormat);
282 }
283
UpdateDeleteTab(const sc::RefUpdateDeleteTabContext & rCxt)284 void ScColorScaleEntry::UpdateDeleteTab( const sc::RefUpdateDeleteTabContext& rCxt )
285 {
286 if (!mpCell)
287 {
288 setListener();
289 return;
290 }
291
292 mpCell->UpdateDeleteTab(rCxt);
293 mpListener.reset(new ScFormulaListener(mpCell.get()));
294 SetRepaintCallback(mpFormat);
295 }
296
UpdateMoveTab(const sc::RefUpdateMoveTabContext & rCxt)297 void ScColorScaleEntry::UpdateMoveTab( const sc::RefUpdateMoveTabContext& rCxt )
298 {
299 if (!mpCell)
300 {
301 setListener();
302 return;
303 }
304
305 SCTAB nTabNo = rCxt.getNewTab(mpCell->aPos.Tab());
306 mpCell->UpdateMoveTab(rCxt, nTabNo);
307 mpListener.reset(new ScFormulaListener(mpCell.get()));
308 SetRepaintCallback(mpFormat);
309 }
310
SetColor(const Color & rColor)311 void ScColorScaleEntry::SetColor(const Color& rColor)
312 {
313 maColor = rColor;
314 }
315
SetRepaintCallback(ScConditionalFormat * pFormat)316 void ScColorScaleEntry::SetRepaintCallback(ScConditionalFormat* pFormat)
317 {
318 mpFormat = pFormat;
319 setListener();
320 if (mpFormat && mpListener)
321 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
322 }
323
SetType(ScColorScaleEntryType eType)324 void ScColorScaleEntry::SetType( ScColorScaleEntryType eType )
325 {
326 meType = eType;
327 if(eType != COLORSCALE_FORMULA)
328 {
329 mpCell.reset();
330 mpListener.reset();
331 }
332
333 setListener();
334 }
335
setListener()336 void ScColorScaleEntry::setListener()
337 {
338 if (!mpFormat)
339 return;
340
341 if (meType == COLORSCALE_PERCENT || meType == COLORSCALE_PERCENTILE
342 || meType == COLORSCALE_MIN || meType == COLORSCALE_MAX
343 || meType == COLORSCALE_AUTO)
344 {
345 mpListener.reset(new ScFormulaListener(*mpFormat->GetDocument(), mpFormat->GetRange()));
346 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
347 }
348 }
349
SetRepaintCallback(const std::function<void ()> & func)350 void ScColorScaleEntry::SetRepaintCallback(const std::function<void()>& func)
351 {
352 mpListener->setCallback(func);
353 }
354
ScColorFormat(ScDocument * pDoc)355 ScColorFormat::ScColorFormat(ScDocument* pDoc)
356 : ScFormatEntry(pDoc)
357 , mpParent(nullptr)
358 {
359 }
360
~ScColorFormat()361 ScColorFormat::~ScColorFormat()
362 {
363 }
364
SetParent(ScConditionalFormat * pParent)365 void ScColorFormat::SetParent( ScConditionalFormat* pParent )
366 {
367 mpParent = pParent;
368 }
369
ScColorScaleFormat(ScDocument * pDoc)370 ScColorScaleFormat::ScColorScaleFormat(ScDocument* pDoc):
371 ScColorFormat(pDoc)
372 {
373 }
374
ScColorScaleFormat(ScDocument * pDoc,const ScColorScaleFormat & rFormat)375 ScColorScaleFormat::ScColorScaleFormat(ScDocument* pDoc, const ScColorScaleFormat& rFormat):
376 ScColorFormat(pDoc)
377 {
378 for(const auto& rxEntry : rFormat)
379 {
380 maColorScales.emplace_back(new ScColorScaleEntry(pDoc, *rxEntry));
381 }
382 }
383
Clone(ScDocument * pDoc) const384 ScColorFormat* ScColorScaleFormat::Clone(ScDocument* pDoc) const
385 {
386 return new ScColorScaleFormat(pDoc, *this);
387 }
388
~ScColorScaleFormat()389 ScColorScaleFormat::~ScColorScaleFormat()
390 {
391 }
392
SetParent(ScConditionalFormat * pFormat)393 void ScColorScaleFormat::SetParent(ScConditionalFormat* pFormat)
394 {
395 for (auto itr = begin(), itrEnd = end(); itr != itrEnd; ++itr)
396 {
397 (*itr)->SetRepaintCallback(pFormat);
398 }
399 ScColorFormat::SetParent(pFormat);
400 }
401
AddEntry(ScColorScaleEntry * pEntry)402 void ScColorScaleFormat::AddEntry( ScColorScaleEntry* pEntry )
403 {
404 maColorScales.push_back(std::unique_ptr<ScColorScaleEntry, o3tl::default_delete<ScColorScaleEntry>>(pEntry));
405 maColorScales.back()->SetRepaintCallback(mpParent);
406 }
407
GetMinValue() const408 double ScColorScaleFormat::GetMinValue() const
409 {
410 ScColorScaleEntries::const_iterator itr = maColorScales.begin();
411
412 if((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
413 return (*itr)->GetValue();
414 else
415 {
416 return getMinValue();
417 }
418 }
419
GetMaxValue() const420 double ScColorScaleFormat::GetMaxValue() const
421 {
422 ScColorScaleEntries::const_reverse_iterator itr = maColorScales.rbegin();
423
424 if((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
425 return (*itr)->GetValue();
426 else
427 {
428 return getMaxValue();
429 }
430 }
431
calcMinMax(double & rMin,double & rMax) const432 void ScColorScaleFormat::calcMinMax(double& rMin, double& rMax) const
433 {
434 rMin = GetMinValue();
435 rMax = GetMaxValue();
436 }
437
GetRange() const438 const ScRangeList& ScColorFormat::GetRange() const
439 {
440 return mpParent->GetRange();
441 }
442
getValues() const443 std::vector<double>& ScColorFormat::getValues() const
444 {
445 if(!mpCache)
446 {
447 mpCache.reset(new ScColorFormatCache);
448 std::vector<double>& rValues = mpCache->maValues;
449
450 size_t n = GetRange().size();
451 const ScRangeList& aRanges = GetRange();
452 for(size_t i = 0; i < n; ++i)
453 {
454 const ScRange & rRange = aRanges[i];
455 SCTAB nTab = rRange.aStart.Tab();
456
457 SCCOL nColStart = rRange.aStart.Col();
458 SCROW nRowStart = rRange.aStart.Row();
459 SCCOL nColEnd = rRange.aEnd.Col();
460 SCROW nRowEnd = rRange.aEnd.Row();
461
462 if(nRowEnd == MAXROW)
463 {
464 bool bShrunk = false;
465 mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
466 nColEnd, nRowEnd, false);
467 }
468 for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
469 {
470 for(SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
471 {
472 ScAddress aAddr(nCol, nRow, nTab);
473 ScRefCellValue rCell(*mpDoc, aAddr);
474 if(rCell.hasNumeric())
475 {
476 double aVal = rCell.getValue();
477 rValues.push_back(aVal);
478 }
479 }
480 }
481 }
482
483 std::sort(rValues.begin(), rValues.end());
484 }
485
486 return mpCache->maValues;
487 }
488
getMinValue() const489 double ScColorFormat::getMinValue() const
490 {
491 std::vector<double>& rValues = getValues();
492 if(rValues.empty())
493 return 0;
494 return rValues[0];
495 }
496
getMaxValue() const497 double ScColorFormat::getMaxValue() const
498 {
499 std::vector<double>& rValues = getValues();
500 if(rValues.empty())
501 return 0;
502 return rValues[rValues.size()-1];
503 }
504
startRendering()505 void ScColorFormat::startRendering()
506 {
507 mpCache.reset();
508 }
509
endRendering()510 void ScColorFormat::endRendering()
511 {
512 mpCache.reset();
513 }
514
515 namespace {
516
GetColorValue(double nVal,double nVal1,sal_uInt8 nColVal1,double nVal2,sal_uInt8 nColVal2)517 sal_uInt8 GetColorValue( double nVal, double nVal1, sal_uInt8 nColVal1, double nVal2, sal_uInt8 nColVal2 )
518 {
519 if (nVal <= nVal1)
520 return nColVal1;
521
522 if (nVal >= nVal2)
523 return nColVal2;
524
525 sal_uInt8 nColVal = static_cast<int>((nVal - nVal1)/(nVal2-nVal1)*(nColVal2-nColVal1))+nColVal1;
526 return nColVal;
527 }
528
CalcColor(double nVal,double nVal1,const Color & rCol1,double nVal2,const Color & rCol2)529 Color CalcColor( double nVal, double nVal1, const Color& rCol1, double nVal2, const Color& rCol2)
530 {
531 sal_uInt8 nColRed = GetColorValue(nVal, nVal1, rCol1.GetRed(), nVal2, rCol2.GetRed());
532 sal_uInt8 nColBlue = GetColorValue(nVal, nVal1, rCol1.GetBlue(), nVal2, rCol2.GetBlue());
533 sal_uInt8 nColGreen = GetColorValue(nVal, nVal1, rCol1.GetGreen(), nVal2, rCol2.GetGreen());
534
535 return Color(nColRed, nColGreen, nColBlue);
536 }
537
538 /**
539 * @param rVector sorted vector of the array
540 * @param fPercentile percentile
541 */
GetPercentile(const std::vector<double> & rArray,double fPercentile)542 double GetPercentile( const std::vector<double>& rArray, double fPercentile )
543 {
544 size_t nSize = rArray.size();
545 size_t nIndex = static_cast<size_t>(::rtl::math::approxFloor( fPercentile * (nSize-1)));
546 double fDiff = fPercentile * (nSize-1) - ::rtl::math::approxFloor( fPercentile * (nSize-1));
547 std::vector<double>::const_iterator iter = rArray.begin() + nIndex;
548 if (fDiff == 0.0)
549 return *iter;
550 else
551 {
552 double fVal = *iter;
553 iter = rArray.begin() + nIndex+1;
554 return fVal + fDiff * (*iter - fVal);
555 }
556 }
557
558 }
559
CalcValue(double nMin,double nMax,const ScColorScaleEntries::const_iterator & itr) const560 double ScColorScaleFormat::CalcValue(double nMin, double nMax, const ScColorScaleEntries::const_iterator& itr) const
561 {
562 switch((*itr)->GetType())
563 {
564 case COLORSCALE_PERCENT:
565 return nMin + (nMax-nMin)*((*itr)->GetValue()/100);
566 case COLORSCALE_MIN:
567 return nMin;
568 case COLORSCALE_MAX:
569 return nMax;
570 case COLORSCALE_PERCENTILE:
571 {
572 std::vector<double>& rValues = getValues();
573 if(rValues.size() == 1)
574 return rValues[0];
575 else
576 {
577 double fPercentile = (*itr)->GetValue()/100.0;
578 return GetPercentile(rValues, fPercentile);
579 }
580 }
581
582 default:
583 break;
584 }
585
586 return (*itr)->GetValue();
587 }
588
GetColor(const ScAddress & rAddr) const589 std::optional<Color> ScColorScaleFormat::GetColor( const ScAddress& rAddr ) const
590 {
591 ScRefCellValue rCell(*mpDoc, rAddr);
592 if(!rCell.hasNumeric())
593 return std::optional<Color>();
594
595 // now we have for sure a value
596 double nVal = rCell.getValue();
597
598 if (maColorScales.size() < 2)
599 return std::optional<Color>();
600
601 double nMin = std::numeric_limits<double>::max();
602 double nMax = std::numeric_limits<double>::min();
603 calcMinMax(nMin, nMax);
604
605 // this check is for safety
606 if(nMin >= nMax)
607 return std::optional<Color>();
608
609 ScColorScaleEntries::const_iterator itr = begin();
610 double nValMin = CalcValue(nMin, nMax, itr);
611 Color rColMin = (*itr)->GetColor();
612 ++itr;
613 double nValMax = CalcValue(nMin, nMax, itr);
614 Color rColMax = (*itr)->GetColor();
615
616 ++itr;
617 while(itr != end() && nVal > nValMax)
618 {
619 rColMin = rColMax;
620 nValMin = nValMax;
621 rColMax = (*itr)->GetColor();
622 nValMax = CalcValue(nMin, nMax, itr);
623 ++itr;
624 }
625
626 Color aColor = CalcColor(nVal, nValMin, rColMin, nValMax, rColMax);
627
628 return aColor;
629 }
630
UpdateReference(sc::RefUpdateContext & rCxt)631 void ScColorScaleFormat::UpdateReference( sc::RefUpdateContext& rCxt )
632 {
633 for(ScColorScaleEntries::iterator itr = begin(); itr != end(); ++itr)
634 (*itr)->UpdateReference(rCxt);
635 }
636
UpdateInsertTab(sc::RefUpdateInsertTabContext & rCxt)637 void ScColorScaleFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
638 {
639 for (ScColorScaleEntries::iterator it = begin(); it != end(); ++it)
640 (*it)->UpdateInsertTab(rCxt);
641 }
642
UpdateDeleteTab(sc::RefUpdateDeleteTabContext & rCxt)643 void ScColorScaleFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
644 {
645 for (ScColorScaleEntries::iterator it = begin(); it != end(); ++it)
646 (*it)->UpdateDeleteTab(rCxt);
647 }
648
UpdateMoveTab(sc::RefUpdateMoveTabContext & rCxt)649 void ScColorScaleFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
650 {
651 for (ScColorScaleEntries::iterator it = begin(); it != end(); ++it)
652 (*it)->UpdateMoveTab(rCxt);
653 }
654
GetType() const655 ScFormatEntry::Type ScColorScaleFormat::GetType() const
656 {
657 return Type::Colorscale;
658 }
659
begin()660 ScColorScaleEntries::iterator ScColorScaleFormat::begin()
661 {
662 return maColorScales.begin();
663 }
664
begin() const665 ScColorScaleEntries::const_iterator ScColorScaleFormat::begin() const
666 {
667 return maColorScales.begin();
668 }
669
end()670 ScColorScaleEntries::iterator ScColorScaleFormat::end()
671 {
672 return maColorScales.end();
673 }
674
end() const675 ScColorScaleEntries::const_iterator ScColorScaleFormat::end() const
676 {
677 return maColorScales.end();
678 }
679
GetEntry(size_t nPos)680 ScColorScaleEntry* ScColorScaleFormat::GetEntry(size_t nPos)
681 {
682 if (maColorScales.size() <= nPos)
683 return nullptr;
684
685 return maColorScales[nPos].get();
686 }
687
GetEntry(size_t nPos) const688 const ScColorScaleEntry* ScColorScaleFormat::GetEntry(size_t nPos) const
689 {
690 if (maColorScales.size() <= nPos)
691 return nullptr;
692
693 return maColorScales[nPos].get();
694 }
695
size() const696 size_t ScColorScaleFormat::size() const
697 {
698 return maColorScales.size();
699 }
700
EnsureSize()701 void ScColorScaleFormat::EnsureSize()
702 {
703 if (maColorScales.size() < 2)
704 {
705 // TODO: create 2 valid entries
706 }
707 }
708
ScDataBarFormat(ScDocument * pDoc)709 ScDataBarFormat::ScDataBarFormat(ScDocument* pDoc):
710 ScColorFormat(pDoc),
711 mpFormatData(new ScDataBarFormatData())
712 {
713 }
714
ScDataBarFormat(ScDocument * pDoc,const ScDataBarFormat & rFormat)715 ScDataBarFormat::ScDataBarFormat(ScDocument* pDoc, const ScDataBarFormat& rFormat):
716 ScColorFormat(pDoc),
717 mpFormatData(new ScDataBarFormatData(*rFormat.mpFormatData))
718 {
719 }
720
SetDataBarData(ScDataBarFormatData * pData)721 void ScDataBarFormat::SetDataBarData( ScDataBarFormatData* pData )
722 {
723 mpFormatData.reset(pData);
724 if (mpParent)
725 {
726 mpFormatData->mpUpperLimit->SetRepaintCallback(mpParent);
727 mpFormatData->mpLowerLimit->SetRepaintCallback(mpParent);
728 }
729 }
730
GetDataBarData()731 ScDataBarFormatData* ScDataBarFormat::GetDataBarData()
732 {
733 return mpFormatData.get();
734 }
735
GetDataBarData() const736 const ScDataBarFormatData* ScDataBarFormat::GetDataBarData() const
737 {
738 return mpFormatData.get();
739 }
740
Clone(ScDocument * pDoc) const741 ScColorFormat* ScDataBarFormat::Clone(ScDocument* pDoc) const
742 {
743 return new ScDataBarFormat(pDoc, *this);
744 }
745
SetParent(ScConditionalFormat * pFormat)746 void ScDataBarFormat::SetParent(ScConditionalFormat* pFormat)
747 {
748 if (mpFormatData)
749 {
750 mpFormatData->mpUpperLimit->SetRepaintCallback(pFormat);
751 mpFormatData->mpLowerLimit->SetRepaintCallback(pFormat);
752 }
753 ScColorFormat::SetParent(pFormat);
754 }
755
GetType() const756 ScFormatEntry::Type ScDataBarFormat::GetType() const
757 {
758 return Type::Databar;
759 }
760
UpdateReference(sc::RefUpdateContext & rCxt)761 void ScDataBarFormat::UpdateReference( sc::RefUpdateContext& rCxt )
762 {
763 mpFormatData->mpUpperLimit->UpdateReference(rCxt);
764 mpFormatData->mpLowerLimit->UpdateReference(rCxt);
765 }
766
UpdateInsertTab(sc::RefUpdateInsertTabContext & rCxt)767 void ScDataBarFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
768 {
769 mpFormatData->mpUpperLimit->UpdateInsertTab(rCxt);
770 mpFormatData->mpLowerLimit->UpdateInsertTab(rCxt);
771 }
772
UpdateDeleteTab(sc::RefUpdateDeleteTabContext & rCxt)773 void ScDataBarFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
774 {
775 mpFormatData->mpUpperLimit->UpdateDeleteTab(rCxt);
776 mpFormatData->mpLowerLimit->UpdateDeleteTab(rCxt);
777 }
778
UpdateMoveTab(sc::RefUpdateMoveTabContext & rCxt)779 void ScDataBarFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
780 {
781 mpFormatData->mpUpperLimit->UpdateMoveTab(rCxt);
782 mpFormatData->mpLowerLimit->UpdateMoveTab(rCxt);
783 }
784
getMin(double nMin,double nMax) const785 double ScDataBarFormat::getMin(double nMin, double nMax) const
786 {
787 switch(mpFormatData->mpLowerLimit->GetType())
788 {
789 case COLORSCALE_MIN:
790 return nMin;
791
792 case COLORSCALE_AUTO:
793 return std::min<double>(0, nMin);
794
795 case COLORSCALE_PERCENT:
796 return nMin + (nMax-nMin)/100*mpFormatData->mpLowerLimit->GetValue();
797
798 case COLORSCALE_PERCENTILE:
799 {
800 double fPercentile = mpFormatData->mpLowerLimit->GetValue()/100.0;
801 std::vector<double>& rValues = getValues();
802 return GetPercentile(rValues, fPercentile);
803 }
804
805 default:
806 break;
807 }
808
809 return mpFormatData->mpLowerLimit->GetValue();
810 }
811
getMax(double nMin,double nMax) const812 double ScDataBarFormat::getMax(double nMin, double nMax) const
813 {
814 switch(mpFormatData->mpUpperLimit->GetType())
815 {
816 case COLORSCALE_MAX:
817 return nMax;
818 case COLORSCALE_AUTO:
819 return std::max<double>(0, nMax);
820 case COLORSCALE_PERCENT:
821 return nMin + (nMax-nMin)/100*mpFormatData->mpUpperLimit->GetValue();
822 case COLORSCALE_PERCENTILE:
823 {
824 double fPercentile = mpFormatData->mpUpperLimit->GetValue()/100.0;
825 std::vector<double>& rValues = getValues();
826 return GetPercentile(rValues, fPercentile);
827 }
828
829 default:
830 break;
831 }
832
833 return mpFormatData->mpUpperLimit->GetValue();
834 }
835
GetDataBarInfo(const ScAddress & rAddr) const836 std::unique_ptr<ScDataBarInfo> ScDataBarFormat::GetDataBarInfo(const ScAddress& rAddr) const
837 {
838 ScRefCellValue rCell(*mpDoc, rAddr);
839 if(!rCell.hasNumeric())
840 return nullptr;
841
842 // now we have for sure a value
843
844 double nValMin = getMinValue();
845 double nValMax = getMaxValue();
846 double nMin = getMin(nValMin, nValMax);
847 double nMax = getMax(nValMin, nValMax);
848 double nMinLength = mpFormatData->mnMinLength;
849 double nMaxLength = mpFormatData->mnMaxLength;
850
851 double nValue = rCell.getValue();
852
853 std::unique_ptr<ScDataBarInfo> pInfo(new ScDataBarInfo);
854 if(mpFormatData->meAxisPosition == databar::NONE)
855 {
856 if(nValue <= nMin)
857 {
858 pInfo->mnLength = nMinLength;
859 }
860 else if(nValue >= nMax)
861 {
862 pInfo->mnLength = nMaxLength;
863 }
864 else
865 {
866 double nDiff = nMax - nMin;
867 pInfo->mnLength = nMinLength + (nValue - nMin)/nDiff * (nMaxLength-nMinLength);
868 }
869 pInfo->mnZero = 0;
870 }
871 else if (mpFormatData->meAxisPosition == databar::AUTOMATIC)
872 {
873 // if auto is used we may need to adjust it
874 // for the length calculation
875 if (mpFormatData->mpLowerLimit->GetType() == COLORSCALE_AUTO && nMin > 0)
876 nMin = 0;
877 if (mpFormatData->mpUpperLimit->GetType() == COLORSCALE_MAX && nMax < 0)
878 nMax = 0;
879
880 //calculate the zero position first
881 if(nMin < 0)
882 {
883 if(nMax < 0)
884 pInfo->mnZero = 100;
885 else
886 {
887 pInfo->mnZero = -100*nMin/(nMax-nMin);
888 }
889 }
890 else
891 pInfo->mnZero = 0;
892
893 double nMinNonNegative = std::max(0.0, nMin);
894 double nMaxNonPositive = std::min(0.0, nMax);
895 //calculate the length
896 if(nValue < 0 && nMin < 0)
897 {
898 if (nValue < nMin)
899 pInfo->mnLength = -100;
900 else
901 pInfo->mnLength = -100 * (nValue-nMaxNonPositive)/(nMin-nMaxNonPositive);
902 }
903 else
904 {
905 if ( nValue > nMax )
906 pInfo->mnLength = 100;
907 else if (nValue <= nMin)
908 pInfo->mnLength = 0;
909 else
910 pInfo->mnLength = 100 * (nValue-nMinNonNegative)/(nMax-nMinNonNegative);
911 }
912 }
913 else if( mpFormatData->meAxisPosition == databar::MIDDLE)
914 {
915 pInfo->mnZero = 50;
916 double nAbsMax = std::max(std::abs(nMin), std::abs(nMax));
917 if (nValue < 0 && nMin < 0)
918 {
919 if (nValue < nMin)
920 pInfo->mnLength = nMaxLength * (nMin/nAbsMax);
921 else
922 pInfo->mnLength = nMaxLength * (nValue/nAbsMax);
923 }
924 else
925 {
926 if (nValue > nMax)
927 pInfo->mnLength = nMaxLength * (nMax/nAbsMax);
928 else
929 pInfo->mnLength = nMaxLength * (std::max(nValue, nMin)/nAbsMax);
930 }
931 }
932 else
933 assert(false);
934
935 // set color
936 if(mpFormatData->mbNeg && nValue < 0)
937 {
938 if(mpFormatData->mxNegativeColor)
939 {
940 pInfo->maColor = *mpFormatData->mxNegativeColor;
941 }
942 else
943 {
944 // default negative color is red
945 pInfo->maColor = COL_LIGHTRED;
946 }
947
948 }
949 else
950 pInfo->maColor = mpFormatData->maPositiveColor;
951
952 pInfo->mbGradient = mpFormatData->mbGradient;
953 pInfo->mbShowValue = !mpFormatData->mbOnlyBar;
954 pInfo->maAxisColor = mpFormatData->maAxisColor;
955
956 return pInfo;
957 }
958
EnsureSize()959 void ScDataBarFormat::EnsureSize()
960 {
961 if (!mpFormatData->mpLowerLimit)
962 {
963 // TODO: implement
964 }
965 if (!mpFormatData->mpUpperLimit)
966 {
967 // TODO: implement
968 }
969 }
970
ScIconSetFormatData(ScIconSetFormatData const & rOther)971 ScIconSetFormatData::ScIconSetFormatData(ScIconSetFormatData const& rOther)
972 : eIconSetType(rOther.eIconSetType)
973 , mbShowValue(rOther.mbShowValue)
974 , mbReverse(rOther.mbReverse)
975 , mbCustom(rOther.mbCustom)
976 , maCustomVector(rOther.maCustomVector)
977 {
978 m_Entries.reserve(rOther.m_Entries.size());
979 for (auto const& it : rOther.m_Entries)
980 {
981 m_Entries.emplace_back(new ScColorScaleEntry(*it));
982 }
983 }
984
ScIconSetFormat(ScDocument * pDoc)985 ScIconSetFormat::ScIconSetFormat(ScDocument* pDoc):
986 ScColorFormat(pDoc),
987 mpFormatData(new ScIconSetFormatData)
988 {
989 }
990
ScIconSetFormat(ScDocument * pDoc,const ScIconSetFormat & rFormat)991 ScIconSetFormat::ScIconSetFormat(ScDocument* pDoc, const ScIconSetFormat& rFormat):
992 ScColorFormat(pDoc),
993 mpFormatData(new ScIconSetFormatData(*rFormat.mpFormatData))
994 {
995 }
996
Clone(ScDocument * pDoc) const997 ScColorFormat* ScIconSetFormat::Clone( ScDocument* pDoc ) const
998 {
999 return new ScIconSetFormat(pDoc, *this);
1000 }
1001
SetParent(ScConditionalFormat * pFormat)1002 void ScIconSetFormat::SetParent(ScConditionalFormat* pFormat)
1003 {
1004 for(iterator itr = begin(); itr != end(); ++itr)
1005 {
1006 (*itr)->SetRepaintCallback(pFormat);
1007 }
1008 ScColorFormat::SetParent(pFormat);
1009 }
1010
SetIconSetData(ScIconSetFormatData * pFormatData)1011 void ScIconSetFormat::SetIconSetData( ScIconSetFormatData* pFormatData )
1012 {
1013 mpFormatData.reset( pFormatData );
1014 SetParent(mpParent);
1015 }
1016
GetIconSetData()1017 ScIconSetFormatData* ScIconSetFormat::GetIconSetData()
1018 {
1019 return mpFormatData.get();
1020 }
1021
GetIconSetData() const1022 const ScIconSetFormatData* ScIconSetFormat::GetIconSetData() const
1023 {
1024 return mpFormatData.get();
1025 }
1026
GetIconSetInfo(const ScAddress & rAddr) const1027 std::unique_ptr<ScIconSetInfo> ScIconSetFormat::GetIconSetInfo(const ScAddress& rAddr) const
1028 {
1029 ScRefCellValue rCell(*mpDoc, rAddr);
1030 if(!rCell.hasNumeric())
1031 return nullptr;
1032
1033 // now we have for sure a value
1034 double nVal = rCell.getValue();
1035
1036 if (mpFormatData->m_Entries.size() < 2)
1037 return nullptr;
1038
1039 double nMin = GetMinValue();
1040 double nMax = GetMaxValue();
1041
1042 sal_Int32 nIndex = 0;
1043 const_iterator itr = begin();
1044 ++itr;
1045 double nValMax = CalcValue(nMin, nMax, itr);
1046
1047 ++itr;
1048 while(itr != end() && nVal >= nValMax)
1049 {
1050 ++nIndex;
1051 nValMax = CalcValue(nMin, nMax, itr);
1052 ++itr;
1053 }
1054
1055 if(nVal >= nValMax)
1056 ++nIndex;
1057
1058 std::unique_ptr<ScIconSetInfo> pInfo(new ScIconSetInfo);
1059
1060 if(mpFormatData->mbReverse)
1061 {
1062 sal_Int32 nMaxIndex = mpFormatData->m_Entries.size() - 1;
1063 nIndex = nMaxIndex - nIndex;
1064 }
1065
1066 if (mpFormatData->mbCustom && sal_Int32(mpFormatData->maCustomVector.size()) > nIndex)
1067 {
1068 ScIconSetType eCustomType = mpFormatData->maCustomVector[nIndex].first;
1069 sal_Int32 nCustomIndex = mpFormatData->maCustomVector[nIndex].second;
1070 if (nCustomIndex == -1)
1071 {
1072 return nullptr;
1073 }
1074
1075 pInfo->eIconSetType = eCustomType;
1076 pInfo->nIconIndex = nCustomIndex;
1077 }
1078 else
1079 {
1080 pInfo->nIconIndex = nIndex;
1081 pInfo->eIconSetType = mpFormatData->eIconSetType;
1082 }
1083
1084 pInfo->mbShowValue = mpFormatData->mbShowValue;
1085 return pInfo;
1086 }
1087
GetType() const1088 ScFormatEntry::Type ScIconSetFormat::GetType() const
1089 {
1090 return Type::Iconset;
1091 }
1092
UpdateReference(sc::RefUpdateContext & rCxt)1093 void ScIconSetFormat::UpdateReference( sc::RefUpdateContext& rCxt )
1094 {
1095 for(iterator itr = begin(); itr != end(); ++itr)
1096 {
1097 (*itr)->UpdateReference(rCxt);
1098 }
1099 }
1100
UpdateInsertTab(sc::RefUpdateInsertTabContext & rCxt)1101 void ScIconSetFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
1102 {
1103 for(iterator itr = begin(); itr != end(); ++itr)
1104 {
1105 (*itr)->UpdateInsertTab(rCxt);
1106 }
1107 }
1108
UpdateDeleteTab(sc::RefUpdateDeleteTabContext & rCxt)1109 void ScIconSetFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
1110 {
1111 for(iterator itr = begin(); itr != end(); ++itr)
1112 {
1113 (*itr)->UpdateDeleteTab(rCxt);
1114 }
1115 }
1116
UpdateMoveTab(sc::RefUpdateMoveTabContext & rCxt)1117 void ScIconSetFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
1118 {
1119 for(iterator itr = begin(); itr != end(); ++itr)
1120 {
1121 (*itr)->UpdateMoveTab(rCxt);
1122 }
1123 }
1124
begin()1125 ScIconSetFormat::iterator ScIconSetFormat::begin()
1126 {
1127 return mpFormatData->m_Entries.begin();
1128 }
1129
begin() const1130 ScIconSetFormat::const_iterator ScIconSetFormat::begin() const
1131 {
1132 return mpFormatData->m_Entries.begin();
1133 }
1134
end()1135 ScIconSetFormat::iterator ScIconSetFormat::end()
1136 {
1137 return mpFormatData->m_Entries.end();
1138 }
1139
end() const1140 ScIconSetFormat::const_iterator ScIconSetFormat::end() const
1141 {
1142 return mpFormatData->m_Entries.end();
1143 }
1144
GetMinValue() const1145 double ScIconSetFormat::GetMinValue() const
1146 {
1147 const_iterator itr = begin();
1148
1149 if ((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
1150 return (*itr)->GetValue();
1151 else
1152 {
1153 return getMinValue();
1154 }
1155 }
1156
GetMaxValue() const1157 double ScIconSetFormat::GetMaxValue() const
1158 {
1159 auto const itr = mpFormatData->m_Entries.rbegin();
1160
1161 if ((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
1162 return (*itr)->GetValue();
1163 else
1164 {
1165 return getMaxValue();
1166 }
1167 }
1168
CalcValue(double nMin,double nMax,const ScIconSetFormat::const_iterator & itr) const1169 double ScIconSetFormat::CalcValue(double nMin, double nMax, const ScIconSetFormat::const_iterator& itr) const
1170 {
1171 switch ((*itr)->GetType())
1172 {
1173 case COLORSCALE_PERCENT:
1174 return nMin + (nMax-nMin)*((*itr)->GetValue()/100);
1175 case COLORSCALE_MIN:
1176 return nMin;
1177 case COLORSCALE_MAX:
1178 return nMax;
1179 case COLORSCALE_PERCENTILE:
1180 {
1181 std::vector<double>& rValues = getValues();
1182 if(rValues.size() == 1)
1183 return rValues[0];
1184 else
1185 {
1186 double fPercentile = (*itr)->GetValue()/100.0;
1187 return GetPercentile(rValues, fPercentile);
1188 }
1189 }
1190
1191 default:
1192 break;
1193 }
1194
1195 return (*itr)->GetValue();
1196 }
1197
1198 const ScIconSetMap ScIconSetFormat::g_IconSetMap[] = {
1199 { "3Arrows", IconSet_3Arrows, 3 },
1200 { "3ArrowsGray", IconSet_3ArrowsGray, 3 },
1201 { "3Flags", IconSet_3Flags, 3 },
1202 { "3TrafficLights1", IconSet_3TrafficLights1, 3 },
1203 { "3TrafficLights2", IconSet_3TrafficLights2, 3 },
1204 { "3Signs", IconSet_3Signs, 3 },
1205 { "3Symbols", IconSet_3Symbols, 3 },
1206 { "3Symbols2", IconSet_3Symbols2, 3 },
1207 { "3Smilies", IconSet_3Smilies, 3 },
1208 { "3ColorSmilies", IconSet_3ColorSmilies, 3 },
1209 { "3Stars", IconSet_3Stars, 3 },
1210 { "3Triangles", IconSet_3Triangles, 3 },
1211 { "4Arrows", IconSet_4Arrows, 4 },
1212 { "4ArrowsGray", IconSet_4ArrowsGray, 4 },
1213 { "4RedToBlack", IconSet_4RedToBlack, 4 },
1214 { "4Rating", IconSet_4Rating, 4 },
1215 { "4TrafficLights", IconSet_4TrafficLights, 4 },
1216 { "5Arrows", IconSet_5Arrows, 5 },
1217 { "5ArrowsGray", IconSet_5ArrowsGray, 5 },
1218 { "5Rating", IconSet_5Ratings, 5 },
1219 { "5Quarters", IconSet_5Quarters, 5 },
1220 { "5Boxes", IconSet_5Boxes, 5 },
1221 { nullptr, IconSet_3Arrows, 0 }
1222 };
1223
size() const1224 size_t ScIconSetFormat::size() const
1225 {
1226 return mpFormatData->m_Entries.size();
1227 }
1228
1229
1230 namespace {
1231
1232 const std::u16string_view a3TrafficLights1[] = {
1233 u"" BMP_ICON_SET_CIRCLES1_RED, u"" BMP_ICON_SET_CIRCLES1_YELLOW, u"" BMP_ICON_SET_CIRCLES1_GREEN
1234 };
1235
1236 const std::u16string_view a3TrafficLights2[] = {
1237 u"" BMP_ICON_SET_TRAFFICLIGHTS_RED, u"" BMP_ICON_SET_TRAFFICLIGHTS_YELLOW, u"" BMP_ICON_SET_TRAFFICLIGHTS_GREEN
1238 };
1239
1240 const std::u16string_view a3Arrows[] = {
1241 u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SAME, u"" BMP_ICON_SET_COLORARROWS_UP
1242 };
1243
1244 const std::u16string_view a3ArrowsGray[] = {
1245 u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SAME, u"" BMP_ICON_SET_GRAYARROWS_UP
1246 };
1247
1248 const std::u16string_view a3Flags[] = {
1249 u"" BMP_ICON_SET_FLAGS_RED, u"" BMP_ICON_SET_FLAGS_YELLOW, u"" BMP_ICON_SET_FLAGS_GREEN
1250 };
1251
1252 const std::u16string_view a3Smilies[] = {
1253 u"" BMP_ICON_SET_POSITIVE_YELLOW_SMILIE, u"" BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, u"" BMP_ICON_SET_NEGATIVE_YELLOW_SMILIE
1254 };
1255
1256 const std::u16string_view a3ColorSmilies[] = {
1257 u"" BMP_ICON_SET_POSITIVE_GREEN_SMILIE, u"" BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, u"" BMP_ICON_SET_NEGATIVE_RED_SMILIE
1258 };
1259
1260 const std::u16string_view a3Stars[] = {
1261 u"" BMP_ICON_SET_STARS_EMPTY, u"" BMP_ICON_SET_STARS_HALF, u"" BMP_ICON_SET_STARS_FULL
1262 };
1263
1264 const std::u16string_view a3Triangles[] = {
1265 u"" BMP_ICON_SET_TRIANGLES_DOWN, u"" BMP_ICON_SET_TRIANGLES_SAME, u"" BMP_ICON_SET_TRIANGLES_UP
1266 };
1267
1268 const std::u16string_view a4Arrows[] = {
1269 u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_COLORARROWS_UP
1270 };
1271
1272 const std::u16string_view a4ArrowsGray[] = {
1273 u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_GRAYARROWS_UP
1274 };
1275
1276 const std::u16string_view a5Arrows[] = {
1277 u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN,
1278 u"" BMP_ICON_SET_COLORARROWS_SAME, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_COLORARROWS_UP
1279 };
1280
1281 const std::u16string_view a5ArrowsGray[] = {
1282 u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN,
1283 u"" BMP_ICON_SET_GRAYARROWS_SAME, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_GRAYARROWS_UP
1284 };
1285
1286 const std::u16string_view a4TrafficLights[] = {
1287 u"" BMP_ICON_SET_CIRCLES1_GRAY, u"" BMP_ICON_SET_CIRCLES1_RED,
1288 u"" BMP_ICON_SET_CIRCLES1_YELLOW, u"" BMP_ICON_SET_CIRCLES1_GREEN
1289 };
1290
1291 const std::u16string_view a5Quarters[] = {
1292 u"" BMP_ICON_SET_PIES_EMPTY, u"" BMP_ICON_SET_PIES_ONE_QUARTER, u"" BMP_ICON_SET_PIES_HALF,
1293 u"" BMP_ICON_SET_PIES_THREE_QUARTER, u"" BMP_ICON_SET_PIES_FULL,
1294 };
1295
1296 const std::u16string_view a5Boxes[] = {
1297 u"" BMP_ICON_SET_SQUARES_EMPTY, u"" BMP_ICON_SET_SQUARES_ONE_QUARTER,
1298 u"" BMP_ICON_SET_SQUARES_HALF, u"" BMP_ICON_SET_SQUARES_THREE_QUARTER,
1299 u"" BMP_ICON_SET_SQUARES_FULL
1300 };
1301
1302 const std::u16string_view a3Symbols1[] = {
1303 u"" BMP_ICON_SET_SYMBOLS1_CROSS, u"" BMP_ICON_SET_SYMBOLS1_EXCLAMATION_MARK, u"" BMP_ICON_SET_SYMBOLS1_CHECK
1304 };
1305
1306 const std::u16string_view a3Signs[] = {
1307 u"" BMP_ICON_SET_SHAPES_DIAMOND, u"" BMP_ICON_SET_SHAPES_TRIANGLE, u"" BMP_ICON_SET_SHAPES_CIRCLE
1308 };
1309
1310 const std::u16string_view a4RedToBlack[] = {
1311 u"" BMP_ICON_SET_CIRCLES2_DARK_GRAY, u"" BMP_ICON_SET_CIRCLES2_LIGHT_GRAY,
1312 u"" BMP_ICON_SET_CIRCLES2_LIGHT_RED, u"" BMP_ICON_SET_CIRCLES2_DARK_RED
1313 };
1314
1315 const std::u16string_view a4Ratings[] = {
1316 u"" BMP_ICON_SET_BARS_ONE_QUARTER, u"" BMP_ICON_SET_BARS_HALF,
1317 u"" BMP_ICON_SET_BARS_THREE_QUARTER, u"" BMP_ICON_SET_BARS_FULL
1318 };
1319
1320 const std::u16string_view a5Ratings[] = {
1321 u"" BMP_ICON_SET_BARS_EMPTY, u"" BMP_ICON_SET_BARS_ONE_QUARTER, u"" BMP_ICON_SET_BARS_HALF,
1322 u"" BMP_ICON_SET_BARS_THREE_QUARTER, u"" BMP_ICON_SET_BARS_FULL
1323 };
1324
1325 struct ScIconSetBitmapMap {
1326 ScIconSetType eType;
1327 const std::u16string_view* pBitmaps;
1328 };
1329
1330 const ScIconSetBitmapMap aBitmapMap[] = {
1331 { IconSet_3Arrows, a3Arrows },
1332 { IconSet_3ArrowsGray, a3ArrowsGray },
1333 { IconSet_3Flags, a3Flags },
1334 { IconSet_3Signs, a3Signs },
1335 { IconSet_3Symbols, a3Symbols1 },
1336 { IconSet_3Symbols2, a3Symbols1 },
1337 { IconSet_3TrafficLights1, a3TrafficLights1 },
1338 { IconSet_3TrafficLights2, a3TrafficLights2 },
1339 { IconSet_3Smilies, a3Smilies },
1340 { IconSet_3ColorSmilies, a3ColorSmilies },
1341 { IconSet_3Triangles, a3Triangles },
1342 { IconSet_3Stars, a3Stars },
1343 { IconSet_4Arrows, a4Arrows },
1344 { IconSet_4ArrowsGray, a4ArrowsGray },
1345 { IconSet_4Rating, a4Ratings },
1346 { IconSet_4RedToBlack, a4RedToBlack },
1347 { IconSet_4TrafficLights, a4TrafficLights },
1348 { IconSet_5Arrows, a5Arrows },
1349 { IconSet_5ArrowsGray, a5ArrowsGray },
1350 { IconSet_5Quarters, a5Quarters },
1351 { IconSet_5Ratings, a5Ratings },
1352 { IconSet_5Boxes, a5Boxes }
1353 };
1354
findIconSetType(ScIconSetType eType)1355 const ScIconSetMap* findIconSetType(ScIconSetType eType)
1356 {
1357 const ScIconSetMap* pMap = ScIconSetFormat::g_IconSetMap;
1358 for (; pMap->pName; ++pMap)
1359 {
1360 if (pMap->eType == eType)
1361 return pMap;
1362 }
1363
1364 return nullptr;
1365 }
1366
1367 }
1368
getIconSetName(ScIconSetType eType)1369 const char* ScIconSetFormat::getIconSetName( ScIconSetType eType )
1370 {
1371 const ScIconSetMap* pMap = findIconSetType(eType);
1372 if (pMap)
1373 return pMap->pName;
1374
1375 return "";
1376 }
1377
getIconSetElements(ScIconSetType eType)1378 sal_Int32 ScIconSetFormat::getIconSetElements( ScIconSetType eType )
1379 {
1380 const ScIconSetMap* pMap = findIconSetType(eType);
1381 if (pMap)
1382 return pMap->nElements;
1383
1384 return 0;
1385 }
1386
getIconName(ScIconSetType const eType,sal_Int32 const nIndex)1387 OUString ScIconSetFormat::getIconName(ScIconSetType const eType, sal_Int32 const nIndex)
1388 {
1389 OUString sBitmap;
1390
1391 for(const ScIconSetBitmapMap & i : aBitmapMap)
1392 {
1393 if(i.eType == eType)
1394 {
1395 sBitmap = *(i.pBitmaps + nIndex);
1396 break;
1397 }
1398 }
1399
1400 assert(!sBitmap.isEmpty());
1401
1402 return sBitmap;
1403 }
1404
getBitmap(sc::IconSetBitmapMap & rIconSetBitmapMap,ScIconSetType const eType,sal_Int32 const nIndex)1405 BitmapEx& ScIconSetFormat::getBitmap(sc::IconSetBitmapMap & rIconSetBitmapMap,
1406 ScIconSetType const eType, sal_Int32 const nIndex)
1407 {
1408 OUString sBitmap(ScIconSetFormat::getIconName(eType, nIndex));
1409
1410 std::map<OUString, BitmapEx>::iterator itr = rIconSetBitmapMap.find(sBitmap);
1411 if (itr != rIconSetBitmapMap.end())
1412 return itr->second;
1413
1414 BitmapEx aBitmap(sBitmap);
1415 std::pair<OUString, BitmapEx> aPair(sBitmap, aBitmap);
1416 std::pair<std::map<OUString, BitmapEx>::iterator, bool> itrNew = rIconSetBitmapMap.insert(aPair);
1417 assert(itrNew.second);
1418
1419 return itrNew.first->second;
1420 }
1421
EnsureSize()1422 void ScIconSetFormat::EnsureSize()
1423 {
1424 ScIconSetType eType = mpFormatData->eIconSetType;
1425 for (const ScIconSetMap & i : g_IconSetMap)
1426 {
1427 if (i.eType == eType)
1428 {
1429 // size_t nElements = aIconSetMap[i].nElements;
1430 // TODO: implement
1431 break;
1432 }
1433 }
1434 }
1435
1436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1437