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