sc/inc/colorscale.hxx | 6 +- sc/inc/fillinfo.hxx | 1 sc/qa/unit/subsequent_filters_test4.cxx | 14 +++++ sc/qa/unit/ucalc_condformat.cxx | 9 +-- sc/source/core/data/colorscale.cxx | 66 ++++++++++++++++++------- sc/source/ui/condformat/condformatdlgentry.cxx | 30 ++++------- sc/uiconfig/scalc/ui/conditionaliconset.ui | 11 +++- 7 files changed, 96 insertions(+), 41 deletions(-)
New commits: commit fcc5770dd1e33dcb4f4f0c28683569af5d1d8368 Author: AhmedHamed <ahmedhamed3...@gmail.com> AuthorDate: Tue Apr 2 19:05:00 2024 +0200 Commit: Andreas Heinisch <andreas.heini...@yahoo.de> CommitDate: Mon Apr 22 18:37:01 2024 +0200 tdf#61313 Replace the static ">=" with a dropdown of different operators The problem is with conditional formatting using icon set, as the icons order is fixed. It is solved by using comboBoxes for condition mode in ScIconSetFrmtDataEntry for every icon, and adjusting the UI file. A function that compares according to the currnt mode is added. Related CppunitTest files are updated. For every cell, last valid condition is applied. Change-Id: I489206d349a46092b307203c180705f42883183d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165701 Tested-by: Jenkins Reviewed-by: Heiko Tietze <heiko.tie...@documentfoundation.org> Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> diff --git a/sc/inc/colorscale.hxx b/sc/inc/colorscale.hxx index 2bb2c8ea5f6a..cbef08b6e05d 100644 --- a/sc/inc/colorscale.hxx +++ b/sc/inc/colorscale.hxx @@ -48,11 +48,13 @@ private: ScConditionalFormat* mpFormat; Color maColor; ScColorScaleEntryType meType; + ScConditionMode meMode; void setListener(); public: - SC_DLLPUBLIC ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType = COLORSCALE_VALUE); + SC_DLLPUBLIC ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType = COLORSCALE_VALUE, + ScConditionMode eMode = ScConditionMode::Equal); SC_DLLPUBLIC ScColorScaleEntry(); ScColorScaleEntry(const ScColorScaleEntry& rEntry); ScColorScaleEntry(ScDocument* pDoc, const ScColorScaleEntry& rEntry); @@ -74,7 +76,9 @@ public: SC_DLLPUBLIC OUString GetFormula( formula::FormulaGrammar::Grammar eGrammar ) const; ScColorScaleEntryType GetType() const { return meType;} + ScConditionMode GetMode() const { return meMode; } SC_DLLPUBLIC void SetType( ScColorScaleEntryType eType ); + SC_DLLPUBLIC void SetMode( ScConditionMode eMode ) { meMode = eMode; } void SetRepaintCallback(ScConditionalFormat* pParent); void SetRepaintCallback(const std::function<void()>& func); diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx index caecd6a7072b..e9c713373724 100644 --- a/sc/inc/fillinfo.hxx +++ b/sc/inc/fillinfo.hxx @@ -92,6 +92,7 @@ struct ScIconSetInfo { sal_Int32 nIconIndex; ScIconSetType eIconSetType; + ScConditionMode eConditionMode; tools::Long mnHeight = 0; bool mbShowValue; }; diff --git a/sc/qa/unit/subsequent_filters_test4.cxx b/sc/qa/unit/subsequent_filters_test4.cxx index e7bced8a313f..1adab95122e2 100644 --- a/sc/qa/unit/subsequent_filters_test4.cxx +++ b/sc/qa/unit/subsequent_filters_test4.cxx @@ -864,6 +864,17 @@ CPPUNIT_TEST_FIXTURE(ScFiltersTest4, testCondFormatThemeColor3XLSX) namespace { +// This function is used temporarily so we don't have to update test files. +void convertToOldCondFormat(const ScIconSetFormat* pIconSet) +{ + auto itr = pIconSet->begin(); + (*itr)->SetMode(ScConditionMode::Less); + (*itr)->SetValue((*(itr + 1))->GetValue()); + (*itr)->SetType((*(++itr))->GetType()); + for (; itr != pIconSet->end(); ++itr) + (*itr)->SetMode(ScConditionMode::EqGreater); +} + void testComplexIconSetsXLSX_Impl(const ScDocument& rDoc, SCCOL nCol, ScIconSetType eType) { ScConditionalFormat* pFormat = rDoc.GetCondFormat(nCol, 1, 0); @@ -886,6 +897,7 @@ void testCustomIconSetsXLSX_Impl(const ScDocument& rDoc, SCCOL nCol, SCROW nRow, CPPUNIT_ASSERT(pEntry); CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::Iconset, pEntry->GetType()); const ScIconSetFormat* pIconSet = static_cast<const ScIconSetFormat*>(pEntry); + convertToOldCondFormat(pIconSet); std::unique_ptr<ScIconSetInfo> pInfo(pIconSet->GetIconSetInfo(ScAddress(nCol, nRow, 1))); if (nIndex == -1) CPPUNIT_ASSERT(!pInfo); @@ -934,6 +946,7 @@ CPPUNIT_TEST_FIXTURE(ScFiltersTest4, testTdf101104) CPPUNIT_ASSERT(pEntry); CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::Iconset, pEntry->GetType()); const ScIconSetFormat* pIconSet = static_cast<const ScIconSetFormat*>(pEntry); + convertToOldCondFormat(pIconSet); for (size_t i = 1; i < 10; ++i) { @@ -960,6 +973,7 @@ CPPUNIT_TEST_FIXTURE(ScFiltersTest4, testTdf64401) CPPUNIT_ASSERT(pEntry); CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::Iconset, pEntry->GetType()); const ScIconSetFormat* pIconSet = static_cast<const ScIconSetFormat*>(pEntry); + convertToOldCondFormat(pIconSet); for (size_t i = 0; i < 10; ++i) { diff --git a/sc/qa/unit/ucalc_condformat.cxx b/sc/qa/unit/ucalc_condformat.cxx index c4dd685c41a8..b38632743f65 100644 --- a/sc/qa/unit/ucalc_condformat.cxx +++ b/sc/qa/unit/ucalc_condformat.cxx @@ -731,9 +731,9 @@ CPPUNIT_TEST_FIXTURE(TestCondformat, testIconSet) ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc); ScIconSetFormatData* pData = new ScIconSetFormatData; - pData->m_Entries.emplace_back(new ScColorScaleEntry(0, COL_BLUE)); - pData->m_Entries.emplace_back(new ScColorScaleEntry(1, COL_GREEN)); - pData->m_Entries.emplace_back(new ScColorScaleEntry(2, COL_RED)); + pData->m_Entries.emplace_back(new ScColorScaleEntry(0, COL_BLUE, COLORSCALE_VALUE, ScConditionMode::EqGreater)); + pData->m_Entries.emplace_back(new ScColorScaleEntry(1, COL_GREEN, COLORSCALE_VALUE, ScConditionMode::EqGreater)); + pData->m_Entries.emplace_back(new ScColorScaleEntry(2, COL_RED, COLORSCALE_VALUE, ScConditionMode::Equal)); pEntry->SetIconSetData(pData); m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1); @@ -742,11 +742,10 @@ CPPUNIT_TEST_FIXTURE(TestCondformat, testIconSet) static struct { double nVal; sal_Int32 nIndex; } const aTests[] = { - { -1.0, 0 }, { 0.0, 0 }, { 1.0, 1 }, { 2.0, 2 }, - { 3.0, 2 } + { 3.0, 1 } }; for(size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) { diff --git a/sc/source/core/data/colorscale.cxx b/sc/source/core/data/colorscale.cxx index 415dde5872e5..963ee78c05d3 100644 --- a/sc/source/core/data/colorscale.cxx +++ b/sc/source/core/data/colorscale.cxx @@ -154,15 +154,17 @@ bool ScFormulaListener::NeedsRepaint() const ScColorScaleEntry::ScColorScaleEntry(): mnVal(0), mpFormat(nullptr), - meType(COLORSCALE_VALUE) + meType(COLORSCALE_VALUE), + meMode(ScConditionMode::Equal) { } -ScColorScaleEntry::ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType): +ScColorScaleEntry::ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType, ScConditionMode eMode): mnVal(nVal), mpFormat(nullptr), maColor(rCol), - meType(eType) + meType(eType), + meMode(eMode) { } @@ -170,7 +172,8 @@ ScColorScaleEntry::ScColorScaleEntry(const ScColorScaleEntry& rEntry): mnVal(rEntry.mnVal), mpFormat(rEntry.mpFormat), maColor(rEntry.maColor), - meType(rEntry.meType) + meType(rEntry.meType), + meMode(rEntry.meMode) { setListener(); if(rEntry.mpCell) @@ -185,7 +188,8 @@ ScColorScaleEntry::ScColorScaleEntry(ScDocument* pDoc, const ScColorScaleEntry& mnVal(rEntry.mnVal), mpFormat(rEntry.mpFormat), maColor(rEntry.maColor), - meType(rEntry.meType) + meType(rEntry.meType), + meMode(rEntry.meMode) { setListener(); if(rEntry.mpCell) @@ -1066,6 +1070,30 @@ void ScDataBarFormat::EnsureSize() } } +static bool Compare(double nVal1, double nVal2, const ScIconSetFormat::const_iterator& itr) +{ + switch ((*itr)->GetMode()) + { + case ScConditionMode::Equal: + return nVal1 == nVal2; + case ScConditionMode::Less: + return nVal1 < nVal2; + case ScConditionMode::Greater: + return nVal1 > nVal2; + case ScConditionMode::EqLess: + return nVal1 <= nVal2; + case ScConditionMode::EqGreater: + return nVal1 >= nVal2; + case ScConditionMode::NotEqual: + return nVal1 != nVal2; + + default: + break; + } + + return false; +} + ScIconSetFormatData::ScIconSetFormatData(ScIconSetFormatData const& rOther) : eIconSetType(rOther.eIconSetType) , mbShowValue(rOther.mbShowValue) @@ -1131,27 +1159,32 @@ std::unique_ptr<ScIconSetInfo> ScIconSetFormat::GetIconSetInfo(const ScAddress& // now we have for sure a value double nVal = rCell.getValue(); - if (mpFormatData->m_Entries.size() < 2) + if (mpFormatData->m_Entries.size() < 1) return nullptr; double nMin = GetMinValue(); double nMax = GetMaxValue(); - sal_Int32 nIndex = 0; + sal_Int32 nIndex = -1; + ScConditionMode eMode = ScConditionMode::EqGreater; const_iterator itr = begin(); - ++itr; - double nValMax = CalcValue(nMin, nMax, itr); + double nValRef = 0; - ++itr; - while(itr != end() && nVal >= nValMax) + int i = 0; + while(itr != end()) { - ++nIndex; - nValMax = CalcValue(nMin, nMax, itr); - ++itr; + nValRef = CalcValue(nMin, nMax, itr); + if (Compare(nVal, nValRef, itr)) + { + nIndex = i; + eMode = (*itr)->GetMode(); + } + itr++; + i++; } - if(nVal >= nValMax) - ++nIndex; + if (nIndex == -1) + return nullptr; std::unique_ptr<ScIconSetInfo> pInfo(new ScIconSetInfo); @@ -1184,6 +1217,7 @@ std::unique_ptr<ScIconSetInfo> ScIconSetFormat::GetIconSetInfo(const ScAddress& } pInfo->mbShowValue = mpFormatData->mbShowValue; + pInfo->eConditionMode = eMode; return pInfo; } diff --git a/sc/source/ui/condformat/condformatdlgentry.cxx b/sc/source/ui/condformat/condformatdlgentry.cxx index 860e8c225150..9798263d06c7 100644 --- a/sc/source/ui/condformat/condformatdlgentry.cxx +++ b/sc/source/ui/condformat/condformatdlgentry.cxx @@ -1318,9 +1318,9 @@ protected: private: std::unique_ptr<weld::Container> mxGrid; std::unique_ptr<weld::Image> mxImgIcon; - std::unique_ptr<weld::Label> mxFtEntry; std::unique_ptr<weld::Entry> mxEdEntry; std::unique_ptr<weld::ComboBox> mxLbEntryType; + std::unique_ptr<weld::ComboBox> mxConditionMode; weld::Container* mpContainer; public: @@ -1336,22 +1336,25 @@ public: } ScColorScaleEntry* CreateEntry(ScDocument& rDoc, const ScAddress& rPos) const; - - void SetFirstEntry(); }; ScIconSetFrmtDataEntry::ScIconSetFrmtDataEntry(weld::Container* pParent, ScIconSetType eType, const ScDocument* pDoc, sal_Int32 i, const ScColorScaleEntry* pEntry) : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/conditionaliconset.ui")) , mxGrid(mxBuilder->weld_container("ConditionalIconSet")) , mxImgIcon(mxBuilder->weld_image("icon")) - , mxFtEntry(mxBuilder->weld_label("label")) , mxEdEntry(mxBuilder->weld_entry("entry")) , mxLbEntryType(mxBuilder->weld_combo_box("listbox")) + , mxConditionMode(mxBuilder->weld_combo_box("conditionMode")) , mpContainer(pParent) { mxImgIcon->set_from_icon_name(ScIconSetFormat::getIconName(eType, i)); if(pEntry) { + if (pEntry->GetMode() >= ScConditionMode::Equal && pEntry->GetMode() <= ScConditionMode::NotEqual) + mxConditionMode->set_active(static_cast<int>(pEntry->GetMode())); + else + assert(false && "ScIconSetFrmtDataEntry::ScIconSetFrmtDataEntry: Invalid condition mode"); + switch(pEntry->GetType()) { case COLORSCALE_VALUE: @@ -1377,6 +1380,7 @@ ScIconSetFrmtDataEntry::ScIconSetFrmtDataEntry(weld::Container* pParent, ScIconS else { mxLbEntryType->set_active(1); + mxConditionMode->set_active(0); } } @@ -1387,7 +1391,8 @@ ScIconSetFrmtDataEntry::~ScIconSetFrmtDataEntry() ScColorScaleEntry* ScIconSetFrmtDataEntry::CreateEntry(ScDocument& rDoc, const ScAddress& rPos) const { - sal_Int32 nPos = mxLbEntryType->get_active(); + sal_Int32 nTypePos = mxLbEntryType->get_active(); + sal_Int32 nModePos = mxConditionMode->get_active(); OUString aText = mxEdEntry->get_text(); ScColorScaleEntry* pEntry = new ScColorScaleEntry(); @@ -1397,7 +1402,7 @@ ScColorScaleEntry* ScIconSetFrmtDataEntry::CreateEntry(ScDocument& rDoc, const S (void)pNumberFormatter->IsNumberFormat(aText, nIndex, nVal); pEntry->SetValue(nVal); - switch(nPos) + switch(nTypePos) { case 0: pEntry->SetType(COLORSCALE_VALUE); @@ -1416,16 +1421,9 @@ ScColorScaleEntry* ScIconSetFrmtDataEntry::CreateEntry(ScDocument& rDoc, const S assert(false); } - return pEntry; -} + pEntry->SetMode(static_cast<ScConditionMode>(nModePos)); -void ScIconSetFrmtDataEntry::SetFirstEntry() -{ - mxEdEntry->hide(); - mxLbEntryType->hide(); - mxFtEntry->hide(); - mxEdEntry->set_text("0"); - mxLbEntryType->set_active(1); + return pEntry; } ScIconSetFrmtEntry::ScIconSetFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScIconSetFormat* pFormat) @@ -1454,7 +1452,6 @@ ScIconSetFrmtEntry::ScIconSetFrmtEntry(ScCondFormatList* pParent, ScDocument* pD mxIconParent.get(), eType, pDoc, i, pIconSetFormatData->m_Entries[i].get())); maEntries[i]->set_grid_top_attach(i); } - maEntries[0]->SetFirstEntry(); } else IconSetTypeHdl(*mxLbIconSetType); @@ -1488,7 +1485,6 @@ IMPL_LINK_NOARG( ScIconSetFrmtEntry, IconSetTypeHdl, weld::ComboBox&, void ) maEntries[i]->set_grid_top_attach(i); maEntries[i]->Show(); } - maEntries[0]->SetFirstEntry(); } OUString ScIconSetFrmtEntry::GetExpressionString() diff --git a/sc/uiconfig/scalc/ui/conditionaliconset.ui b/sc/uiconfig/scalc/ui/conditionaliconset.ui index bf129a2c914c..342a4747c012 100644 --- a/sc/uiconfig/scalc/ui/conditionaliconset.ui +++ b/sc/uiconfig/scalc/ui/conditionaliconset.ui @@ -16,10 +16,17 @@ <property name="row_spacing">6</property> <property name="column_spacing">12</property> <child> - <object class="GtkLabel" id="label"> + <object class="GtkComboBoxText" id="conditionMode"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="label" translatable="yes" context="conditionaliconset|label"> >= </property> + <items> + <item translatable="no" context="conditionaliconset|conditionMode"> = </item> + <item translatable="no" context="conditionaliconset|conditionMode"> < </item> + <item translatable="no" context="conditionaliconset|conditionMode"> > </item> + <item translatable="no" context="conditionaliconset|conditionMode"> <= </item> + <item translatable="no" context="conditionaliconset|conditionMode"> >= </item> + <item translatable="no" context="conditionaliconset|conditionMode"> <> </item> + </items> </object> <packing> <property name="left_attach">1</property>