diff options
author | Szymon Kłos <szymon.klos@collabora.com> | 2020-10-20 10:55:44 +0200 |
---|---|---|
committer | Szymon Kłos <szymon.klos@collabora.com> | 2020-11-30 18:21:13 +0100 |
commit | 0b95ba1c9335e247a2e2ff946d36f98338aab1b1 (patch) | |
tree | fd76085c530a29052c1bc871d886cdcc0882e89c /sc | |
parent | aafd6037dafdf10669944cc90abdeb6e7ae4a618 (diff) |
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@collabora.com>
Reviewed-by: Szymon Kłos <szymon.klos@collabora.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/source/ui/cctrl/checklistmenu.cxx | 554 | ||||
-rw-r--r-- | sc/source/ui/inc/checklistmenu.hxx | 66 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 13 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin2.cxx | 3 | ||||
-rw-r--r-- | sc/uiconfig/scalc/ui/filterdropdown.ui | 133 |
5 files changed, 436 insertions, 333 deletions
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> |