sc/source/ui/cctrl/checklistmenu.cxx      |   74 +++++-
 sc/source/ui/inc/checklistmenu.hxx        |   28 +-
 sc/source/ui/view/gridwin.cxx             |  344 +++++++++++++++++++++---------
 sc/source/ui/view/gridwin2.cxx            |    4 
 sc/uiconfig/scalc/ui/filtersubdropdown.ui |   33 ++
 5 files changed, 359 insertions(+), 124 deletions(-)

New commits:
commit 29145df0977baa866e7da94d1d385b772ae1e6ce
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Mon Nov 29 12:55:38 2021 +0000
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Thu Dec 2 23:27:27 2021 +0100

    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 <caol...@redhat.com>

diff --git a/sc/source/ui/cctrl/checklistmenu.cxx 
b/sc/source/ui/cctrl/checklistmenu.cxx
index f4caff97e8ad..7e0c9fc5c03c 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 6a5dbceb1966..961fddceac58 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 81be88882264..dd24eb941a26 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 bf9e41bd7369..a7cd96a649ba 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 5785bd9d80ae..eb9d3444032c 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>

Reply via email to