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
diff --git a/sc/inc/colorscale.hxx b/sc/inc/colorscale.hxx
index 2bb2c8e..cbef08b 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 caecd6a7..e9c7133 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 e7bced8..1adab95 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 c4dd685..b386327 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 415dde5..963ee78 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 860e8c2..9798263 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 bf129a2..342a474 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"> &gt;= </property>
            <items>
              <item translatable="no" context="conditionaliconset|conditionMode"> = </item>
              <item translatable="no" context="conditionaliconset|conditionMode"> &lt; </item>
              <item translatable="no" context="conditionaliconset|conditionMode"> &gt; </item>
              <item translatable="no" context="conditionaliconset|conditionMode"> &lt;= </item>
              <item translatable="no" context="conditionaliconset|conditionMode"> &gt;= </item>
              <item translatable="no" context="conditionaliconset|conditionMode"> &lt;&gt; </item>
            </items>
          </object>
          <packing>
            <property name="left_attach">1</property>