Resolves: tdf#144811 use the hover-style menu for color submenus

Change-Id: I8653c36d084f9df5a4d34baf7d88e2f2b5f1609b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126209
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx
index f4caff9..7e0c9fc 100644
--- a/sc/source/ui/cctrl/checklistmenu.cxx
+++ b/sc/source/ui/cctrl/checklistmenu.cxx
@@ -38,6 +38,8 @@
#include <vcl/jsdialog/executor.hxx>

#include <document.hxx>
#include <docsh.hxx>
#include <viewdata.hxx>

using namespace com::sun::star;
using ::com::sun::star::uno::Reference;
@@ -120,7 +122,7 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, SelectHdl, weld::TreeView&, void)
    setSelectedMenuItem(nSelectedMenu, true);
}

void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction, bool bIndicateSubMenu)
void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction)
{
    MenuItemData aItem;
    aItem.mbEnabled = true;
@@ -129,10 +131,7 @@ void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction,

    mxMenu->show();
    mxMenu->append_text(rText);
    if (bIndicateSubMenu)
        mxMenu->set_image(mxMenu->n_children() - 1, *mxDropDown, 1);
    else
        mxMenu->set_image(mxMenu->n_children() - 1, css::uno::Reference<css::graphic::XGraphic>(), 1);
    mxMenu->set_image(mxMenu->n_children() - 1, css::uno::Reference<css::graphic::XGraphic>(), 1);
}

void ScCheckListMenuControl::addSeparator()
@@ -180,12 +179,12 @@ void ScCheckListMenuControl::CreateDropDown()
                         DrawSymbolFlags::NONE);
}

ScListSubMenuControl* ScCheckListMenuControl::addSubMenuItem(const OUString& rText, bool bEnabled)
ScListSubMenuControl* ScCheckListMenuControl::addSubMenuItem(const OUString& rText, bool bEnabled, bool bCheckList)
{
    MenuItemData aItem;
    aItem.mbEnabled = bEnabled;

    aItem.mxSubMenuWin.reset(new ScListSubMenuControl(mxMenu.get(), *this, mpNotifier));
    aItem.mxSubMenuWin.reset(new ScListSubMenuControl(mxMenu.get(), *this, bCheckList, mpNotifier));
    maMenuItems.emplace_back(std::move(aItem));

    mxMenu->show();
@@ -451,7 +450,7 @@ constexpr int nBorderWidth = 4;
// number of rows visible in checklist
constexpr int nCheckListVisibleRows = 8;

ScCheckListMenuControl::ScCheckListMenuControl(weld::Widget* pParent, ScDocument* pDoc,
ScCheckListMenuControl::ScCheckListMenuControl(weld::Widget* pParent, ScViewData& rViewData,
                                               bool bHasDates, int nWidth, vcl::ILibreOfficeKitNotifier* pNotifier)
    : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/filterdropdown.ui"))
    , mxPopover(mxBuilder->weld_popover("FilterDropDown"))
@@ -474,7 +473,7 @@ ScCheckListMenuControl::ScCheckListMenuControl(weld::Widget* pParent, ScDocument
    , mnWndWidth(0)
    , mePrevToggleAllState(TRISTATE_INDET)
    , mnSelectedMenu(MENU_NOT_SELECTED)
    , mpDoc(pDoc)
    , mrViewData(rViewData)
    , mnAsyncPostPopdownId(nullptr)
    , mnAsyncSetDropdownPosId(nullptr)
    , mpNotifier(pNotifier)
@@ -890,7 +889,7 @@ void ScCheckListMenuControl::setMemberSize(size_t n)

void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal, bool bVisible)
{
    SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
    SvNumberFormatter* pFormatter = mrViewData.GetDocument().GetFormatTable();

    // Convert the numeric date value to a date object.
    Date aDate = pFormatter->GetNullDate();
@@ -1448,7 +1447,7 @@ int ScCheckListMenuControl::IncreaseWindowWidthToFitText(int nMaxTextWidth)
    return mnCheckWidthReq + nBorder;
}

ScListSubMenuControl::ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, vcl::ILibreOfficeKitNotifier* pNotifier)
ScListSubMenuControl::ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, bool bCheckList, vcl::ILibreOfficeKitNotifier* pNotifier)
    : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/filtersubdropdown.ui"))
    , mxPopover(mxBuilder->weld_popover("FilterSubDropDown"))
    , mxContainer(mxBuilder->weld_container("container"))
@@ -1457,12 +1456,22 @@ ScListSubMenuControl::ScListSubMenuControl(weld::Widget* pParent, ScCheckListMen
    , mrParentControl(rParentControl)
    , mpNotifier(pNotifier)
{
    if (bCheckList)
    {
        mxMenu->set_clicks_to_toggle(1);
        mxMenu->enable_toggle_buttons(weld::ColumnToggleType::Radio);
    }

    mxMenu->connect_row_activated(LINK(this, ScListSubMenuControl, RowActivatedHdl));
    mxMenu->connect_toggled(LINK(this, ScListSubMenuControl, CheckToggledHdl));
    mxMenu->connect_key_press(LINK(this, ScListSubMenuControl, MenuKeyInputHdl));
}

void ScListSubMenuControl::StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect)
{
    if (mxPopupStartAction)
        mxPopupStartAction->execute();

    mxPopover->popup_at_rect(pParent, rRect, weld::Placement::End);

    mxMenu->set_cursor(0);
@@ -1491,16 +1500,33 @@ void ScListSubMenuControl::resizeToFitMenuItems()
    mxMenu->set_size_request(-1, mxMenu->get_preferred_size().Height() + 2);
}

void ScListSubMenuControl::addMenuItem(const OUString& rText, ScCheckListMenuControl::Action* pAction)
void ScListSubMenuControl::addItem(ScCheckListMenuControl::Action* pAction)
{
    ScCheckListMenuControl::MenuItemData aItem;
    aItem.mbEnabled = true;
    aItem.mxAction.reset(pAction);
    maMenuItems.emplace_back(std::move(aItem));
    mxMenu->show();
}

void ScListSubMenuControl::addMenuItem(const OUString& rText, ScCheckListMenuControl::Action* pAction)
{
    addItem(pAction);
    mxMenu->append_text(rText);
}

void ScListSubMenuControl::addMenuCheckItem(const OUString& rText, bool bActive, VirtualDevice& rImage, ScCheckListMenuControl::Action* pAction)
{
    addItem(pAction);
    mxMenu->insert(nullptr, -1, &rText, nullptr, nullptr, &rImage, false, mxScratchIter.get());
    mxMenu->set_toggle(*mxScratchIter, bActive ? TRISTATE_TRUE : TRISTATE_FALSE);
}

void ScListSubMenuControl::clearMenuItems()
{
    maMenuItems.clear();
    mxMenu->clear();
}

IMPL_LINK(ScListSubMenuControl, MenuKeyInputHdl, const KeyEvent&, rKEvt, bool)
{
    bool bConsumed = false;
@@ -1515,6 +1541,13 @@ IMPL_LINK(ScListSubMenuControl, MenuKeyInputHdl, const KeyEvent&, rKEvt, bool)
            bConsumed = true;
            break;
        }
        case KEY_SPACE:
        case KEY_RETURN:
        {
            // don't toggle checkbutton, go straight to activating entry
            bConsumed = RowActivatedHdl(*mxMenu);
            break;
        }
    }

    return bConsumed;
@@ -1526,6 +1559,16 @@ IMPL_LINK_NOARG(ScListSubMenuControl, RowActivatedHdl, weld::TreeView&, bool)
    return true;
}

IMPL_LINK(ScListSubMenuControl, CheckToggledHdl, const weld::TreeView::iter_col&, rRowCol, void)
{
    mxMenu->all_foreach([this, &rRowCol](weld::TreeIter& rEntry){
        bool bToggledEntry = mxMenu->iter_compare(rEntry, rRowCol.first) == 0;
        if (!bToggledEntry)
            mxMenu->set_toggle(rEntry, TRISTATE_FALSE);
        return false;
    });
}

void ScListSubMenuControl::executeMenuItem(size_t nPos)
{
    if (nPos >= maMenuItems.size())
@@ -1540,6 +1583,11 @@ void ScListSubMenuControl::executeMenuItem(size_t nPos)
        terminateAllPopupMenus();
}

void ScListSubMenuControl::setPopupStartAction(ScCheckListMenuControl::Action* p)
{
    mxPopupStartAction.reset(p);
}

void ScListSubMenuControl::terminateAllPopupMenus()
{
    if (comphelper::LibreOfficeKit::isActive())
diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx
index 6a5dbce..961fddc 100644
--- a/sc/source/ui/inc/checklistmenu.hxx
+++ b/sc/source/ui/inc/checklistmenu.hxx
@@ -11,6 +11,7 @@

#include <vcl/dockwin.hxx>
#include <vcl/timer.hxx>
#include <vcl/virdev.hxx>
#include <vcl/weld.hxx>

#include <memory>
@@ -18,10 +19,8 @@
#include <map>
#include <set>

class ScDocument;

class ScCheckListMenuControl;

class ScViewData;
struct ScCheckListMember;

struct ScCheckListMember
@@ -123,14 +122,14 @@ public:
        Config();
    };

    ScCheckListMenuControl(weld::Widget* pParent, ScDocument* pDoc,
    ScCheckListMenuControl(weld::Widget* pParent, ScViewData& rViewData,
                           bool bTreeMode, int nWidth,
                           vcl::ILibreOfficeKitNotifier* pNotifier);
    ~ScCheckListMenuControl();

    void addMenuItem(const OUString& rText, Action* pAction, bool bIndicateSubMenu = false);
    void addMenuItem(const OUString& rText, Action* pAction);
    void addSeparator();
    ScListSubMenuControl* addSubMenuItem(const OUString& rText, bool bEnabled);
    ScListSubMenuControl* addSubMenuItem(const OUString& rText, bool bEnabled, bool bCheckList);
    void resizeToFitMenuItems();

    void selectMenuItem(size_t nPos, bool bSubMenuTimer);
@@ -168,6 +167,8 @@ public:
     */
    ExtendedData* getExtendedData();

    ScViewData& GetViewData() const { return mrViewData; }

    void GrabFocus();

    void setOKAction(Action* p);
@@ -292,7 +293,7 @@ private:

    size_t  mnSelectedMenu;

    ScDocument* mpDoc;
    ScViewData& mrViewData;

    ImplSVEvent* mnAsyncPostPopdownId;
    ImplSVEvent* mnAsyncSetDropdownPosId;
@@ -323,7 +324,9 @@ private:
class ScListSubMenuControl final
{
public:
    ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, vcl::ILibreOfficeKitNotifier* pNotifier);
    ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, bool bCheckList, vcl::ILibreOfficeKitNotifier* pNotifier);

    void setPopupStartAction(ScCheckListMenuControl::Action* p);

    void GrabFocus();
    bool IsVisible() const;
@@ -332,10 +335,16 @@ public:
    void EndPopupMode();

    void addMenuItem(const OUString& rText, ScCheckListMenuControl::Action* pAction);
    void addMenuCheckItem(const OUString& rText, bool bActive, VirtualDevice& rImage, ScCheckListMenuControl::Action* pAction);
    void clearMenuItems();
    void resizeToFitMenuItems();

    void setSelectedMenuItem(size_t nPos);

    ScViewData& GetViewData() const { return mrParentControl.GetViewData(); }
    ScCheckListMenuControl::ExtendedData* getExtendedData() { return mrParentControl.getExtendedData(); }
    VclPtr<VirtualDevice> create_virtual_device() const { return mxMenu->create_virtual_device(); }

    /**
     * Dismiss all visible popup menus and set focus back to the application
     * window.  This method is called e.g. when a menu action is fired.
@@ -348,15 +357,18 @@ private:
    std::unique_ptr<weld::Container> mxContainer;
    std::unique_ptr<weld::TreeView> mxMenu;
    std::unique_ptr<weld::TreeIter> mxScratchIter;
    std::unique_ptr<ScCheckListMenuControl::Action> mxPopupStartAction;
    std::vector<ScCheckListMenuControl::MenuItemData> maMenuItems;
    ScCheckListMenuControl& mrParentControl;
    vcl::ILibreOfficeKitNotifier* mpNotifier;

    DECL_LINK(RowActivatedHdl, weld::TreeView& rMEvt, bool);
    DECL_LINK(CheckToggledHdl, const weld::TreeView::iter_col&, void);
    DECL_LINK(MenuKeyInputHdl, const KeyEvent&, bool);

    void NotifyCloseLOK();
    void executeMenuItem(size_t nPos);
    void addItem(ScCheckListMenuControl::Action* pAction);
};

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 81be888..dd24eb94 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -24,12 +24,13 @@
#include <editeng/adjustitem.hxx>
#include <sot/storage.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/editview.hxx>
#include <editeng/editobj.hxx>
#include <editeng/editstat.hxx>
#include <editeng/editview.hxx>
#include <editeng/flditem.hxx>
#include <editeng/justifyitem.hxx>
#include <editeng/outliner.hxx>
#include <editeng/misspellrange.hxx>
#include <editeng/editobj.hxx>
#include <o3tl/unit_conversion.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/viewfrm.hxx>
@@ -48,8 +49,8 @@
#include <sot/formats.hxx>
#include <comphelper/classids.hxx>

#include <svx/drawitem.hxx>
#include <svx/svdview.hxx>
#include <editeng/outliner.hxx>
#include <svx/svdocapt.hxx>
#include <svx/svdpagv.hxx>
#include <svtools/optionsdrawinglayer.hxx>
@@ -127,6 +128,9 @@
#include <inputopt.hxx>
#include <queryparam.hxx>

#include <officecfg/Office/Common.hxx>

#include <svx/PaletteManager.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <vcl/svapp.hxx>
@@ -495,6 +499,7 @@ struct AutoFilterData : public ScCheckListMenuControl::ExtendedData

class AutoFilterAction : public ScCheckListMenuControl::Action
{
protected:
    VclPtr<ScGridWindow> mpWindow;
    ScGridWindow::AutoFilterMode meMode;
public:
@@ -523,6 +528,242 @@ public:
    }
};

class AutoFilterSubMenuAction : public AutoFilterAction
{
protected:
    ScListSubMenuControl* m_pSubMenu;

public:
    AutoFilterSubMenuAction(ScGridWindow* p, ScListSubMenuControl* pSubMenu, ScGridWindow::AutoFilterMode eMode)
        : AutoFilterAction(p, eMode)
        , m_pSubMenu(pSubMenu)
    {
    }
};

class AutoFilterColorAction : public AutoFilterSubMenuAction
{
private:
    Color m_aColor;

public:
    AutoFilterColorAction(ScGridWindow* p, ScListSubMenuControl* pSubMenu, ScGridWindow::AutoFilterMode eMode, const Color& rColor)
        : AutoFilterSubMenuAction(p, pSubMenu, eMode)
        , m_aColor(rColor)
    {
    }

    virtual bool execute() override
    {
        const AutoFilterData* pData =
            static_cast<const AutoFilterData*>(m_pSubMenu->getExtendedData());

        if (!pData)
            return false;

        ScDBData* pDBData = pData->mpData;
        if (!pDBData)
            return false;

        const ScAddress& rPos = pData->maPos;

        ScViewData& rViewData = m_pSubMenu->GetViewData();
        ScDocument& rDoc = rViewData.GetDocument();

        ScQueryParam aParam;
        pDBData->GetQueryParam(aParam);

        // Try to use the existing entry for the column (if one exists).
        ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);

        if (!pEntry)
        {
            // Something went terribly wrong!
            return false;
        }

        if (ScTabViewShell::isAnyEditViewInRange(rViewData.GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2))
            return false;

        pEntry->bDoQuery = true;
        pEntry->nField = rPos.Col();
        pEntry->eConnect = SC_AND;

        ScFilterEntries aFilterEntries;
        rDoc.GetFilterEntries(rPos.Col(), rPos.Row(), rPos.Tab(), aFilterEntries);

        bool bActive = false;
        auto aItem = pEntry->GetQueryItem();
        if (aItem.maColor == m_aColor
            && ((meMode == ScGridWindow::AutoFilterMode::TextColor
                 && aItem.meType == ScQueryEntry::ByTextColor)
                || (meMode == ScGridWindow::AutoFilterMode::BackgroundColor
                    && aItem.meType == ScQueryEntry::ByBackgroundColor)))
        {
            bActive = true;
        }

        // Disable color filter when active color was selected
        if (bActive)
        {
            aParam.RemoveAllEntriesByField(rPos.Col());
            pEntry = nullptr;   // invalidated by RemoveAllEntriesByField call

            // tdf#46184 reset filter options to default values
            aParam.eSearchType = utl::SearchParam::SearchType::Normal;
            aParam.bCaseSens = false;
            aParam.bDuplicate = true;
            aParam.bInplace = true;
        }
        else
        {
            if (meMode == ScGridWindow::AutoFilterMode::TextColor)
                pEntry->SetQueryByTextColor(m_aColor);
            else
                pEntry->SetQueryByBackgroundColor(m_aColor);
        }

        rViewData.GetView()->Query(aParam, nullptr, true);
        pDBData->SetQueryParam(aParam);

        return true;
    }
};

class AutoFilterColorPopupStartAction : public AutoFilterSubMenuAction
{
public:
    AutoFilterColorPopupStartAction(ScGridWindow* p, ScListSubMenuControl* pSubMenu, ScGridWindow::AutoFilterMode eMode)
        : AutoFilterSubMenuAction(p, pSubMenu, eMode)
    {
    }

    virtual bool execute() override
    {
        const AutoFilterData* pData =
            static_cast<const AutoFilterData*>(m_pSubMenu->getExtendedData());

        if (!pData)
            return false;

        ScDBData* pDBData = pData->mpData;
        if (!pDBData)
            return false;

        ScViewData& rViewData = m_pSubMenu->GetViewData();
        ScDocument& rDoc = rViewData.GetDocument();
        const ScAddress& rPos = pData->maPos;

        ScFilterEntries aFilterEntries;
        rDoc.GetFilterEntries(rPos.Col(), rPos.Row(), rPos.Tab(), aFilterEntries);

        m_pSubMenu->clearMenuItems();

        std::set<Color> aColors = meMode == ScGridWindow::AutoFilterMode::TextColor
                                      ? aFilterEntries.getTextColors()
                                      : aFilterEntries.getBackgroundColors();

        XColorListRef xUserColorList;

        OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get());
        PaletteManager aPaletteManager;
        std::vector<OUString> aPaletteNames = aPaletteManager.GetPaletteList();
        for (size_t i = 0, nLen = aPaletteNames.size(); i < nLen; ++i)
        {
            if (aPaletteName == aPaletteNames[i])
            {
                aPaletteManager.SetPalette(i);
                xUserColorList = XPropertyList::AsColorList(
                                XPropertyList::CreatePropertyListFromURL(
                                XPropertyListType::Color, aPaletteManager.GetSelectedPalettePath()));
                if (!xUserColorList->Load())
                    xUserColorList = nullptr;
                break;
            }
        }

        ScQueryParam aParam;
        pDBData->GetQueryParam(aParam);
        ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);

        for (auto& rColor : aColors)
        {
            bool bActive = false;

            if (pEntry)
            {
                auto aItem = pEntry->GetQueryItem();
                if (aItem.maColor == rColor
                    && ((meMode == ScGridWindow::AutoFilterMode::TextColor
                         && aItem.meType == ScQueryEntry::ByTextColor)
                        || (meMode == ScGridWindow::AutoFilterMode::BackgroundColor
                            && aItem.meType == ScQueryEntry::ByBackgroundColor)))
                {
                    bActive = true;
                }
            }

            const bool bAutoColor = rColor == COL_AUTO;

            // ColorListBox::ShowPreview is similar
            ScopedVclPtr<VirtualDevice> xDev(m_pSubMenu->create_virtual_device());
            const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
            Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
            xDev->SetOutputSize(aImageSize);
            const tools::Rectangle aRect(Point(0, 0), aImageSize);

            if (bAutoColor)
            {
                const Color aW(COL_WHITE);
                const Color aG(0xef, 0xef, 0xef);
                int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1;
                int nCheckSize = nMinDim / 3;
                xDev->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG);
                xDev->SetFillColor();
            }
            else
                xDev->SetFillColor(rColor);

            xDev->SetLineColor(rStyleSettings.GetDisableColor());
            xDev->DrawRect(aRect);

            if (bAutoColor)
            {
                OUString sText = meMode == ScGridWindow::AutoFilterMode::TextColor
                                     ? ScResId(SCSTR_FILTER_AUTOMATIC_COLOR)
                                     : ScResId(SCSTR_FILTER_NO_FILL);
                m_pSubMenu->addMenuCheckItem(sText, bActive, *xDev,
                                             new AutoFilterColorAction(mpWindow, m_pSubMenu, meMode, rColor));
            }
            else
            {
                OUString sName;

                bool bFoundColorName = false;
                if (xUserColorList)
                {
                    sal_Int32 nPos = xUserColorList->GetIndexOfColor(rColor);
                    if (nPos != -1)
                    {
                        XColorEntry* pColorEntry = xUserColorList->GetColor(nPos);
                        sName = pColorEntry->GetName();
                        bFoundColorName = true;
                    }
                }
                if (!bFoundColorName)
                    sName = "#" + rColor.AsRGBHexString().toAsciiUpperCase();

                m_pSubMenu->addMenuCheckItem(sName, bActive, *xDev,
                                             new AutoFilterColorAction(mpWindow, m_pSubMenu, meMode, rColor));
            }
        }

        m_pSubMenu->resizeToFitMenuItems();

        return false;
    }
};

class AddItemToEntry
{
    ScQueryEntry::QueryItemsType& mrItems;
@@ -594,7 +835,7 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)

    weld::Window* pPopupParent = GetFrameWeld();
    int nColWidth = ScViewData::ToPixel(rDoc.GetColWidth(nCol, nTab), mrViewData.GetPPTX());
    mpAutoFilterPopup.reset(new ScCheckListMenuControl(pPopupParent, &rDoc,
    mpAutoFilterPopup.reset(new ScCheckListMenuControl(pPopupParent, mrViewData,
                                                       aFilterEntries.mbHasDates, nColWidth, pNotifier));

    int nMaxTextWidth = 0;
@@ -735,10 +976,10 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
    mpAutoFilterPopup->addMenuItem(
        ScResId(SCSTR_FILTER_NOTEMPTY), new AutoFilterAction(this, AutoFilterMode::NonEmpty));
    mpAutoFilterPopup->addSeparator();
    mpAutoFilterPopup->addMenuItem(
        ScResId(SCSTR_FILTER_TEXT_COLOR), new AutoFilterAction(this, AutoFilterMode::TextColor), true);
    mpAutoFilterPopup->addMenuItem(
        ScResId(SCSTR_FILTER_BACKGROUND_COLOR), new AutoFilterAction(this, AutoFilterMode::BackgroundColor), true);
    if (ScListSubMenuControl* pSubMenu = mpAutoFilterPopup->addSubMenuItem(ScResId(SCSTR_FILTER_TEXT_COLOR), true, true))
        pSubMenu->setPopupStartAction(new AutoFilterColorPopupStartAction(this, pSubMenu, AutoFilterMode::TextColor));
    if (ScListSubMenuControl* pSubMenu = mpAutoFilterPopup->addSubMenuItem(ScResId(SCSTR_FILTER_BACKGROUND_COLOR), true, true))
        pSubMenu->setPopupStartAction(new AutoFilterColorPopupStartAction(this, pSubMenu, AutoFilterMode::BackgroundColor));
    mpAutoFilterPopup->addSeparator();
    mpAutoFilterPopup->addMenuItem(
        ScResId(SCSTR_STDFILTER), new AutoFilterAction(this, AutoFilterMode::Custom));
@@ -922,91 +1163,8 @@ void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode)
            break;
            case AutoFilterMode::TextColor:
            case AutoFilterMode::BackgroundColor:
            {
                ScFilterEntries aFilterEntries;
                rDoc.GetFilterEntries(rPos.Col(), rPos.Row(), rPos.Tab(), aFilterEntries);

                weld::Window* pWindow = GetFrameWeld();
                std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pWindow, "modules/scalc/ui/colormenu.ui"));
                std::unique_ptr<weld::Menu> xColorMenu(xBuilder->weld_menu("menu"));

                std::set<Color> aColors = eMode == AutoFilterMode::TextColor
                                              ? aFilterEntries.getTextColors()
                                              : aFilterEntries.getBackgroundColors();

                sal_Int32 i = 1;
                sal_Int32 nActive = -1;
                for (auto& rColor : aColors)
                {
                    if (rColor == COL_AUTO)
                    {
                        OUString sText = eMode == AutoFilterMode::TextColor
                                             ? ScResId(SCSTR_FILTER_AUTOMATIC_COLOR)
                                             : ScResId(SCSTR_FILTER_NO_FILL);
                        xColorMenu->append_check(OUString::number(i), sText);
                    }
                    else
                    {
                        // ColorListBox::ShowPreview is similar
                        ScopedVclPtr<VirtualDevice> xDev(pWindow->create_virtual_device());
                        const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
                        Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
                        xDev->SetOutputSize(aImageSize);
                        const tools::Rectangle aRect(Point(0, 0), aImageSize);
                        xDev->SetFillColor(rColor);
                        xDev->SetLineColor(rStyleSettings.GetDisableColor());
                        xDev->DrawRect(aRect);

                        xColorMenu->insert(-1, OUString::number(i), OUString(),
                                           nullptr, xDev.get(), nullptr, TRISTATE_TRUE);
                    }
                    auto aItem = pEntry->GetQueryItem();
                    if (aItem.maColor == rColor
                        && ((eMode == AutoFilterMode::TextColor
                             && aItem.meType == ScQueryEntry::ByTextColor)
                            || (eMode == AutoFilterMode::BackgroundColor
                                && aItem.meType == ScQueryEntry::ByBackgroundColor)))
                    {
                        nActive = i;
                        xColorMenu->set_active(OString::number(i), true);
                    }
                    i++;
                }

                sal_Int32 nSelected = mpAutoFilterPopup->ExecuteMenu(*xColorMenu);
                xColorMenu.reset();

                if (nSelected == 0)
                    return;

                mpAutoFilterPopup->terminateAllPopupMenus();

                // Disable color filter when active color was selected
                if (nSelected == nActive)
                {
                    aParam.RemoveAllEntriesByField(rPos.Col());
                    pEntry = nullptr;   // invalidated by RemoveAllEntriesByField call

                    // tdf#46184 reset filter options to default values
                    aParam.eSearchType = utl::SearchParam::SearchType::Normal;
                    aParam.bCaseSens = false;
                    aParam.bDuplicate = true;
                    aParam.bInplace = true;
                }
                else
                {
                    // Get selected color from set
                    std::set<Color>::iterator it = aColors.begin();
                    std::advance(it, nSelected - 1);
                    Color selectedColor = *it;

                    if (eMode == AutoFilterMode::TextColor)
                        pEntry->SetQueryByTextColor(selectedColor);
                    else
                        pEntry->SetQueryByBackgroundColor(selectedColor);
                }
            }

                assert(false && "should be handled by AutoFilterColorAction::execute");
            break;
            break;
            default:
                // We don't know how to handle this!
diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx
index bf9e41b..a7cd96a 100644
--- a/sc/source/ui/view/gridwin2.cxx
+++ b/sc/source/ui/view/gridwin2.cxx
@@ -474,7 +474,7 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScr
        pNotifier = SfxViewShell::Current();

    weld::Window* pPopupParent = GetFrameWeld();
    mpDPFieldPopup.reset(new ScCheckListMenuControl(pPopupParent, &mrViewData.GetDocument(),
    mpDPFieldPopup.reset(new ScCheckListMenuControl(pPopupParent, mrViewData,
                                                    false, -1, pNotifier));

    mpDPFieldPopup->setExtendedData(std::move(pDPData));
@@ -519,7 +519,7 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScr
            ScResId(STR_MENU_SORT_DESC),
            new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::DESCENDING, 0, pViewShell));

        ScListSubMenuControl* pSubMenu = mpDPFieldPopup->addSubMenuItem(ScResId(STR_MENU_SORT_CUSTOM), !aUserSortNames.empty());
        ScListSubMenuControl* pSubMenu = mpDPFieldPopup->addSubMenuItem(ScResId(STR_MENU_SORT_CUSTOM), !aUserSortNames.empty(), false);
        if (pSubMenu)
        {
            size_t n = aUserSortNames.size();
diff --git a/sc/uiconfig/scalc/ui/filtersubdropdown.ui b/sc/uiconfig/scalc/ui/filtersubdropdown.ui
index 5785bd9..eb9d344 100644
--- a/sc/uiconfig/scalc/ui/filtersubdropdown.ui
+++ b/sc/uiconfig/scalc/ui/filtersubdropdown.ui
@@ -2,14 +2,20 @@
<!-- Generated with glade 3.38.2 -->
<interface domain="sc">
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkTreeStore" id="liststore1">
  <object class="GtkListStore" id="liststore1">
    <columns>
      <!-- column-name text -->
      <!-- column-name check1 -->
      <column type="gboolean"/>
      <!-- column-name surface -->
      <column type="CairoSurface"/>
      <!-- column-name text1 -->
      <column type="gchararray"/>
      <!-- column-name image1 -->
      <column type="GdkPixbuf"/>
      <!-- column-name id -->
      <column type="gchararray"/>
      <!-- column-name checkvis1 -->
      <column type="gboolean"/>
      <!-- column-name checktri1 -->
      <column type="gboolean"/>
    </columns>
  </object>
  <object class="GtkPopover" id="FilterSubDropDown">
@@ -52,9 +58,10 @@
                <child>
                  <object class="GtkTreeViewColumn" id="treeviewcolumn1">
                    <child>
                      <object class="GtkCellRendererText" id="cellrenderertext1"/>
                      <object class="GtkCellRendererToggle" id="cellrenderertoggle"/>
                      <attributes>
                        <attribute name="text">0</attribute>
                        <attribute name="visible">4</attribute>
                        <attribute name="active">0</attribute>
                      </attributes>
                    </child>
                  </object>
@@ -62,9 +69,19 @@
                <child>
                  <object class="GtkTreeViewColumn" id="treeviewcolumn2">
                    <child>
                      <object class="GtkCellRendererPixbuf" id="cellrenderertext55"/>
                      <object class="GtkCellRendererPixbuf" id="cellrendererpixbuf"/>
                      <attributes>
                        <attribute name="pixbuf">1</attribute>
                        <attribute name="surface">1</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="treeviewcolumn3">
                    <child>
                      <object class="GtkCellRendererText" id="cellrenderertext"/>
                      <attributes>
                        <attribute name="text">2</attribute>
                      </attributes>
                    </child>
                  </object>