sc: add "updateValues" method to conditional format list
[LibreOffice.git] / sc / source / core / data / colorscale.cxx
bloba8d94440f2374afbd866b57f42a304f93eae0f65
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 <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>
20 #include <formula/token.hxx>
21 #include <vcl/bitmapex.hxx>
23 #include <algorithm>
24 #include <cassert>
25 #include <string_view>
27 ScFormulaListener::ScFormulaListener(ScFormulaCell* pCell):
28 mbDirty(false),
29 mrDoc(pCell->GetDocument())
31 startListening( pCell->GetCode(), pCell->aPos );
34 ScFormulaListener::ScFormulaListener(ScDocument& rDoc):
35 mbDirty(false),
36 mrDoc(rDoc)
40 ScFormulaListener::ScFormulaListener(ScDocument& rDoc, const ScRangeList& rRange):
41 mbDirty(false),
42 mrDoc(rDoc)
44 startListening(rRange);
47 void ScFormulaListener::startListening(const ScTokenArray* pArr, const ScRange& rRange)
49 if (!pArr || mrDoc.IsClipOrUndo())
50 return;
52 for ( auto t: pArr->References() )
54 switch (t->GetType())
56 case formula::svSingleRef:
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);
64 break;
65 case formula::svDoubleRef:
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())
78 if (t->GetOpCode() == ocColRowNameAuto)
79 { // automagically
80 if ( rRef1.IsColRel() )
81 { // ColName
82 aRange1.aEnd.SetRow(mrDoc.MaxRow());
84 else
85 { // RowName
86 aRange1.aEnd.SetCol(mrDoc.MaxCol());
89 mrDoc.StartListeningArea(aRange1, false, this);
92 break;
93 default:
94 ; // nothing
99 void ScFormulaListener::startListening(const ScRangeList& rRange)
101 if (mrDoc.IsClipOrUndo())
102 return;
104 size_t nLength = rRange.size();
105 for (size_t i = 0; i < nLength; ++i)
107 const ScRange& aRange = rRange[i];
108 mrDoc.StartListeningArea(aRange, false, this);
112 void ScFormulaListener::addTokenArray(const ScTokenArray* pArray, const ScRange& rRange)
114 startListening(pArray, rRange);
117 void ScFormulaListener::setCallback(const std::function<void()>& aCallback)
119 maCallbackFunction = aCallback;
122 void ScFormulaListener::stopListening()
124 if (mrDoc.IsClipOrUndo())
125 return;
127 EndListeningAll();
130 ScFormulaListener::~ScFormulaListener()
132 stopListening();
135 void ScFormulaListener::Notify(const SfxHint& rHint)
137 mbDirty = true;
139 if (rHint.GetId() == SfxHintId::Dying)
140 return;
142 if (maCallbackFunction)
143 maCallbackFunction();
146 bool ScFormulaListener::NeedsRepaint() const
148 bool bRet = mbDirty;
149 mbDirty = false;
150 return bRet;
153 ScColorScaleEntry::ScColorScaleEntry():
154 mnVal(0),
155 mpFormat(nullptr),
156 meType(COLORSCALE_VALUE)
160 ScColorScaleEntry::ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType):
161 mnVal(nVal),
162 mpFormat(nullptr),
163 maColor(rCol),
164 meType(eType)
168 ScColorScaleEntry::ScColorScaleEntry(const ScColorScaleEntry& rEntry):
169 mnVal(rEntry.mnVal),
170 mpFormat(rEntry.mpFormat),
171 maColor(rEntry.maColor),
172 meType(rEntry.meType)
174 setListener();
175 if(rEntry.mpCell)
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()));
183 ScColorScaleEntry::ScColorScaleEntry(ScDocument* pDoc, const ScColorScaleEntry& rEntry):
184 mnVal(rEntry.mnVal),
185 mpFormat(rEntry.mpFormat),
186 maColor(rEntry.maColor),
187 meType(rEntry.meType)
189 setListener();
190 if(rEntry.mpCell)
192 mpCell.reset(new ScFormulaCell(*rEntry.mpCell, *pDoc, rEntry.mpCell->aPos, ScCloneFlags::NoMakeAbsExternal));
193 mpCell->StartListeningTo( *pDoc );
194 mpListener.reset(new ScFormulaListener(mpCell.get()));
195 if (mpFormat)
196 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
200 ScColorScaleEntry::~ScColorScaleEntry() COVERITY_NOEXCEPT_FALSE
202 if(mpCell)
203 mpCell->EndListeningTo(mpCell->GetDocument());
206 void ScColorScaleEntry::SetFormula( const OUString& rFormula, ScDocument& rDoc, const ScAddress& rAddr, formula::FormulaGrammar::Grammar eGrammar )
208 mpCell.reset(new ScFormulaCell( rDoc, rAddr, rFormula, eGrammar ));
209 mpCell->StartListeningTo( rDoc );
210 mpListener.reset(new ScFormulaListener(mpCell.get()));
211 if (mpFormat)
212 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
215 const ScTokenArray* ScColorScaleEntry::GetFormula() const
217 if(mpCell)
219 return mpCell->GetCode();
222 return nullptr;
225 OUString ScColorScaleEntry::GetFormula( formula::FormulaGrammar::Grammar eGrammar ) const
227 if(mpCell)
229 return mpCell->GetFormula(eGrammar);
232 return OUString();
235 double ScColorScaleEntry::GetValue() const
237 if(mpCell)
239 mpCell->Interpret();
240 if(mpCell->IsValue())
241 return mpCell->GetValue();
243 return std::numeric_limits<double>::max();
246 return mnVal;
249 void ScColorScaleEntry::SetValue(double nValue)
251 mnVal = nValue;
252 mpCell.reset();
253 setListener();
256 void ScColorScaleEntry::UpdateReference( const sc::RefUpdateContext& rCxt )
258 if (!mpCell)
260 setListener();
261 return;
264 mpCell->UpdateReference(rCxt);
265 mpListener.reset(new ScFormulaListener(mpCell.get()));
266 SetRepaintCallback(mpFormat);
269 void ScColorScaleEntry::UpdateInsertTab( const sc::RefUpdateInsertTabContext& rCxt )
271 if (!mpCell)
273 setListener();
274 return;
277 mpCell->UpdateInsertTab(rCxt);
278 mpListener.reset(new ScFormulaListener(mpCell.get()));
279 SetRepaintCallback(mpFormat);
282 void ScColorScaleEntry::UpdateDeleteTab( const sc::RefUpdateDeleteTabContext& rCxt )
284 if (!mpCell)
286 setListener();
287 return;
290 mpCell->UpdateDeleteTab(rCxt);
291 mpListener.reset(new ScFormulaListener(mpCell.get()));
292 SetRepaintCallback(mpFormat);
295 void ScColorScaleEntry::UpdateMoveTab( const sc::RefUpdateMoveTabContext& rCxt )
297 if (!mpCell)
299 setListener();
300 return;
303 SCTAB nTabNo = rCxt.getNewTab(mpCell->aPos.Tab());
304 mpCell->UpdateMoveTab(rCxt, nTabNo);
305 mpListener.reset(new ScFormulaListener(mpCell.get()));
306 SetRepaintCallback(mpFormat);
309 void ScColorScaleEntry::SetColor(const Color& rColor)
311 maColor = rColor;
314 void ScColorScaleEntry::SetRepaintCallback(ScConditionalFormat* pFormat)
316 mpFormat = pFormat;
317 setListener();
318 if (mpFormat && mpListener)
319 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
322 void ScColorScaleEntry::SetType( ScColorScaleEntryType eType )
324 meType = eType;
325 if(eType != COLORSCALE_FORMULA)
327 mpCell.reset();
328 mpListener.reset();
331 setListener();
334 void ScColorScaleEntry::setListener()
336 if (!mpFormat)
337 return;
339 if (meType == COLORSCALE_PERCENT || meType == COLORSCALE_PERCENTILE
340 || meType == COLORSCALE_MIN || meType == COLORSCALE_MAX
341 || meType == COLORSCALE_AUTO)
343 mpListener.reset(new ScFormulaListener(*mpFormat->GetDocument(), mpFormat->GetRange()));
344 mpListener->setCallback([&]() { mpFormat->DoRepaint();});
348 void ScColorScaleEntry::SetRepaintCallback(const std::function<void()>& func)
350 mpListener->setCallback(func);
353 ScColorFormat::ScColorFormat(ScDocument* pDoc)
354 : ScFormatEntry(pDoc)
355 , mpParent(nullptr)
359 ScColorFormat::~ScColorFormat()
363 void ScColorFormat::SetParent( ScConditionalFormat* pParent )
365 mpParent = pParent;
368 ScColorScaleFormat::ScColorScaleFormat(ScDocument* pDoc):
369 ScColorFormat(pDoc)
373 ScColorScaleFormat::ScColorScaleFormat(ScDocument* pDoc, const ScColorScaleFormat& rFormat):
374 ScColorFormat(pDoc)
376 for(const auto& rxEntry : rFormat)
378 maColorScales.emplace_back(new ScColorScaleEntry(pDoc, *rxEntry));
382 ScColorFormat* ScColorScaleFormat::Clone(ScDocument* pDoc) const
384 return new ScColorScaleFormat(pDoc, *this);
387 ScColorScaleFormat::~ScColorScaleFormat()
391 void ScColorScaleFormat::SetParent(ScConditionalFormat* pFormat)
393 for (auto itr = begin(), itrEnd = end(); itr != itrEnd; ++itr)
395 (*itr)->SetRepaintCallback(pFormat);
397 ScColorFormat::SetParent(pFormat);
400 void ScColorScaleFormat::AddEntry( ScColorScaleEntry* pEntry )
402 maColorScales.push_back(std::unique_ptr<ScColorScaleEntry, o3tl::default_delete<ScColorScaleEntry>>(pEntry));
403 maColorScales.back()->SetRepaintCallback(mpParent);
406 double ScColorScaleFormat::GetMinValue() const
408 ScColorScaleEntries::const_iterator itr = maColorScales.begin();
410 if((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
411 return (*itr)->GetValue();
412 else
414 return getMinValue();
418 double ScColorScaleFormat::GetMaxValue() const
420 ScColorScaleEntries::const_reverse_iterator itr = maColorScales.rbegin();
422 if((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
423 return (*itr)->GetValue();
424 else
426 return getMaxValue();
430 void ScColorScaleFormat::calcMinMax(double& rMin, double& rMax) const
432 rMin = GetMinValue();
433 rMax = GetMaxValue();
436 const ScRangeList& ScColorFormat::GetRange() const
438 return mpParent->GetRange();
441 std::vector<double>& ScColorFormat::getValues() const
443 if(!mpCache)
445 mpCache.reset(new ScColorFormatCache);
446 std::vector<double>& rValues = mpCache->maValues;
448 size_t n = GetRange().size();
449 const ScRangeList& aRanges = GetRange();
450 for(size_t i = 0; i < n; ++i)
452 const ScRange & rRange = aRanges[i];
453 SCTAB nTab = rRange.aStart.Tab();
455 SCCOL nColStart = rRange.aStart.Col();
456 SCROW nRowStart = rRange.aStart.Row();
457 SCCOL nColEnd = rRange.aEnd.Col();
458 SCROW nRowEnd = rRange.aEnd.Row();
460 if(nRowEnd == MAXROW)
462 bool bShrunk = false;
463 mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
464 nColEnd, nRowEnd, false);
466 for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
468 for(SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
470 ScAddress aAddr(nCol, nRow, nTab);
471 ScRefCellValue rCell(*mpDoc, aAddr);
472 if(rCell.hasNumeric())
474 double aVal = rCell.getValue();
475 rValues.push_back(aVal);
481 std::sort(rValues.begin(), rValues.end());
484 return mpCache->maValues;
487 double ScColorFormat::getMinValue() const
489 std::vector<double>& rValues = getValues();
490 if(rValues.empty())
491 return 0;
492 return rValues[0];
495 double ScColorFormat::getMaxValue() const
497 std::vector<double>& rValues = getValues();
498 if(rValues.empty())
499 return 0;
500 return rValues[rValues.size()-1];
503 void ScColorFormat::startRendering()
505 mpCache.reset();
508 void ScColorFormat::endRendering()
510 mpCache.reset();
513 void ScColorFormat::updateValues()
515 getMinValue();
516 getMaxValue();
519 namespace {
521 sal_uInt8 GetColorValue( double nVal, double nVal1, sal_uInt8 nColVal1, double nVal2, sal_uInt8 nColVal2 )
523 if (nVal <= nVal1)
524 return nColVal1;
526 if (nVal >= nVal2)
527 return nColVal2;
529 sal_uInt8 nColVal = static_cast<int>((nVal - nVal1)/(nVal2-nVal1)*(nColVal2-nColVal1))+nColVal1;
530 return nColVal;
533 Color CalcColor( double nVal, double nVal1, const Color& rCol1, double nVal2, const Color& rCol2)
535 sal_uInt8 nColRed = GetColorValue(nVal, nVal1, rCol1.GetRed(), nVal2, rCol2.GetRed());
536 sal_uInt8 nColBlue = GetColorValue(nVal, nVal1, rCol1.GetBlue(), nVal2, rCol2.GetBlue());
537 sal_uInt8 nColGreen = GetColorValue(nVal, nVal1, rCol1.GetGreen(), nVal2, rCol2.GetGreen());
539 return Color(nColRed, nColGreen, nColBlue);
543 * @param rVector sorted vector of the array
544 * @param fPercentile percentile
546 double GetPercentile( const std::vector<double>& rArray, double fPercentile )
548 size_t nSize = rArray.size();
549 double fFloor = ::rtl::math::approxFloor(fPercentile * (nSize-1));
550 SAL_WARN_IF(fFloor < 0, "sc", "negative percentile");
551 size_t nIndex = fFloor >= 0 ? static_cast<size_t>(fFloor) : 0;
552 double fDiff = fPercentile * (nSize-1) - fFloor;
553 std::vector<double>::const_iterator iter = rArray.begin() + nIndex;
554 if (fDiff == 0.0)
555 return *iter;
556 else
558 double fVal = *iter;
559 iter = rArray.begin() + nIndex+1;
560 return fVal + fDiff * (*iter - fVal);
566 double ScColorScaleFormat::CalcValue(double nMin, double nMax, const ScColorScaleEntries::const_iterator& itr) const
568 switch((*itr)->GetType())
570 case COLORSCALE_PERCENT:
571 return nMin + (nMax-nMin)*((*itr)->GetValue()/100);
572 case COLORSCALE_MIN:
573 return nMin;
574 case COLORSCALE_MAX:
575 return nMax;
576 case COLORSCALE_PERCENTILE:
578 std::vector<double>& rValues = getValues();
579 if(rValues.size() == 1)
580 return rValues[0];
581 else
583 double fPercentile = (*itr)->GetValue()/100.0;
584 return GetPercentile(rValues, fPercentile);
588 default:
589 break;
592 return (*itr)->GetValue();
595 std::optional<Color> ScColorScaleFormat::GetColor( const ScAddress& rAddr ) const
597 ScRefCellValue rCell(*mpDoc, rAddr);
598 if(!rCell.hasNumeric())
599 return std::optional<Color>();
601 // now we have for sure a value
602 double nVal = rCell.getValue();
604 if (maColorScales.size() < 2)
605 return std::optional<Color>();
607 double nMin = std::numeric_limits<double>::max();
608 double nMax = std::numeric_limits<double>::min();
609 calcMinMax(nMin, nMax);
611 // this check is for safety
612 if(nMin >= nMax)
613 return std::optional<Color>();
615 ScColorScaleEntries::const_iterator itr = begin();
616 double nValMin = CalcValue(nMin, nMax, itr);
617 Color rColMin = (*itr)->GetColor();
618 ++itr;
619 double nValMax = CalcValue(nMin, nMax, itr);
620 Color rColMax = (*itr)->GetColor();
622 ++itr;
623 while(itr != end() && nVal > nValMax)
625 rColMin = rColMax;
626 nValMin = nValMax;
627 rColMax = (*itr)->GetColor();
628 nValMax = CalcValue(nMin, nMax, itr);
629 ++itr;
632 Color aColor = CalcColor(nVal, nValMin, rColMin, nValMax, rColMax);
634 return aColor;
637 void ScColorScaleFormat::UpdateReference( sc::RefUpdateContext& rCxt )
639 for(ScColorScaleEntries::iterator itr = begin(); itr != end(); ++itr)
640 (*itr)->UpdateReference(rCxt);
643 void ScColorScaleFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
645 for (ScColorScaleEntries::iterator it = begin(); it != end(); ++it)
646 (*it)->UpdateInsertTab(rCxt);
649 void ScColorScaleFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
651 for (ScColorScaleEntries::iterator it = begin(); it != end(); ++it)
652 (*it)->UpdateDeleteTab(rCxt);
655 void ScColorScaleFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
657 for (ScColorScaleEntries::iterator it = begin(); it != end(); ++it)
658 (*it)->UpdateMoveTab(rCxt);
661 ScFormatEntry::Type ScColorScaleFormat::GetType() const
663 return Type::Colorscale;
666 ScColorScaleEntries::iterator ScColorScaleFormat::begin()
668 return maColorScales.begin();
671 ScColorScaleEntries::const_iterator ScColorScaleFormat::begin() const
673 return maColorScales.begin();
676 ScColorScaleEntries::iterator ScColorScaleFormat::end()
678 return maColorScales.end();
681 ScColorScaleEntries::const_iterator ScColorScaleFormat::end() const
683 return maColorScales.end();
686 ScColorScaleEntry* ScColorScaleFormat::GetEntry(size_t nPos)
688 if (maColorScales.size() <= nPos)
689 return nullptr;
691 return maColorScales[nPos].get();
694 const ScColorScaleEntry* ScColorScaleFormat::GetEntry(size_t nPos) const
696 if (maColorScales.size() <= nPos)
697 return nullptr;
699 return maColorScales[nPos].get();
702 size_t ScColorScaleFormat::size() const
704 return maColorScales.size();
707 void ScColorScaleFormat::EnsureSize()
709 if (maColorScales.size() < 2)
711 // TODO: create 2 valid entries
715 ScDataBarFormat::ScDataBarFormat(ScDocument* pDoc):
716 ScColorFormat(pDoc),
717 mpFormatData(new ScDataBarFormatData())
721 ScDataBarFormat::ScDataBarFormat(ScDocument* pDoc, const ScDataBarFormat& rFormat):
722 ScColorFormat(pDoc),
723 mpFormatData(new ScDataBarFormatData(*rFormat.mpFormatData))
727 void ScDataBarFormat::SetDataBarData( ScDataBarFormatData* pData )
729 mpFormatData.reset(pData);
730 if (mpParent)
732 mpFormatData->mpUpperLimit->SetRepaintCallback(mpParent);
733 mpFormatData->mpLowerLimit->SetRepaintCallback(mpParent);
737 ScDataBarFormatData* ScDataBarFormat::GetDataBarData()
739 return mpFormatData.get();
742 const ScDataBarFormatData* ScDataBarFormat::GetDataBarData() const
744 return mpFormatData.get();
747 ScColorFormat* ScDataBarFormat::Clone(ScDocument* pDoc) const
749 return new ScDataBarFormat(pDoc, *this);
752 void ScDataBarFormat::SetParent(ScConditionalFormat* pFormat)
754 if (mpFormatData)
756 mpFormatData->mpUpperLimit->SetRepaintCallback(pFormat);
757 mpFormatData->mpLowerLimit->SetRepaintCallback(pFormat);
759 ScColorFormat::SetParent(pFormat);
762 ScFormatEntry::Type ScDataBarFormat::GetType() const
764 return Type::Databar;
767 void ScDataBarFormat::UpdateReference( sc::RefUpdateContext& rCxt )
769 mpFormatData->mpUpperLimit->UpdateReference(rCxt);
770 mpFormatData->mpLowerLimit->UpdateReference(rCxt);
773 void ScDataBarFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
775 mpFormatData->mpUpperLimit->UpdateInsertTab(rCxt);
776 mpFormatData->mpLowerLimit->UpdateInsertTab(rCxt);
779 void ScDataBarFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
781 mpFormatData->mpUpperLimit->UpdateDeleteTab(rCxt);
782 mpFormatData->mpLowerLimit->UpdateDeleteTab(rCxt);
785 void ScDataBarFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
787 mpFormatData->mpUpperLimit->UpdateMoveTab(rCxt);
788 mpFormatData->mpLowerLimit->UpdateMoveTab(rCxt);
791 double ScDataBarFormat::getMin(double nMin, double nMax) const
793 switch(mpFormatData->mpLowerLimit->GetType())
795 case COLORSCALE_MIN:
796 return nMin;
798 case COLORSCALE_AUTO:
799 return std::min<double>(0, nMin);
801 case COLORSCALE_PERCENT:
802 return nMin + (nMax-nMin)/100*mpFormatData->mpLowerLimit->GetValue();
804 case COLORSCALE_PERCENTILE:
806 double fPercentile = mpFormatData->mpLowerLimit->GetValue()/100.0;
807 std::vector<double>& rValues = getValues();
808 return GetPercentile(rValues, fPercentile);
811 default:
812 break;
815 return mpFormatData->mpLowerLimit->GetValue();
818 double ScDataBarFormat::getMax(double nMin, double nMax) const
820 switch(mpFormatData->mpUpperLimit->GetType())
822 case COLORSCALE_MAX:
823 return nMax;
824 case COLORSCALE_AUTO:
825 return std::max<double>(0, nMax);
826 case COLORSCALE_PERCENT:
827 return nMin + (nMax-nMin)/100*mpFormatData->mpUpperLimit->GetValue();
828 case COLORSCALE_PERCENTILE:
830 double fPercentile = mpFormatData->mpUpperLimit->GetValue()/100.0;
831 std::vector<double>& rValues = getValues();
832 return GetPercentile(rValues, fPercentile);
835 default:
836 break;
839 return mpFormatData->mpUpperLimit->GetValue();
842 std::unique_ptr<ScDataBarInfo> ScDataBarFormat::GetDataBarInfo(const ScAddress& rAddr) const
844 ScRefCellValue rCell(*mpDoc, rAddr);
845 if(!rCell.hasNumeric())
846 return nullptr;
848 // now we have for sure a value
850 double nValMin = getMinValue();
851 double nValMax = getMaxValue();
852 double nMin = getMin(nValMin, nValMax);
853 double nMax = getMax(nValMin, nValMax);
854 double nMinLength = mpFormatData->mnMinLength;
855 double nMaxLength = mpFormatData->mnMaxLength;
857 double nValue = rCell.getValue();
859 std::unique_ptr<ScDataBarInfo> pInfo(new ScDataBarInfo);
860 if(mpFormatData->meAxisPosition == databar::NONE)
862 if(nValue <= nMin)
864 pInfo->mnLength = nMinLength;
866 else if(nValue >= nMax)
868 pInfo->mnLength = nMaxLength;
870 else
872 double nDiff = nMax - nMin;
873 pInfo->mnLength = nMinLength + (nValue - nMin)/nDiff * (nMaxLength-nMinLength);
875 pInfo->mnZero = 0;
877 else if (mpFormatData->meAxisPosition == databar::AUTOMATIC)
879 // if auto is used we may need to adjust it
880 // for the length calculation
881 if (mpFormatData->mpLowerLimit->GetType() == COLORSCALE_AUTO && nMin > 0)
882 nMin = 0;
883 if (mpFormatData->mpUpperLimit->GetType() == COLORSCALE_MAX && nMax < 0)
884 nMax = 0;
886 //calculate the zero position first
887 if(nMin < 0)
889 if(nMax < 0)
890 pInfo->mnZero = 100;
891 else
893 pInfo->mnZero = -100*nMin/(nMax-nMin);
896 else
897 pInfo->mnZero = 0;
899 double nMinNonNegative = std::max(0.0, nMin);
900 double nMaxNonPositive = std::min(0.0, nMax);
901 //calculate the length
902 if(nValue < 0 && nMin < 0)
904 if (nValue < nMin)
905 pInfo->mnLength = -100;
906 else
907 pInfo->mnLength = -100 * (nValue-nMaxNonPositive)/(nMin-nMaxNonPositive);
909 else
911 if ( nValue > nMax )
912 pInfo->mnLength = 100;
913 else if (nValue <= nMin)
914 pInfo->mnLength = 0;
915 else
916 pInfo->mnLength = 100 * (nValue-nMinNonNegative)/(nMax-nMinNonNegative);
919 else if( mpFormatData->meAxisPosition == databar::MIDDLE)
921 pInfo->mnZero = 50;
922 double nAbsMax = std::max(std::abs(nMin), std::abs(nMax));
923 if (nValue < 0 && nMin < 0)
925 if (nValue < nMin)
926 pInfo->mnLength = nMaxLength * (nMin/nAbsMax);
927 else
928 pInfo->mnLength = nMaxLength * (nValue/nAbsMax);
930 else
932 if (nValue > nMax)
933 pInfo->mnLength = nMaxLength * (nMax/nAbsMax);
934 else
935 pInfo->mnLength = nMaxLength * (std::max(nValue, nMin)/nAbsMax);
938 else
939 assert(false);
941 // set color
942 if(mpFormatData->mbNeg && nValue < 0)
944 if(mpFormatData->mxNegativeColor)
946 pInfo->maColor = *mpFormatData->mxNegativeColor;
948 else
950 // default negative color is red
951 pInfo->maColor = COL_LIGHTRED;
955 else
956 pInfo->maColor = mpFormatData->maPositiveColor;
958 pInfo->mbGradient = mpFormatData->mbGradient;
959 pInfo->mbShowValue = !mpFormatData->mbOnlyBar;
960 pInfo->maAxisColor = mpFormatData->maAxisColor;
962 return pInfo;
965 void ScDataBarFormat::EnsureSize()
967 if (!mpFormatData->mpLowerLimit)
969 // TODO: implement
971 if (!mpFormatData->mpUpperLimit)
973 // TODO: implement
977 ScIconSetFormatData::ScIconSetFormatData(ScIconSetFormatData const& rOther)
978 : eIconSetType(rOther.eIconSetType)
979 , mbShowValue(rOther.mbShowValue)
980 , mbReverse(rOther.mbReverse)
981 , mbCustom(rOther.mbCustom)
982 , maCustomVector(rOther.maCustomVector)
984 m_Entries.reserve(rOther.m_Entries.size());
985 for (auto const& it : rOther.m_Entries)
987 m_Entries.emplace_back(new ScColorScaleEntry(*it));
991 ScIconSetFormat::ScIconSetFormat(ScDocument* pDoc):
992 ScColorFormat(pDoc),
993 mpFormatData(new ScIconSetFormatData)
997 ScIconSetFormat::ScIconSetFormat(ScDocument* pDoc, const ScIconSetFormat& rFormat):
998 ScColorFormat(pDoc),
999 mpFormatData(new ScIconSetFormatData(*rFormat.mpFormatData))
1003 ScColorFormat* ScIconSetFormat::Clone( ScDocument* pDoc ) const
1005 return new ScIconSetFormat(pDoc, *this);
1008 void ScIconSetFormat::SetParent(ScConditionalFormat* pFormat)
1010 for(iterator itr = begin(); itr != end(); ++itr)
1012 (*itr)->SetRepaintCallback(pFormat);
1014 ScColorFormat::SetParent(pFormat);
1017 void ScIconSetFormat::SetIconSetData( ScIconSetFormatData* pFormatData )
1019 mpFormatData.reset( pFormatData );
1020 SetParent(mpParent);
1023 ScIconSetFormatData* ScIconSetFormat::GetIconSetData()
1025 return mpFormatData.get();
1028 const ScIconSetFormatData* ScIconSetFormat::GetIconSetData() const
1030 return mpFormatData.get();
1033 std::unique_ptr<ScIconSetInfo> ScIconSetFormat::GetIconSetInfo(const ScAddress& rAddr) const
1035 ScRefCellValue rCell(*mpDoc, rAddr);
1036 if(!rCell.hasNumeric())
1037 return nullptr;
1039 // now we have for sure a value
1040 double nVal = rCell.getValue();
1042 if (mpFormatData->m_Entries.size() < 2)
1043 return nullptr;
1045 double nMin = GetMinValue();
1046 double nMax = GetMaxValue();
1048 sal_Int32 nIndex = 0;
1049 const_iterator itr = begin();
1050 ++itr;
1051 double nValMax = CalcValue(nMin, nMax, itr);
1053 ++itr;
1054 while(itr != end() && nVal >= nValMax)
1056 ++nIndex;
1057 nValMax = CalcValue(nMin, nMax, itr);
1058 ++itr;
1061 if(nVal >= nValMax)
1062 ++nIndex;
1064 std::unique_ptr<ScIconSetInfo> pInfo(new ScIconSetInfo);
1066 if(mpFormatData->mbReverse)
1068 sal_Int32 nMaxIndex = mpFormatData->m_Entries.size() - 1;
1069 nIndex = nMaxIndex - nIndex;
1072 if (mpFormatData->mbCustom && sal_Int32(mpFormatData->maCustomVector.size()) > nIndex)
1074 ScIconSetType eCustomType = mpFormatData->maCustomVector[nIndex].first;
1075 sal_Int32 nCustomIndex = mpFormatData->maCustomVector[nIndex].second;
1076 if (nCustomIndex == -1)
1078 return nullptr;
1081 pInfo->eIconSetType = eCustomType;
1082 pInfo->nIconIndex = nCustomIndex;
1084 else
1086 pInfo->nIconIndex = nIndex;
1087 pInfo->eIconSetType = mpFormatData->eIconSetType;
1090 pInfo->mbShowValue = mpFormatData->mbShowValue;
1091 return pInfo;
1094 ScFormatEntry::Type ScIconSetFormat::GetType() const
1096 return Type::Iconset;
1099 void ScIconSetFormat::UpdateReference( sc::RefUpdateContext& rCxt )
1101 for(iterator itr = begin(); itr != end(); ++itr)
1103 (*itr)->UpdateReference(rCxt);
1107 void ScIconSetFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
1109 for(iterator itr = begin(); itr != end(); ++itr)
1111 (*itr)->UpdateInsertTab(rCxt);
1115 void ScIconSetFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
1117 for(iterator itr = begin(); itr != end(); ++itr)
1119 (*itr)->UpdateDeleteTab(rCxt);
1123 void ScIconSetFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
1125 for(iterator itr = begin(); itr != end(); ++itr)
1127 (*itr)->UpdateMoveTab(rCxt);
1131 ScIconSetFormat::iterator ScIconSetFormat::begin()
1133 return mpFormatData->m_Entries.begin();
1136 ScIconSetFormat::const_iterator ScIconSetFormat::begin() const
1138 return mpFormatData->m_Entries.begin();
1141 ScIconSetFormat::iterator ScIconSetFormat::end()
1143 return mpFormatData->m_Entries.end();
1146 ScIconSetFormat::const_iterator ScIconSetFormat::end() const
1148 return mpFormatData->m_Entries.end();
1151 double ScIconSetFormat::GetMinValue() const
1153 const_iterator itr = begin();
1155 if ((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
1156 return (*itr)->GetValue();
1157 else
1159 return getMinValue();
1163 double ScIconSetFormat::GetMaxValue() const
1165 auto const itr = mpFormatData->m_Entries.rbegin();
1167 if ((*itr)->GetType() == COLORSCALE_VALUE || (*itr)->GetType() == COLORSCALE_FORMULA)
1168 return (*itr)->GetValue();
1169 else
1171 return getMaxValue();
1175 double ScIconSetFormat::CalcValue(double nMin, double nMax, const ScIconSetFormat::const_iterator& itr) const
1177 switch ((*itr)->GetType())
1179 case COLORSCALE_PERCENT:
1180 return nMin + (nMax-nMin)*((*itr)->GetValue()/100);
1181 case COLORSCALE_MIN:
1182 return nMin;
1183 case COLORSCALE_MAX:
1184 return nMax;
1185 case COLORSCALE_PERCENTILE:
1187 std::vector<double>& rValues = getValues();
1188 if(rValues.size() == 1)
1189 return rValues[0];
1190 else
1192 double fPercentile = (*itr)->GetValue()/100.0;
1193 return GetPercentile(rValues, fPercentile);
1197 default:
1198 break;
1201 return (*itr)->GetValue();
1204 const ScIconSetMap ScIconSetFormat::g_IconSetMap[] = {
1205 { "3Arrows", IconSet_3Arrows, 3 },
1206 { "3ArrowsGray", IconSet_3ArrowsGray, 3 },
1207 { "3Flags", IconSet_3Flags, 3 },
1208 { "3TrafficLights1", IconSet_3TrafficLights1, 3 },
1209 { "3TrafficLights2", IconSet_3TrafficLights2, 3 },
1210 { "3Signs", IconSet_3Signs, 3 },
1211 { "3Symbols", IconSet_3Symbols, 3 },
1212 { "3Symbols2", IconSet_3Symbols2, 3 },
1213 { "3Smilies", IconSet_3Smilies, 3 },
1214 { "3ColorSmilies", IconSet_3ColorSmilies, 3 },
1215 { "3Stars", IconSet_3Stars, 3 },
1216 { "3Triangles", IconSet_3Triangles, 3 },
1217 { "4Arrows", IconSet_4Arrows, 4 },
1218 { "4ArrowsGray", IconSet_4ArrowsGray, 4 },
1219 { "4RedToBlack", IconSet_4RedToBlack, 4 },
1220 { "4Rating", IconSet_4Rating, 4 },
1221 { "4TrafficLights", IconSet_4TrafficLights, 4 },
1222 { "5Arrows", IconSet_5Arrows, 5 },
1223 { "5ArrowsGray", IconSet_5ArrowsGray, 5 },
1224 { "5Rating", IconSet_5Ratings, 5 },
1225 { "5Quarters", IconSet_5Quarters, 5 },
1226 { "5Boxes", IconSet_5Boxes, 5 },
1227 { nullptr, IconSet_3Arrows, 0 }
1230 size_t ScIconSetFormat::size() const
1232 return mpFormatData->m_Entries.size();
1236 namespace {
1238 const std::u16string_view a3TrafficLights1[] = {
1239 u"" BMP_ICON_SET_CIRCLES1_RED, u"" BMP_ICON_SET_CIRCLES1_YELLOW, u"" BMP_ICON_SET_CIRCLES1_GREEN
1242 const std::u16string_view a3TrafficLights2[] = {
1243 u"" BMP_ICON_SET_TRAFFICLIGHTS_RED, u"" BMP_ICON_SET_TRAFFICLIGHTS_YELLOW, u"" BMP_ICON_SET_TRAFFICLIGHTS_GREEN
1246 const std::u16string_view a3Arrows[] = {
1247 u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SAME, u"" BMP_ICON_SET_COLORARROWS_UP
1250 const std::u16string_view a3ArrowsGray[] = {
1251 u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SAME, u"" BMP_ICON_SET_GRAYARROWS_UP
1254 const std::u16string_view a3Flags[] = {
1255 u"" BMP_ICON_SET_FLAGS_RED, u"" BMP_ICON_SET_FLAGS_YELLOW, u"" BMP_ICON_SET_FLAGS_GREEN
1258 const std::u16string_view a3Smilies[] = {
1259 u"" BMP_ICON_SET_POSITIVE_YELLOW_SMILIE, u"" BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, u"" BMP_ICON_SET_NEGATIVE_YELLOW_SMILIE
1262 const std::u16string_view a3ColorSmilies[] = {
1263 u"" BMP_ICON_SET_POSITIVE_GREEN_SMILIE, u"" BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, u"" BMP_ICON_SET_NEGATIVE_RED_SMILIE
1266 const std::u16string_view a3Stars[] = {
1267 u"" BMP_ICON_SET_STARS_EMPTY, u"" BMP_ICON_SET_STARS_HALF, u"" BMP_ICON_SET_STARS_FULL
1270 const std::u16string_view a3Triangles[] = {
1271 u"" BMP_ICON_SET_TRIANGLES_DOWN, u"" BMP_ICON_SET_TRIANGLES_SAME, u"" BMP_ICON_SET_TRIANGLES_UP
1274 const std::u16string_view a4Arrows[] = {
1275 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
1278 const std::u16string_view a4ArrowsGray[] = {
1279 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
1282 const std::u16string_view a5Arrows[] = {
1283 u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN,
1284 u"" BMP_ICON_SET_COLORARROWS_SAME, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_COLORARROWS_UP
1287 const std::u16string_view a5ArrowsGray[] = {
1288 u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN,
1289 u"" BMP_ICON_SET_GRAYARROWS_SAME, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_GRAYARROWS_UP
1292 const std::u16string_view a4TrafficLights[] = {
1293 u"" BMP_ICON_SET_CIRCLES1_GRAY, u"" BMP_ICON_SET_CIRCLES1_RED,
1294 u"" BMP_ICON_SET_CIRCLES1_YELLOW, u"" BMP_ICON_SET_CIRCLES1_GREEN
1297 const std::u16string_view a5Quarters[] = {
1298 u"" BMP_ICON_SET_PIES_EMPTY, u"" BMP_ICON_SET_PIES_ONE_QUARTER, u"" BMP_ICON_SET_PIES_HALF,
1299 u"" BMP_ICON_SET_PIES_THREE_QUARTER, u"" BMP_ICON_SET_PIES_FULL,
1302 const std::u16string_view a5Boxes[] = {
1303 u"" BMP_ICON_SET_SQUARES_EMPTY, u"" BMP_ICON_SET_SQUARES_ONE_QUARTER,
1304 u"" BMP_ICON_SET_SQUARES_HALF, u"" BMP_ICON_SET_SQUARES_THREE_QUARTER,
1305 u"" BMP_ICON_SET_SQUARES_FULL
1308 const std::u16string_view a3Symbols1[] = {
1309 u"" BMP_ICON_SET_SYMBOLS1_CROSS, u"" BMP_ICON_SET_SYMBOLS1_EXCLAMATION_MARK, u"" BMP_ICON_SET_SYMBOLS1_CHECK
1312 const std::u16string_view a3Signs[] = {
1313 u"" BMP_ICON_SET_SHAPES_DIAMOND, u"" BMP_ICON_SET_SHAPES_TRIANGLE, u"" BMP_ICON_SET_SHAPES_CIRCLE
1316 const std::u16string_view a4RedToBlack[] = {
1317 u"" BMP_ICON_SET_CIRCLES2_DARK_GRAY, u"" BMP_ICON_SET_CIRCLES2_LIGHT_GRAY,
1318 u"" BMP_ICON_SET_CIRCLES2_LIGHT_RED, u"" BMP_ICON_SET_CIRCLES2_DARK_RED
1321 const std::u16string_view a4Ratings[] = {
1322 u"" BMP_ICON_SET_BARS_ONE_QUARTER, u"" BMP_ICON_SET_BARS_HALF,
1323 u"" BMP_ICON_SET_BARS_THREE_QUARTER, u"" BMP_ICON_SET_BARS_FULL
1326 const std::u16string_view a5Ratings[] = {
1327 u"" BMP_ICON_SET_BARS_EMPTY, u"" BMP_ICON_SET_BARS_ONE_QUARTER, u"" BMP_ICON_SET_BARS_HALF,
1328 u"" BMP_ICON_SET_BARS_THREE_QUARTER, u"" BMP_ICON_SET_BARS_FULL
1331 struct ScIconSetBitmapMap {
1332 ScIconSetType eType;
1333 const std::u16string_view* pBitmaps;
1336 const ScIconSetBitmapMap aBitmapMap[] = {
1337 { IconSet_3Arrows, a3Arrows },
1338 { IconSet_3ArrowsGray, a3ArrowsGray },
1339 { IconSet_3Flags, a3Flags },
1340 { IconSet_3Signs, a3Signs },
1341 { IconSet_3Symbols, a3Symbols1 },
1342 { IconSet_3Symbols2, a3Symbols1 },
1343 { IconSet_3TrafficLights1, a3TrafficLights1 },
1344 { IconSet_3TrafficLights2, a3TrafficLights2 },
1345 { IconSet_3Smilies, a3Smilies },
1346 { IconSet_3ColorSmilies, a3ColorSmilies },
1347 { IconSet_3Triangles, a3Triangles },
1348 { IconSet_3Stars, a3Stars },
1349 { IconSet_4Arrows, a4Arrows },
1350 { IconSet_4ArrowsGray, a4ArrowsGray },
1351 { IconSet_4Rating, a4Ratings },
1352 { IconSet_4RedToBlack, a4RedToBlack },
1353 { IconSet_4TrafficLights, a4TrafficLights },
1354 { IconSet_5Arrows, a5Arrows },
1355 { IconSet_5ArrowsGray, a5ArrowsGray },
1356 { IconSet_5Quarters, a5Quarters },
1357 { IconSet_5Ratings, a5Ratings },
1358 { IconSet_5Boxes, a5Boxes }
1361 const ScIconSetMap* findIconSetType(ScIconSetType eType)
1363 const ScIconSetMap* pMap = ScIconSetFormat::g_IconSetMap;
1364 for (; pMap->pName; ++pMap)
1366 if (pMap->eType == eType)
1367 return pMap;
1370 return nullptr;
1375 const char* ScIconSetFormat::getIconSetName( ScIconSetType eType )
1377 const ScIconSetMap* pMap = findIconSetType(eType);
1378 if (pMap)
1379 return pMap->pName;
1381 return "";
1384 sal_Int32 ScIconSetFormat::getIconSetElements( ScIconSetType eType )
1386 const ScIconSetMap* pMap = findIconSetType(eType);
1387 if (pMap)
1388 return pMap->nElements;
1390 return 0;
1393 OUString ScIconSetFormat::getIconName(ScIconSetType const eType, sal_Int32 const nIndex)
1395 OUString sBitmap;
1397 for(const ScIconSetBitmapMap & i : aBitmapMap)
1399 if(i.eType == eType)
1401 sBitmap = *(i.pBitmaps + nIndex);
1402 break;
1406 assert(!sBitmap.isEmpty());
1408 return sBitmap;
1411 BitmapEx& ScIconSetFormat::getBitmap(sc::IconSetBitmapMap & rIconSetBitmapMap,
1412 ScIconSetType const eType, sal_Int32 const nIndex)
1414 OUString sBitmap(ScIconSetFormat::getIconName(eType, nIndex));
1416 std::map<OUString, BitmapEx>::iterator itr = rIconSetBitmapMap.find(sBitmap);
1417 if (itr != rIconSetBitmapMap.end())
1418 return itr->second;
1420 BitmapEx aBitmap(sBitmap);
1421 std::pair<OUString, BitmapEx> aPair(sBitmap, aBitmap);
1422 std::pair<std::map<OUString, BitmapEx>::iterator, bool> itrNew = rIconSetBitmapMap.insert(aPair);
1423 assert(itrNew.second);
1425 return itrNew.first->second;
1428 void ScIconSetFormat::EnsureSize()
1430 ScIconSetType eType = mpFormatData->eIconSetType;
1431 for (const ScIconSetMap & i : g_IconSetMap)
1433 if (i.eType == eType)
1435 // size_t nElements = aIconSetMap[i].nElements;
1436 // TODO: implement
1437 break;
1442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */