[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - sc/source sc/uiconfig

Szymon KÅ‚os (via logerrit) logerrit at kemper.freedesktop.org
Mon Nov 30 17:21:53 UTC 2020


 sc/source/ui/cctrl/checklistmenu.cxx   |  554 ++++++++++++++++++---------------
 sc/source/ui/inc/checklistmenu.hxx     |   66 +--
 sc/source/ui/view/gridwin.cxx          |   13 
 sc/source/ui/view/gridwin2.cxx         |    3 
 sc/uiconfig/scalc/ui/filterdropdown.ui |  133 ++++++-
 5 files changed, 436 insertions(+), 333 deletions(-)

New commits:
commit 0b95ba1c9335e247a2e2ff946d36f98338aab1b1
Author:     Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Tue Oct 20 10:55:44 2020 +0200
Commit:     Szymon Kłos <szymon.klos at collabora.com>
CommitDate: Mon Nov 30 18:21:13 2020 +0100

    Autofilter popup: sync code with master
    
    Change-Id: I37f236e9f2331b42fe86d933d64ff136e98cad90
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/106877
    Tested-by: Szymon Kłos <szymon.klos at collabora.com>
    Reviewed-by: Szymon Kłos <szymon.klos at collabora.com>

diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx
index 44b7607f6340..8c9317f9d5ab 100644
--- a/sc/source/ui/cctrl/checklistmenu.cxx
+++ b/sc/source/ui/cctrl/checklistmenu.cxx
@@ -25,7 +25,7 @@
 
 #include <vcl/decoview.hxx>
 #include <vcl/event.hxx>
-#include <vcl/floatwin.hxx>
+#include <vcl/dockwin.hxx>
 #include <vcl/settings.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/virdev.hxx>
@@ -40,7 +40,6 @@ using ::com::sun::star::uno::Reference;
 
 ScCheckListMenuControl::MenuItemData::MenuItemData()
     : mbEnabled(true)
-    , mbSeparator(false)
 {
 }
 
@@ -120,13 +119,12 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, SelectHdl, weld::TreeView&, void)
     else
         nSelectedMenu = mxMenu->get_iter_index_in_parent(*mxScratchIter);
 
-    setSelectedMenuItem(nSelectedMenu, true, false);
+    setSelectedMenuItem(nSelectedMenu, true);
 }
 
 void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction)
 {
     MenuItemData aItem;
-    aItem.maText = rText;
     aItem.mbEnabled = true;
     aItem.mxAction.reset(pAction);
     maMenuItems.emplace_back(std::move(aItem));
@@ -139,10 +137,9 @@ void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction)
 void ScCheckListMenuControl::addSeparator()
 {
     MenuItemData aItem;
-    aItem.mbSeparator = true;
     maMenuItems.emplace_back(std::move(aItem));
 
-    //mxMenu->append_separator("seperator" + OUString::number(maMenuItems.size()));
+    //mxMenu->append_separator("separator" + OUString::number(maMenuItems.size()));
 }
 
 IMPL_LINK(ScCheckListMenuControl, TreeSizeAllocHdl, const Size&, rSize, void)
@@ -168,10 +165,10 @@ ScCheckListMenuWindow* ScCheckListMenuControl::addSubMenuItem(const OUString& rT
     assert(mbCanHaveSubMenu);
 
     MenuItemData aItem;
-    aItem.maText = rText;
     aItem.mbEnabled = bEnabled;
     vcl::Window *pContainer = mxFrame->GetWindow(GetWindowType::FirstChild);
-    aItem.mxSubMenuWin.reset(VclPtr<ScCheckListMenuWindow>::Create(pContainer, mpDoc, false, -1, mxFrame->GetMenuStackLevel()+1, mxFrame.get()));
+    aItem.mxSubMenuWin.reset(VclPtr<ScCheckListMenuWindow>::Create(pContainer, mpDoc, false,
+                                                                   false, -1, mxFrame.get()));
     maMenuItems.emplace_back(std::move(aItem));
 
     mxMenu->append_text(rText);
@@ -195,23 +192,12 @@ void ScCheckListMenuControl::executeMenuItem(size_t nPos)
     maMenuItems[nPos].mxAction->execute();
 }
 
-void ScCheckListMenuControl::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu)
+void ScCheckListMenuControl::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer)
 {
     if (mnSelectedMenu == nPos)
         // nothing to do.
         return;
 
-    if (bEnsureSubMenu)
-    {
-        // Dismiss any child popup menu windows.
-        if (mnSelectedMenu < maMenuItems.size() &&
-            maMenuItems[mnSelectedMenu].mxSubMenuWin &&
-            maMenuItems[mnSelectedMenu].mxSubMenuWin->IsVisible())
-        {
-            maMenuItems[mnSelectedMenu].mxSubMenuWin->get_widget().ensureSubMenuNotVisible();
-        }
-    }
-
     selectMenuItem(nPos, bSubMenuTimer);
 }
 
@@ -346,23 +332,19 @@ void ScCheckListMenuControl::selectMenuItem(size_t nPos, bool bSubMenuTimer)
         return;
     }
 
+    ScCheckListMenuWindow* pParentMenu = mxFrame->GetParentMenu();
+    if (pParentMenu)
+        pParentMenu->get_widget().setSubMenuFocused(this);
 
-    if (nPos != MENU_NOT_SELECTED)
+    if (bSubMenuTimer)
     {
-        ScCheckListMenuWindow* pParentMenu = mxFrame->GetParentMenu();
-        if (pParentMenu)
-            pParentMenu->get_widget().setSubMenuFocused(this);
-
-        if (bSubMenuTimer)
+        if (maMenuItems[nPos].mxSubMenuWin)
         {
-            if (maMenuItems[nPos].mxSubMenuWin)
-            {
-                ScCheckListMenuWindow* pSubMenu = maMenuItems[nPos].mxSubMenuWin.get();
-                queueLaunchSubMenu(nPos, pSubMenu);
-            }
-            else
-                queueCloseSubMenu();
+            ScCheckListMenuWindow* pSubMenu = maMenuItems[nPos].mxSubMenuWin.get();
+            queueLaunchSubMenu(nPos, pSubMenu);
         }
+        else
+            queueCloseSubMenu();
     }
 }
 
@@ -401,24 +383,12 @@ void ScCheckListMenuControl::EndPopupMode()
     mxFrame->EnableDocking(false);
 }
 
-void ScCheckListMenuControl::StartPopupMode(const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags)
+void ScCheckListMenuControl::StartPopupMode(const tools::Rectangle& rRect, FloatWinPopupFlags eFlags)
 {
     mxFrame->EnableDocking(true);
     DockingManager* pDockingManager = vcl::Window::GetDockingManager();
     pDockingManager->SetPopupModeEndHdl(mxFrame, LINK(this, ScCheckListMenuControl, PopupModeEndHdl));
-    pDockingManager->StartPopupMode(mxFrame, rRect, nPopupModeFlags);
-}
-
-void ScCheckListMenuControl::ensureSubMenuNotVisible()
-{
-    if (mnSelectedMenu < maMenuItems.size() &&
-        maMenuItems[mnSelectedMenu].mxSubMenuWin &&
-        maMenuItems[mnSelectedMenu].mxSubMenuWin->IsVisible())
-    {
-        maMenuItems[mnSelectedMenu].mxSubMenuWin->get_widget().ensureSubMenuNotVisible();
-    }
-
-    EndPopupMode();
+    pDockingManager->StartPopupMode(mxFrame, rRect, (eFlags | FloatWinPopupFlags::GrabFocus));
 }
 
 void ScCheckListMenuControl::terminateAllPopupMenus()
@@ -443,15 +413,17 @@ ScCheckListMember::ScCheckListMember()
 }
 
 ScCheckListMenuControl::ScCheckListMenuControl(ScCheckListMenuWindow* pParent, vcl::Window* pContainer,
-                                               ScDocument* pDoc, bool bCanHaveSubMenu, int nWidth)
+                                               ScDocument* pDoc, bool bCanHaveSubMenu,
+                                               bool bHasDates, int nWidth)
     : mxFrame(pParent)
-    , mxBuilder(Application::CreateInterimBuilder(pContainer, "modules/scalc/ui/filterdropdown.ui"))
+    , mxBuilder(Application::CreateInterimBuilder(pContainer, "modules/scalc/ui/filterdropdown.ui", false))
     , mxContainer(mxBuilder->weld_container("FilterDropDown"))
     , mxMenu(mxBuilder->weld_tree_view("menu"))
     , mxScratchIter(mxMenu->make_iterator())
     , mxEdSearch(mxBuilder->weld_entry("search_edit"))
     , mxBox(mxBuilder->weld_widget("box"))
-    , mxChecks(mxBuilder->weld_tree_view("check_list_box"))
+    , mxListChecks(mxBuilder->weld_tree_view("check_list_box"))
+    , mxTreeChecks(mxBuilder->weld_tree_view("check_tree_box"))
     , mxChkToggleAll(mxBuilder->weld_check_button("toggle_all"))
     , mxBtnSelectSingle(mxBuilder->weld_button("select_current"))
     , mxBtnUnselectSingle(mxBuilder->weld_button("unselect_current"))
@@ -459,33 +431,92 @@ ScCheckListMenuControl::ScCheckListMenuControl(ScCheckListMenuWindow* pParent, v
     , mxBtnOk(mxBuilder->weld_button("ok"))
     , mxBtnCancel(mxBuilder->weld_button("cancel"))
     , mxDropDown(mxMenu->create_virtual_device())
-    , mnWidthHint(nWidth)
-    , maWndSize()
+    , mnCheckWidthReq(-1)
+    , mnWndWidth(0)
     , mePrevToggleAllState(TRISTATE_INDET)
     , mnSelectedMenu(MENU_NOT_SELECTED)
     , mpDoc(pDoc)
     , mnAsyncPostPopdownId(nullptr)
-    , mbHasDates(false)
+    , mbHasDates(bHasDates)
     , mbCanHaveSubMenu(bCanHaveSubMenu)
     , maOpenTimer(this)
     , maCloseTimer(this)
 {
+    /*
+       tdf#136559 If we have no dates we don't need a tree
+       structure, just a list. GtkListStore can be then
+       used which is much faster than a GtkTreeStore, so
+       with no dates switch to the treeview which uses the
+       faster GtkListStore
+    */
+    if (mbHasDates)
+        mpChecks = mxTreeChecks.get();
+    else
+    {
+        mxTreeChecks->hide();
+        mxListChecks->show();
+        mpChecks = mxListChecks.get();
+    }
+
+    bool bIsSubMenu = pParent->GetParentMenu();
+
+    int nChecksHeight = mxTreeChecks->get_height_rows(9);
+    if (!bIsSubMenu && nWidth != -1)
+    {
+        mnCheckWidthReq = nWidth - mxFrame->get_border_width() * 2 - 4;
+        mxTreeChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+        mxListChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+    }
+
     // sort ok/cancel into native order, if this was a dialog they would be auto-sorted, but this
     // popup isn't a true dialog
     //mxButtonBox->sort_native_button_order();
 
-    //mxChecks->enable_toggle_buttons(weld::ColumnToggleType::Check);
+    if (!bIsSubMenu)
+    {
+        mxTreeChecks->enable_toggle_buttons(weld::ColumnToggleType::Check);
+        mxListChecks->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+        mxBox->show();
+        mxEdSearch->show();
+        mxButtonBox->show();
+    }
 
     mxContainer->connect_focus_in(LINK(this, ScCheckListMenuControl, FocusHdl));
     mxMenu->connect_row_activated(LINK(this, ScCheckListMenuControl, RowActivatedHdl));
     mxMenu->connect_changed(LINK(this, ScCheckListMenuControl, SelectHdl));
     mxMenu->connect_key_press(LINK(this, ScCheckListMenuControl, MenuKeyInputHdl));
 
+    if (!bIsSubMenu)
+    {
+        mxBtnOk->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+        mxBtnCancel->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+        mxEdSearch->connect_changed(LINK(this, ScCheckListMenuControl, EdModifyHdl));
+        mxEdSearch->connect_activate(LINK(this, ScCheckListMenuControl, EdActivateHdl));
+        mxTreeChecks->connect_toggled(LINK(this, ScCheckListMenuControl, CheckHdl));
+        mxTreeChecks->connect_key_press(LINK(this, ScCheckListMenuControl, KeyInputHdl));
+        mxListChecks->connect_toggled(LINK(this, ScCheckListMenuControl, CheckHdl));
+        mxListChecks->connect_key_press(LINK(this, ScCheckListMenuControl, KeyInputHdl));
+        mxChkToggleAll->connect_toggled(LINK(this, ScCheckListMenuControl, TriStateHdl));
+        mxBtnSelectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+        mxBtnUnselectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+    }
+
     if (mbCanHaveSubMenu)
     {
         CreateDropDown();
         mxMenu->connect_size_allocate(LINK(this, ScCheckListMenuControl, TreeSizeAllocHdl));
     }
+
+    if (!bIsSubMenu)
+    {
+        // determine what width the checklist will end up with
+        mnCheckWidthReq = mxContainer->get_preferred_size().Width();
+        // make that size fixed now, we can now use mnCheckWidthReq to speed up
+        // bulk_insert_for_each
+        mxTreeChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+        mxListChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+    }
 }
 
 IMPL_LINK_NOARG(ScCheckListMenuControl, FocusHdl, weld::Widget&, void)
@@ -517,13 +548,13 @@ ScCheckListMenuControl::~ScCheckListMenuControl()
 }
 
 ScCheckListMenuWindow::ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, bool bCanHaveSubMenu,
-                                             int nWidth, sal_uInt16 nMenuStackLevel, ScCheckListMenuWindow* pParentMenu)
+                                             bool bTreeMode, int nWidth, ScCheckListMenuWindow* pParentMenu)
     : DockingWindow(pParent, "InterimDockParent", "svx/ui/interimdockparent.ui")
     , mxParentMenu(pParentMenu)
     , mxBox(get<vcl::Window>("box"))
-    , mxControl(new ScCheckListMenuControl(this, mxBox.get(), pDoc, bCanHaveSubMenu, nWidth))
-    , mnMenuStackLevel(nMenuStackLevel)
 {
+    setDeferredProperties();
+    mxControl.reset(new ScCheckListMenuControl(this, mxBox.get(), pDoc, bCanHaveSubMenu, bTreeMode, nWidth));
     SetBackground(Application::GetSettings().GetStyleSettings().GetMenuColor());
     set_id("check_list_menu");
 }
@@ -560,39 +591,22 @@ void ScCheckListMenuWindow::GetFocus()
     mxControl->GrabFocus();
 }
 
-void ScCheckListMenuControl::packWindow()
+void ScCheckListMenuControl::prepWindow()
 {
-    mxBox->show();
-    mxEdSearch->show();
-    mxButtonBox->show();
-
-    mxBtnOk->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
-    mxBtnCancel->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
-    mxEdSearch->connect_changed(LINK(this, ScCheckListMenuControl, EdModifyHdl));
-    mxEdSearch->connect_activate(LINK(this, ScCheckListMenuControl, EdActivateHdl));
-    //mxChecks->connect_toggled(LINK(this, ScCheckListMenuControl, CheckHdl));
-    mxChecks->connect_key_press(LINK(this, ScCheckListMenuControl, KeyInputHdl));
-    mxChkToggleAll->connect_toggled(LINK(this, ScCheckListMenuControl, TriStateHdl));
-    mxBtnSelectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
-    mxBtnUnselectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
-
-    mxChecks->set_size_request(-1, mxChecks->get_height_rows(9));
     mxMenu->set_size_request(-1, mxMenu->get_preferred_size().Height() + 2);
     mnSelectedMenu = 0;
     mxMenu->set_cursor(mnSelectedMenu);
     mxMenu->unselect_all();
 
-    maWndSize = mxContainer->get_preferred_size();
-    if (maWndSize.Width() < mnWidthHint)
-    {
-        mxContainer->set_size_request(mnWidthHint, -1);
-        maWndSize.setWidth(mnWidthHint);
-    }
+    mnWndWidth = mxContainer->get_preferred_size().Width() + mxFrame->get_border_width() * 2 + 4;
 }
 
 void ScCheckListMenuControl::setAllMemberState(bool bSet)
 {
-    CheckAllChildren(nullptr, bSet);
+    mpChecks->all_foreach([this, bSet](weld::TreeIter& rEntry){
+        mpChecks->set_toggle(rEntry, bSet ? TRISTATE_TRUE : TRISTATE_FALSE);
+        return false;
+    });
 
     if (!maConfig.mbAllowEmptySet)
     {
@@ -604,10 +618,10 @@ void ScCheckListMenuControl::setAllMemberState(bool bSet)
 void ScCheckListMenuControl::selectCurrentMemberOnly(bool bSet)
 {
     setAllMemberState(!bSet);
-    std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator();
-    if (!mxChecks->get_cursor(xEntry.get()))
+    std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+    if (!mpChecks->get_cursor(xEntry.get()))
         return;
-    //mxChecks->set_toggle(*xEntry, bSet ? TRISTATE_TRUE : TRISTATE_FALSE);
+    mpChecks->set_toggle(*xEntry, bSet ? TRISTATE_TRUE : TRISTATE_FALSE);
 }
 
 IMPL_LINK(ScCheckListMenuControl, ButtonHdl, weld::Button&, rBtn, void)
@@ -619,8 +633,8 @@ IMPL_LINK(ScCheckListMenuControl, ButtonHdl, weld::Button&, rBtn, void)
     else if (&rBtn == mxBtnSelectSingle.get() || &rBtn == mxBtnUnselectSingle.get())
     {
         selectCurrentMemberOnly(&rBtn == mxBtnSelectSingle.get());
-        std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator();
-        if (!mxChecks->get_cursor(xEntry.get()))
+        std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+        if (!mpChecks->get_cursor(xEntry.get()))
             xEntry.reset();
         Check(xEntry.get());
     }
@@ -657,12 +671,12 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
     size_t nSelCount = 0;
     bool bSomeDateDeletes = false;
 
-    mxChecks->freeze();
+    mpChecks->freeze();
 
-    if (bSearchTextEmpty)
+    if (bSearchTextEmpty && !mbHasDates)
     {
         // when there are a lot of rows, it is cheaper to simply clear the tree and re-initialise
-        mxChecks->clear();
+        mpChecks->clear();
         nSelCount = initMembers();
     }
     else
@@ -725,7 +739,7 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
         }
     }
 
-    mxChecks->thaw();
+    mpChecks->thaw();
 
     if ( nSelCount == n )
         mxChkToggleAll->set_state( TRISTATE_TRUE );
@@ -737,7 +751,7 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
     if ( !maConfig.mbAllowEmptySet )
     {
         const bool bEmptySet( nSelCount == 0 );
-        mxChecks->set_sensitive(!bEmptySet);
+        mpChecks->set_sensitive(!bEmptySet);
         mxChkToggleAll->set_sensitive(!bEmptySet);
         mxBtnSelectSingle->set_sensitive(!bEmptySet);
         mxBtnUnselectSingle->set_sensitive(!bEmptySet);
@@ -752,15 +766,15 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdActivateHdl, weld::Entry&, bool)
     return true;
 }
 
-// IMPL_LINK( ScCheckListMenuControl, CheckHdl, const weld::TreeView::iter_col&, rRowCol, void )
-// {
-//     Check(&rRowCol.first);
-// }
+IMPL_LINK( ScCheckListMenuControl, CheckHdl, const weld::TreeView::iter_col&, rRowCol, void )
+{
+    Check(&rRowCol.first);
+}
 
 void ScCheckListMenuControl::Check(const weld::TreeIter* pEntry)
 {
     if (pEntry)
-        CheckEntry(pEntry,  mxChecks->get_toggle(*pEntry) == TRISTATE_TRUE);
+        CheckEntry(*pEntry, mpChecks->get_toggle(*pEntry) == TRISTATE_TRUE);
     size_t nNumChecked = GetCheckedEntryCount();
     if (nNumChecked == maMembers.size())
         // all members visible
@@ -790,13 +804,13 @@ void ScCheckListMenuControl::updateMemberParents(const weld::TreeIter* pLeaf, si
     if ( pLeaf )
     {
         std::unique_ptr<weld::TreeIter> xYearEntry;
-        std::unique_ptr<weld::TreeIter> xMonthEntry = mxChecks->make_iterator(pLeaf);
-        if (!mxChecks->iter_parent(*xMonthEntry))
+        std::unique_ptr<weld::TreeIter> xMonthEntry = mpChecks->make_iterator(pLeaf);
+        if (!mpChecks->iter_parent(*xMonthEntry))
             xMonthEntry.reset();
         else
         {
-            xYearEntry = mxChecks->make_iterator(xMonthEntry.get());
-            if (!mxChecks->iter_parent(*xYearEntry))
+            xYearEntry = mpChecks->make_iterator(xMonthEntry.get());
+            if (!mpChecks->iter_parent(*xYearEntry))
                 xYearEntry.reset();
         }
 
@@ -851,15 +865,15 @@ void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal,
     if ( aDayName.getLength() == 1 )
         aDayName = "0" + aDayName;
 
-    mxChecks->freeze();
+    mpChecks->freeze();
 
     std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, aYearName);
     if (!xYearEntry)
     {
-        xYearEntry = mxChecks->make_iterator();
-        mxChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get());
-        mxChecks->set_toggle(*xYearEntry, TRISTATE_FALSE);
-        mxChecks->set_text(*xYearEntry, aYearName, 0);
+        xYearEntry = mpChecks->make_iterator();
+        mpChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get());
+        mpChecks->set_toggle(*xYearEntry, TRISTATE_FALSE);
+        mpChecks->set_text(*xYearEntry, aYearName, 0);
         ScCheckListMember aMemYear;
         aMemYear.maName = aYearName;
         aMemYear.maRealName = rsName;
@@ -874,10 +888,10 @@ void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal,
     std::unique_ptr<weld::TreeIter> xMonthEntry = FindEntry(xYearEntry.get(), aMonthName);
     if (!xMonthEntry)
     {
-        xMonthEntry = mxChecks->make_iterator();
-        mxChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get());
-        mxChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE);
-        mxChecks->set_text(*xMonthEntry, aMonthName, 0);
+        xMonthEntry = mpChecks->make_iterator();
+        mpChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get());
+        mpChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE);
+        mpChecks->set_text(*xMonthEntry, aMonthName, 0);
         ScCheckListMember aMemMonth;
         aMemMonth.maName = aMonthName;
         aMemMonth.maRealName = rsName;
@@ -893,10 +907,10 @@ void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal,
     std::unique_ptr<weld::TreeIter> xDayEntry = FindEntry(xMonthEntry.get(), aDayName);
     if (!xDayEntry)
     {
-        xDayEntry = mxChecks->make_iterator();
-        mxChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get());
-        mxChecks->set_toggle(*xDayEntry, TRISTATE_FALSE);
-        mxChecks->set_text(*xDayEntry, aDayName, 0);
+        xDayEntry = mpChecks->make_iterator();
+        mpChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get());
+        mpChecks->set_toggle(*xDayEntry, TRISTATE_FALSE);
+        mpChecks->set_text(*xDayEntry, aDayName, 0);
         ScCheckListMember aMemDay;
         aMemDay.maName = aDayName;
         aMemDay.maRealName = rsName;
@@ -911,7 +925,7 @@ void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal,
         maMembers.emplace_back(std::move(aMemDay));
     }
 
-    mxChecks->thaw();
+    mpChecks->thaw();
 }
 
 void ScCheckListMenuControl::addMember(const OUString& rName, bool bVisible)
@@ -927,13 +941,13 @@ void ScCheckListMenuControl::addMember(const OUString& rName, bool bVisible)
 
 std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::FindEntry(const weld::TreeIter* pParent, const OUString& sNode)
 {
-    std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(pParent);
-    bool bEntry = pParent ? mxChecks->iter_children(*xEntry) : mxChecks->get_iter_first(*xEntry);
+    std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator(pParent);
+    bool bEntry = pParent ? mpChecks->iter_children(*xEntry) : mpChecks->get_iter_first(*xEntry);
     while (bEntry)
     {
-        if (sNode == mxChecks->get_text(*xEntry, 0))
+        if (sNode == mpChecks->get_text(*xEntry, 0))
             return xEntry;
-        bEntry = mxChecks->iter_next_sibling(*xEntry);
+        bEntry = mpChecks->iter_next_sibling(*xEntry);
     }
     return nullptr;
 }
@@ -941,50 +955,50 @@ std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::FindEntry(const weld::Tr
 void ScCheckListMenuControl::GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set<OUString>& vOut,
                                                  OUString& rLabel)
 {
-    if (mxChecks->get_toggle(*pEntry) == TRISTATE_TRUE)
-    {
-        // We have to hash parents and children together.
-        // Per convention for easy access in getResult()
-        // "child;parent;grandparent" while descending.
-        if (rLabel.isEmpty())
-            rLabel = mxChecks->get_text(*pEntry, 0);
-        else
-            rLabel = mxChecks->get_text(*pEntry, 0) + ";" + rLabel;
+    if (mpChecks->get_toggle(*pEntry) != TRISTATE_TRUE)
+        return;
 
-        // Prerequisite: the selection mechanism guarantees that if a child is
-        // selected then also the parent is selected, so we only have to
-        // inspect the children in case the parent is selected.
-        if (mxChecks->iter_has_child(*pEntry))
-        {
-            std::unique_ptr<weld::TreeIter> xChild(mxChecks->make_iterator(pEntry));
-            bool bChild = mxChecks->iter_children(*xChild);
-            while (bChild)
-            {
-                OUString aLabel = rLabel;
-                GetRecursiveChecked(xChild.get(), vOut, aLabel);
-                if (!aLabel.isEmpty() && aLabel != rLabel)
-                    vOut.insert(aLabel);
-                bChild = mxChecks->iter_next_sibling(*xChild);
-            }
-            // Let the caller not add the parent alone.
-            rLabel.clear();
-        }
+    // We have to hash parents and children together.
+    // Per convention for easy access in getResult()
+    // "child;parent;grandparent" while descending.
+    if (rLabel.isEmpty())
+        rLabel = mpChecks->get_text(*pEntry, 0);
+    else
+        rLabel = mpChecks->get_text(*pEntry, 0) + ";" + rLabel;
+
+    // Prerequisite: the selection mechanism guarantees that if a child is
+    // selected then also the parent is selected, so we only have to
+    // inspect the children in case the parent is selected.
+    if (!mpChecks->iter_has_child(*pEntry))
+        return;
+
+    std::unique_ptr<weld::TreeIter> xChild(mpChecks->make_iterator(pEntry));
+    bool bChild = mpChecks->iter_children(*xChild);
+    while (bChild)
+    {
+        OUString aLabel = rLabel;
+        GetRecursiveChecked(xChild.get(), vOut, aLabel);
+        if (!aLabel.isEmpty() && aLabel != rLabel)
+            vOut.insert(aLabel);
+        bChild = mpChecks->iter_next_sibling(*xChild);
     }
+    // Let the caller not add the parent alone.
+    rLabel.clear();
 }
 
 std::unordered_set<OUString> ScCheckListMenuControl::GetAllChecked()
 {
     std::unordered_set<OUString> vResults(0);
 
-    std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator();
-    bool bEntry = mxChecks->get_iter_first(*xEntry);
+    std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+    bool bEntry = mpChecks->get_iter_first(*xEntry);
     while (bEntry)
     {
         OUString aLabel;
         GetRecursiveChecked(xEntry.get(), vResults, aLabel);
         if (!aLabel.isEmpty())
             vResults.insert(aLabel);
-        bEntry = mxChecks->iter_next_sibling(*xEntry);
+        bEntry = mpChecks->iter_next_sibling(*xEntry);
     }
 
     return vResults;
@@ -993,61 +1007,60 @@ std::unordered_set<OUString> ScCheckListMenuControl::GetAllChecked()
 bool ScCheckListMenuControl::IsChecked(const OUString& sName, const weld::TreeIter* pParent)
 {
     std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pParent, sName);
-    return xEntry && mxChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
+    return xEntry && mpChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
 }
 
 void ScCheckListMenuControl::CheckEntry(const OUString& sName, const weld::TreeIter* pParent, bool bCheck)
 {
     std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pParent, sName);
     if (xEntry)
-        CheckEntry(xEntry.get(), bCheck);
+        CheckEntry(*xEntry, bCheck);
 }
 
-// Recursively check all children of pParent
-void ScCheckListMenuControl::CheckAllChildren(const weld::TreeIter* pParent, bool bCheck)
+// Recursively check all children of rParent
+void ScCheckListMenuControl::CheckAllChildren(const weld::TreeIter& rParent, bool bCheck)
 {
-    if (pParent)
-        mxChecks->set_toggle(*pParent, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
-    std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(pParent);
-    bool bEntry = pParent ? mxChecks->iter_children(*xEntry) : mxChecks->get_iter_first(*xEntry);
+    mpChecks->set_toggle(rParent, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
+    std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator(&rParent);
+    bool bEntry = mpChecks->iter_children(*xEntry);
     while (bEntry)
     {
-        CheckAllChildren(xEntry.get(), bCheck);
-        bEntry = mxChecks->iter_next_sibling(*xEntry);
+        CheckAllChildren(*xEntry, bCheck);
+        bEntry = mpChecks->iter_next_sibling(*xEntry);
     }
 }
 
-void ScCheckListMenuControl::CheckEntry(const weld::TreeIter* pParent, bool bCheck)
+void ScCheckListMenuControl::CheckEntry(const weld::TreeIter& rParent, bool bCheck)
 {
-    // recursively check all items below pParent
-    CheckAllChildren(pParent, bCheck);
-    // checking pParent can affect ancestors, e.g. if ancestor is unchecked and pParent is
+    // recursively check all items below rParent
+    CheckAllChildren(rParent, bCheck);
+    // checking rParent can affect ancestors, e.g. if ancestor is unchecked and rParent is
     // now checked then the ancestor needs to be checked also
-    if (pParent && mxChecks->get_iter_depth(*pParent))
+    if (!mpChecks->get_iter_depth(rParent))
+        return;
+
+    std::unique_ptr<weld::TreeIter> xAncestor(mpChecks->make_iterator(&rParent));
+    bool bAncestor = mpChecks->iter_parent(*xAncestor);
+    while (bAncestor)
     {
-        std::unique_ptr<weld::TreeIter> xAncestor(mxChecks->make_iterator(pParent));
-        bool bAncestor = mxChecks->iter_parent(*xAncestor);
-        while (bAncestor)
+        // if any first level children checked then ancestor
+        // needs to be checked, similarly if no first level children
+        // checked then ancestor needs to be unchecked
+        std::unique_ptr<weld::TreeIter> xChild(mpChecks->make_iterator(xAncestor.get()));
+        bool bChild = mpChecks->iter_children(*xChild);
+        bool bChildChecked = false;
+
+        while (bChild)
         {
-            // if any first level children checked then ancestor
-            // needs to be checked, similarly if no first level children
-            // checked then ancestor needs to be unchecked
-            std::unique_ptr<weld::TreeIter> xChild(mxChecks->make_iterator(xAncestor.get()));
-            bool bChild = mxChecks->iter_children(*xChild);
-            bool bChildChecked = false;
-
-            while (bChild)
+            if (mpChecks->get_toggle(*xChild) == TRISTATE_TRUE)
             {
-                if (mxChecks->get_toggle(*xChild) == TRISTATE_TRUE)
-                {
-                    bChildChecked = true;
-                    break;
-                }
-                bChild = mxChecks->iter_next_sibling(*xChild);
+                bChildChecked = true;
+                break;
             }
-            mxChecks->set_toggle(*xAncestor, bChildChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
-            bAncestor = mxChecks->iter_parent(*xAncestor);
+            bChild = mpChecks->iter_next_sibling(*xChild);
         }
+        mpChecks->set_toggle(*xAncestor, bChildChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
+        bAncestor = mpChecks->iter_parent(*xAncestor);
     }
 }
 
@@ -1069,50 +1082,50 @@ std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::ShowCheckEntry(const OUS
                 std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, rMember.maDateParts[0]);
                 if (!xYearEntry)
                 {
-                    xYearEntry = mxChecks->make_iterator();
-                    mxChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get());
-                    mxChecks->set_toggle(*xYearEntry, TRISTATE_FALSE);
-                    mxChecks->set_text(*xYearEntry, rMember.maDateParts[0], 0);
+                    xYearEntry = mpChecks->make_iterator();
+                    mpChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get());
+                    mpChecks->set_toggle(*xYearEntry, TRISTATE_FALSE);
+                    mpChecks->set_text(*xYearEntry, rMember.maDateParts[0], 0);
                 }
                 std::unique_ptr<weld::TreeIter> xMonthEntry = FindEntry(xYearEntry.get(), rMember.maDateParts[1]);
                 if (!xMonthEntry)
                 {
-                    xMonthEntry = mxChecks->make_iterator();
-                    mxChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get());
-                    mxChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE);
-                    mxChecks->set_text(*xMonthEntry, rMember.maDateParts[1], 0);
+                    xMonthEntry = mpChecks->make_iterator();
+                    mpChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get());
+                    mpChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE);
+                    mpChecks->set_text(*xMonthEntry, rMember.maDateParts[1], 0);
                 }
                 std::unique_ptr<weld::TreeIter> xDayEntry = FindEntry(xMonthEntry.get(), rMember.maName);
                 if (!xDayEntry)
                 {
-                    xDayEntry = mxChecks->make_iterator();
-                    mxChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get());
-                    mxChecks->set_toggle(*xDayEntry, TRISTATE_FALSE);
-                    mxChecks->set_text(*xDayEntry, rMember.maName, 0);
+                    xDayEntry = mpChecks->make_iterator();
+                    mpChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get());
+                    mpChecks->set_toggle(*xDayEntry, TRISTATE_FALSE);
+                    mpChecks->set_text(*xDayEntry, rMember.maName, 0);
                 }
                 return xDayEntry; // Return leaf node
             }
 
-            xEntry = mxChecks->make_iterator();
-            mxChecks->append(xEntry.get());
-            mxChecks->set_toggle(*xEntry, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
-            mxChecks->set_text(*xEntry, sName, 0);
+            xEntry = mpChecks->make_iterator();
+            mpChecks->append(xEntry.get());
+            mpChecks->set_toggle(*xEntry, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
+            mpChecks->set_text(*xEntry, sName, 0);
         }
         else
-            CheckEntry(xEntry.get(), bCheck);
+            CheckEntry(*xEntry, bCheck);
     }
     else if (xEntry)
     {
-        mxChecks->remove(*xEntry);
+        mpChecks->remove(*xEntry);
         if (rMember.mxParent)
         {
-            std::unique_ptr<weld::TreeIter> xParent(mxChecks->make_iterator(rMember.mxParent.get()));
-            while (xParent && !mxChecks->iter_has_child(*xParent))
+            std::unique_ptr<weld::TreeIter> xParent(mpChecks->make_iterator(rMember.mxParent.get()));
+            while (xParent && !mpChecks->iter_has_child(*xParent))
             {
-                std::unique_ptr<weld::TreeIter> xTmp(mxChecks->make_iterator(xParent.get()));
-                if (!mxChecks->iter_parent(*xParent))
+                std::unique_ptr<weld::TreeIter> xTmp(mpChecks->make_iterator(xParent.get()));
+                if (!mpChecks->iter_parent(*xParent))
                     xParent.reset();
-                mxChecks->remove(*xTmp);
+                mpChecks->remove(*xTmp);
             }
         }
     }
@@ -1123,8 +1136,8 @@ int ScCheckListMenuControl::GetCheckedEntryCount() const
 {
     int nRet = 0;
 
-    mxChecks->all_foreach([this, &nRet](weld::TreeIter& rEntry){
-        if (mxChecks->get_toggle(rEntry) == TRISTATE_TRUE)
+    mpChecks->all_foreach([this, &nRet](weld::TreeIter& rEntry){
+        if (mpChecks->get_toggle(rEntry) == TRISTATE_TRUE)
             ++nRet;
         return false;
     });
@@ -1138,13 +1151,13 @@ IMPL_LINK(ScCheckListMenuControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
 
     if ( rKey.GetCode() == KEY_RETURN || rKey.GetCode() == KEY_SPACE )
     {
-        std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator();
-        bool bEntry = mxChecks->get_cursor(xEntry.get());
+        std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+        bool bEntry = mpChecks->get_cursor(xEntry.get());
         if (bEntry)
         {
-            bool bOldCheck = mxChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
-            CheckEntry(xEntry.get(), !bOldCheck);
-            bool bNewCheck = mxChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
+            bool bOldCheck = mpChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
+            CheckEntry(*xEntry, !bOldCheck);
+            bool bNewCheck = mpChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
             if (bOldCheck != bNewCheck)
                 Check(xEntry.get());
         }
@@ -1154,49 +1167,75 @@ IMPL_LINK(ScCheckListMenuControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
     return false;
 }
 
-void ScCheckListMenuControl::setHasDates(bool bHasDates)
+namespace
 {
-    mbHasDates = bHasDates;
-    mxChecks->set_show_expanders(mbHasDates);
+    void insertMember(weld::TreeView& rView, const weld::TreeIter& rIter, const ScCheckListMember& rMember)
+    {
+        OUString aLabel = rMember.maName;
+        if (aLabel.isEmpty())
+            aLabel = ScResId(STR_EMPTYDATA);
+        rView.set_toggle(rIter, rMember.mbVisible ? TRISTATE_TRUE : TRISTATE_FALSE);
+        rView.set_text(rIter, aLabel, 0);
+    }
 }
 
-size_t ScCheckListMenuControl::initMembers()
+size_t ScCheckListMenuControl::initMembers(int nMaxMemberWidth)
 {
     size_t n = maMembers.size();
     size_t nVisMemCount = 0;
 
-    mxChecks->freeze();
+    if (nMaxMemberWidth == -1)
+        nMaxMemberWidth = mnCheckWidthReq;
 
-    std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator();
-    std::vector<std::unique_ptr<weld::TreeIter>> aExpandRows;
-
-    for (size_t i = 0; i < n; ++i)
+    if (!mpChecks->n_children() && !mbHasDates)
+    {
+        std::vector<int> aFixedWidths { nMaxMemberWidth };
+        // tdf#134038 insert in the fastest order, this might be backwards so only do it for
+        // the !mbHasDates case where no entry depends on another to exist before getting
+        // inserted. We cannot retain pre-existing treeview content, only clear and fill it.
+        mpChecks->bulk_insert_for_each(n, [this, &nVisMemCount](weld::TreeIter& rIter, int i) {
+            assert(!maMembers[i].mbDate);
+            insertMember(*mpChecks, rIter, maMembers[i]);
+            if (maMembers[i].mbVisible)
+                ++nVisMemCount;
+        }, &aFixedWidths);
+    }
+    else
     {
-        if (maMembers[i].mbDate)
+        mpChecks->freeze();
+
+        std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+        std::vector<std::unique_ptr<weld::TreeIter>> aExpandRows;
+
+        for (size_t i = 0; i < n; ++i)
         {
-            CheckEntry(maMembers[i].maName, maMembers[i].mxParent.get(), maMembers[i].mbVisible);
-            // Expand first node of checked dates
-            if (!maMembers[i].mxParent && IsChecked(maMembers[i].maName,  maMembers[i].mxParent.get()))
+            if (maMembers[i].mbDate)
             {
-                std::unique_ptr<weld::TreeIter> xDateEntry = FindEntry(nullptr, maMembers[i].maName);
-                if (xDateEntry)
-                    aExpandRows.emplace_back(std::move(xDateEntry));
+                CheckEntry(maMembers[i].maName, maMembers[i].mxParent.get(), maMembers[i].mbVisible);
+                // Expand first node of checked dates
+                if (!maMembers[i].mxParent && IsChecked(maMembers[i].maName, maMembers[i].mxParent.get()))
+                {
+                    std::unique_ptr<weld::TreeIter> xDateEntry = FindEntry(nullptr, maMembers[i].maName);
+                    if (xDateEntry)
+                        aExpandRows.emplace_back(std::move(xDateEntry));
+                }
+            }
+            else
+            {
+                mpChecks->append(xEntry.get());
+                insertMember(*mpChecks, *xEntry, maMembers[i]);
             }
-        }
-        else
-        {
-            OUString aLabel = maMembers[i].maName;
-            if (aLabel.isEmpty())
-                aLabel = ScResId(STR_EMPTYDATA);
 
-            mxChecks->append(xEntry.get());
-            mxChecks->set_toggle(*xEntry, maMembers[i].mbVisible ? TRISTATE_TRUE : TRISTATE_FALSE);
-            mxChecks->set_text(*xEntry, aLabel, 0);
+            if (maMembers[i].mbVisible)
+                ++nVisMemCount;
         }
 
-        if (maMembers[i].mbVisible)
-            ++nVisMemCount;
+        mpChecks->thaw();
+
+        for (auto& rRow : aExpandRows)
+            mpChecks->expand_row(*rRow);
     }
+
     if (nVisMemCount == n)
     {
         // all members visible
@@ -1215,13 +1254,8 @@ size_t ScCheckListMenuControl::initMembers()
         mePrevToggleAllState = TRISTATE_INDET;
     }
 
-    mxChecks->thaw();
-
-    for (auto& rRow : aExpandRows)
-        mxChecks->expand_row(*rRow);
-
     if (nVisMemCount)
-        mxChecks->select(0);
+        mpChecks->select(0);
 
     return nVisMemCount;
 }
@@ -1254,12 +1288,12 @@ void ScCheckListMenuControl::getResult(ResultType& rResult)
             // Checked labels are in the form "child;parent;grandparent".
             if (maMembers[i].mxParent)
             {
-                std::unique_ptr<weld::TreeIter> xIter(mxChecks->make_iterator(maMembers[i].mxParent.get()));
+                std::unique_ptr<weld::TreeIter> xIter(mpChecks->make_iterator(maMembers[i].mxParent.get()));
                 do
                 {
-                    aLabel.append(";").append(mxChecks->get_text(*xIter));
+                    aLabel.append(";").append(mpChecks->get_text(*xIter));
                 }
-                while (mxChecks->iter_parent(*xIter));
+                while (mpChecks->iter_parent(*xIter));
             }
 
             bool bState = vCheckeds.find(aLabel.makeStringAndClear()) != vCheckeds.end();
@@ -1279,7 +1313,7 @@ void ScCheckListMenuControl::getResult(ResultType& rResult)
 
 void ScCheckListMenuControl::launch(const tools::Rectangle& rRect)
 {
-    packWindow();
+    prepWindow();
     if (!maConfig.mbAllowEmptySet)
         // We need to have at least one member selected.
         mxBtnOk->set_sensitive(GetCheckedEntryCount() != 0);
@@ -1291,16 +1325,16 @@ void ScCheckListMenuControl::launch(const tools::Rectangle& rRect)
         long nLeft = aRect.Left() - aRect.GetWidth();
         aRect.SetLeft( nLeft );
     }
-    else if (maWndSize.Width() < aRect.GetWidth())
+    else if (mnWndWidth < aRect.GetWidth())
     {
         // Target rectangle (i.e. cell width) is wider than the window.
         // Simulate right-aligned launch by modifying the target rectangle
         // size.
-        long nDiff = aRect.GetWidth() - maWndSize.Width();
+        long nDiff = aRect.GetWidth() - mnWndWidth;
         aRect.AdjustLeft(nDiff );
     }
 
-    StartPopupMode(aRect, (FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus));
+    StartPopupMode(aRect, FloatWinPopupFlags::Down);
 }
 
 void ScCheckListMenuControl::close(bool bOK)
@@ -1337,4 +1371,22 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, PopupModeEndHdl, FloatingWindow*, void)
         mxPopupEndAction->execute();
 }
 
+int ScCheckListMenuControl::GetTextWidth(const OUString& rsName) const
+{
+    return mxDropDown->GetTextWidth(rsName);
+}
+
+int ScCheckListMenuControl::IncreaseWindowWidthToFitText(int nMaxTextWidth)
+{
+    int nBorder = mxFrame->get_border_width() * 2 + 4;
+    int nNewWidth = nMaxTextWidth - nBorder;
+    if (nNewWidth > mnCheckWidthReq)
+    {
+        mnCheckWidthReq = nNewWidth;
+        int nChecksHeight = mpChecks->get_height_rows(9);
+        mpChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+    }
+    return mnCheckWidthReq + nBorder;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx
index 3b589bf36850..eb5c418a3cad 100644
--- a/sc/source/ui/inc/checklistmenu.hxx
+++ b/sc/source/ui/inc/checklistmenu.hxx
@@ -88,10 +88,7 @@ public:
 
     struct MenuItemData
     {
-        OUString maText;
         bool     mbEnabled:1;
-        bool     mbSeparator:1;
-
         std::shared_ptr<Action> mxAction;
         VclPtr<ScCheckListMenuWindow> mxSubMenuWin;
 
@@ -118,8 +115,8 @@ public:
         Config();
     };
 
-    explicit ScCheckListMenuControl(ScCheckListMenuWindow* pParent, vcl::Window* pContainer, ScDocument* pDoc,
-                                    bool bCanHaveSubMenu, int nWidth);
+    ScCheckListMenuControl(ScCheckListMenuWindow* pParent, vcl::Window* pContainer, ScDocument* pDoc,
+                           bool bCanHaveSubMenu, bool bTreeMode, int nWidth);
     ~ScCheckListMenuControl();
 
     void addMenuItem(const OUString& rText, Action* pAction);
@@ -133,7 +130,7 @@ public:
     void setMemberSize(size_t n);
     void addDateMember(const OUString& rName, double nVal, bool bVisible);
     void addMember(const OUString& rName, bool bVisible);
-    size_t initMembers();
+    size_t initMembers(int nMaxMemberWidth = -1);
     void setConfig(const Config& rConfig);
 
     bool isAllSelected() const;
@@ -141,7 +138,7 @@ public:
     void launch(const tools::Rectangle& rRect);
     void close(bool bOK);
 
-    void StartPopupMode(const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags);
+    void StartPopupMode(const tools::Rectangle& rRect, FloatWinPopupFlags eFlags);
     void EndPopupMode();
 
     size_t getSubMenuPos(const ScCheckListMenuControl* pSubMenu);
@@ -166,45 +163,31 @@ public:
     void setOKAction(Action* p);
     void setPopupEndAction(Action* p);
 
-    void setHasDates(bool bHasDates);
+    int GetTextWidth(const OUString& rsName) const;
+    int IncreaseWindowWidthToFitText(int nMaxTextWidth);
 
 private:
 
     std::vector<MenuItemData>         maMenuItems;
 
-    enum SectionType {
-        WHOLE,                // entire window
-        LISTBOX_AREA_OUTER,   // box enclosing the check box items.
-        LISTBOX_AREA_INNER,   // box enclosing the check box items.
-        SINGLE_BTN_AREA,      // box enclosing the single-action buttons.
-        CHECK_TOGGLE_ALL,     // check box for toggling all items.
-        BTN_SINGLE_SELECT,
-        BTN_SINGLE_UNSELECT,
-        BTN_OK,               // OK button
-        BTN_CANCEL,           // Cancel button
-        EDIT_SEARCH,          // Search box
-    };
-    void getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const;
-
     /**
-     * Calculate the appropriate window size, the position and size of each
-     * control based on the menu items.
+     * Calculate the appropriate window size based on the menu items.
      */
-    void packWindow();
+    void prepWindow();
     void setAllMemberState(bool bSet);
     void selectCurrentMemberOnly(bool bSet);
     void updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx);
 
     std::unique_ptr<weld::TreeIter> ShowCheckEntry(const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true);
     void CheckEntry(const OUString& sName, const weld::TreeIter* pParent, bool bCheck);
-    void CheckEntry(const weld::TreeIter* pEntry, bool bCheck);
+    void CheckEntry(const weld::TreeIter& rEntry, bool bCheck);
     void GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set<OUString>& vOut, OUString& rLabel);
     std::unordered_set<OUString> GetAllChecked();
     bool IsChecked(const OUString& sName, const weld::TreeIter* pParent);
     int GetCheckedEntryCount() const;
-    void CheckAllChildren(const weld::TreeIter* pEntry, bool bCheck);
+    void CheckAllChildren(const weld::TreeIter& rEntry, bool bCheck);
 
-    void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu);
+    void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer);
 
     std::unique_ptr<weld::TreeIter> FindEntry(const weld::TreeIter* pParent, const OUString& sNode);
 
@@ -216,12 +199,6 @@ private:
      */
     void terminateAllPopupMenus();
 
-    /**
-     * Dismiss any visible child submenus when a menu item of a parent menu is
-     * selected.
-     */
-    void ensureSubMenuNotVisible();
-
     void endSubMenu(ScCheckListMenuControl& rSubMenu);
 
     struct SubMenuItemData;
@@ -237,7 +214,7 @@ private:
 
     void Check(const weld::TreeIter* pIter);
 
-    //DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void);
+    DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void);
 
     DECL_LINK(PopupModeEndHdl, FloatingWindow*, void);
 
@@ -261,7 +238,9 @@ private:
     std::unique_ptr<weld::TreeIter> mxScratchIter;
     std::unique_ptr<weld::Entry> mxEdSearch;
     std::unique_ptr<weld::Widget> mxBox;
-    std::unique_ptr<weld::TreeView> mxChecks;
+    std::unique_ptr<weld::TreeView> mxListChecks;
+    std::unique_ptr<weld::TreeView> mxTreeChecks;
+    weld::TreeView* mpChecks;
 
     std::unique_ptr<weld::CheckButton> mxChkToggleAll;
     std::unique_ptr<weld::Button> mxBtnSelectSingle;
@@ -282,9 +261,8 @@ private:
     std::unique_ptr<Action>       mxPopupEndAction;
 
     Config maConfig;
-    int mnWidthHint; /// min width hint
-    Size maWndSize;  /// whole window size.
-    Size maMenuSize; /// size of all menu items combined.
+    int mnCheckWidthReq; /// matching width request for mxChecks
+    int mnWndWidth;  /// whole window width.
     TriState mePrevToggleAllState;
 
     size_t  mnSelectedMenu;
@@ -322,8 +300,9 @@ private:
 class ScCheckListMenuWindow : public DockingWindow
 {
 public:
-    explicit ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, bool bCanHaveSubMenu, int nWidth = -1,
-                                   sal_uInt16 nMenuStackLevel = 0, ScCheckListMenuWindow* pParentMenu = nullptr);
+    explicit ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc,
+                                   bool bCanHaveSubMenu, bool bTreeMode, int nWidth = -1,
+                                   ScCheckListMenuWindow* pParentMenu = nullptr);
     virtual void dispose() override;
     virtual ~ScCheckListMenuWindow() override;
 
@@ -333,13 +312,10 @@ public:
     ScCheckListMenuWindow* GetParentMenu() { return mxParentMenu; }
     ScCheckListMenuControl& get_widget() { return *mxControl; }
 
-    sal_uInt16 GetMenuStackLevel() const { return mnMenuStackLevel; }
-
 private:
     VclPtr<ScCheckListMenuWindow> mxParentMenu;
     VclPtr<vcl::Window> mxBox;
-    std::unique_ptr<ScCheckListMenuControl> mxControl;
-    sal_uInt16 mnMenuStackLevel;
+    std::unique_ptr<ScCheckListMenuControl, o3tl::default_delete<ScCheckListMenuControl>> mxControl;
 };
 
 #endif
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 8509a37cfa80..31db62f12c6e 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -634,8 +634,14 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
     bool bLOKActive = comphelper::LibreOfficeKit::isActive();
 
     mpAutoFilterPopup.disposeAndClear();
+
+    // Estimate the width (in pixels) of the longest text in the list
+    ScFilterEntries aFilterEntries;
+    pDoc->GetFilterEntries(nCol, nRow, nTab, aFilterEntries);
+
     int nColWidth = ScViewData::ToPixel(pDoc->GetColWidth(nCol, nTab), pViewData->GetPPTX());
-    mpAutoFilterPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pDoc, false, nColWidth));
+    mpAutoFilterPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pDoc, false,
+                                                                  aFilterEntries.mbHasDates, nColWidth));
     ScCheckListMenuControl& rControl = mpAutoFilterPopup->get_widget();
 
     if (bLOKActive)
@@ -684,11 +690,6 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
         }
     }
 
-    // Populate the check box list.
-    ScFilterEntries aFilterEntries;
-    pDoc->GetFilterEntries(nCol, nRow, nTab, aFilterEntries);
-
-    rControl.setHasDates(aFilterEntries.mbHasDates);
     rControl.setMemberSize(aFilterEntries.size());
     for (const auto& rEntry : aFilterEntries)
     {
diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx
index 23adce09d061..bfd4eec09a0e 100644
--- a/sc/source/ui/view/gridwin2.cxx
+++ b/sc/source/ui/view/gridwin2.cxx
@@ -467,7 +467,8 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScr
     const ScDPLabelData& rLabelData = pDPData->maLabels;
 
     mpDPFieldPopup.disposeAndClear();
-    mpDPFieldPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pViewData->GetDocument(), bDimOrientNotPage));
+    mpDPFieldPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pViewData->GetDocument(),
+                                                               bDimOrientNotPage, false));
 
     ScCheckListMenuControl& rControl = mpDPFieldPopup->get_widget();
     rControl.setExtendedData(std::move(pDPData));
diff --git a/sc/uiconfig/scalc/ui/filterdropdown.ui b/sc/uiconfig/scalc/ui/filterdropdown.ui
index c37771a2116c..07c484c67ae8 100644
--- a/sc/uiconfig/scalc/ui/filterdropdown.ui
+++ b/sc/uiconfig/scalc/ui/filterdropdown.ui
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.2 -->
+<!-- Generated with glade 3.36.0 -->
 <interface domain="sw">
   <requires lib="gtk+" version="3.18"/>
   <object class="GtkImage" id="image1">
@@ -22,7 +22,21 @@
       <column type="gchararray"/>
     </columns>
   </object>
-  <object class="GtkTreeStore" id="liststore2">
+  <object class="GtkListStore" id="liststore2">
+    <columns>
+      <!-- column-name check1 -->
+      <column type="gboolean"/>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+      <!-- column-name checkvis1 -->
+      <column type="gboolean"/>
+      <!-- column-name checktri1 -->
+      <column type="gboolean"/>
+    </columns>
+  </object>
+  <object class="GtkTreeStore" id="treestore2">
     <columns>
       <!-- column-name check1 -->
       <column type="gboolean"/>
@@ -193,49 +207,108 @@
               </packing>
             </child>
             <child>
-              <object class="GtkScrolledWindow">
+              <object class="GtkBox">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
+                <property name="can_focus">False</property>
                 <property name="hexpand">True</property>
                 <property name="vexpand">True</property>
-                <property name="hscrollbar_policy">never</property>
-                <property name="shadow_type">in</property>
                 <child>
-                  <object class="GtkTreeView" id="check_list_box">
-                    <property name="visible">True</property>
+                  <object class="GtkScrolledWindow">
                     <property name="can_focus">True</property>
                     <property name="hexpand">True</property>
                     <property name="vexpand">True</property>
-                    <property name="model">liststore2</property>
-                    <property name="headers_visible">False</property>
-                    <property name="headers_clickable">False</property>
-                    <property name="search_column">1</property>
-                    <property name="show_expanders">False</property>
-                    <property name="enable_tree_lines">True</property>
-                    <child internal-child="selection">
-                      <object class="GtkTreeSelection"/>
-                    </child>
+                    <property name="shadow_type">in</property>
                     <child>
-                      <object class="GtkTreeViewColumn" id="treeviewcolumn4">
-                        <property name="resizable">True</property>
-                        <property name="spacing">6</property>
-                        <property name="alignment">0.5</property>
+                      <object class="GtkTreeView" id="check_list_box">
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="model">liststore2</property>
+                        <property name="headers_visible">False</property>
+                        <property name="headers_clickable">False</property>
+                        <property name="search_column">1</property>
+                        <property name="show_expanders">False</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection"/>
+                        </child>
                         <child>
-                          <object class="GtkCellRendererToggle" id="cellrenderer5"/>
-                          <attributes>
-                            <attribute name="visible">3</attribute>
-                            <attribute name="active">0</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+                            <property name="resizable">True</property>
+                            <property name="spacing">6</property>
+                            <property name="alignment">0.5</property>
+                            <child>
+                              <object class="GtkCellRendererToggle" id="cellrenderer5"/>
+                              <attributes>
+                                <attribute name="visible">3</attribute>
+                                <attribute name="active">0</attribute>
+                              </attributes>
+                            </child>
+                            <child>
+                              <object class="GtkCellRendererText" id="cellrenderer4"/>
+                              <attributes>
+                                <attribute name="text">1</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="check_tree_box">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="model">treestore2</property>
+                        <property name="headers_visible">False</property>
+                        <property name="headers_clickable">False</property>
+                        <property name="search_column">1</property>
+                        <property name="enable_tree_lines">True</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection"/>
                         </child>
                         <child>
-                          <object class="GtkCellRendererText" id="cellrenderer4"/>
-                          <attributes>
-                            <attribute name="text">1</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+                            <property name="resizable">True</property>
+                            <property name="spacing">6</property>
+                            <property name="alignment">0.5</property>
+                            <child>
+                              <object class="GtkCellRendererToggle" id="cellrenderer1"/>
+                              <attributes>
+                                <attribute name="visible">3</attribute>
+                                <attribute name="active">0</attribute>
+                              </attributes>
+                            </child>
+                            <child>
+                              <object class="GtkCellRendererText" id="cellrenderer2"/>
+                              <attributes>
+                                <attribute name="text">1</attribute>
+                              </attributes>
+                            </child>
+                          </object>
                         </child>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
               </object>
               <packing>


More information about the Libreoffice-commits mailing list