summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzymon Kłos <szymon.klos@collabora.com>2020-10-20 10:55:44 +0200
committerSzymon Kłos <szymon.klos@collabora.com>2020-11-30 18:21:13 +0100
commit0b95ba1c9335e247a2e2ff946d36f98338aab1b1 (patch)
treefd76085c530a29052c1bc871d886cdcc0882e89c
parentaafd6037dafdf10669944cc90abdeb6e7ae4a618 (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>
-rw-r--r--sc/source/ui/cctrl/checklistmenu.cxx554
-rw-r--r--sc/source/ui/inc/checklistmenu.hxx66
-rw-r--r--sc/source/ui/view/gridwin.cxx13
-rw-r--r--sc/source/ui/view/gridwin2.cxx3
-rw-r--r--sc/uiconfig/scalc/ui/filterdropdown.ui133
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>