From 511fb8e80d298d42f5c45e7410bf64f2a25b441e Mon Sep 17 00:00:00 2001 From: Jean-Sebastien Bevilacqua Date: Wed, 31 May 2017 10:59:42 +0200 Subject: tdf#108259 Enable autofilter with many different values When you create an autofilter on a column which contains many different values, you will have problems. First of all, if you exceed 65535 values, you will enter in an infinite loop because a uint16 is incremented for each value, and after 65535, you restart to 0. Secondly, the algorithm executes a double loop in O(n2) to determine checked values, it's too long. Instead of that, all checked values can be determined before. This patch is graciously offered by Linagora. Change-Id: Idc4500f6a496ae789aae11eb0e183aee157daa20 Reviewed-on: https://gerrit.libreoffice.org/38269 Reviewed-by: Noel Grandin Tested-by: Noel Grandin --- sc/source/ui/cctrl/checklistmenu.cxx | 26 ++++++++++++++++++++++---- sc/source/ui/inc/checklistmenu.hxx | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx index d3ed848145da..ee51abb9f8a8 100644 --- a/sc/source/ui/cctrl/checklistmenu.cxx +++ b/sc/source/ui/cctrl/checklistmenu.cxx @@ -1141,8 +1141,8 @@ void ScCheckListMenuWindow::setAllMemberState(bool bSet) { if (!(*itr)) { - sal_uInt16 nCount = maChecks->GetEntryCount(); - for( sal_uInt16 i = 0; i < nCount; ++i) + sal_uInt32 nCount = maChecks->GetEntryCount(); + for( sal_uInt32 i = 0; i < nCount; ++i) { SvTreeListEntry* pEntry = maChecks->GetEntry(i); if (!pEntry) @@ -1620,7 +1620,7 @@ ScCheckListBox::ScCheckListBox( vcl::Window* pParent ) SvTreeListEntry* ScCheckListBox::FindEntry( SvTreeListEntry* pParent, const OUString& sNode ) { - sal_uInt16 nRootPos = 0; + sal_uInt32 nRootPos = 0; SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : GetEntry( nRootPos ); while ( pEntry ) { @@ -1639,6 +1639,23 @@ void ScCheckListBox::Init() SetNodeDefaultImages(); } +std::unordered_set ScCheckListBox::GetAllChecked() +{ + std::unordered_set results(0); + sal_uInt32 nRootPos = 0; + SvTreeListEntry* pEntry = GetEntry(nRootPos); + while (pEntry) + { + if (GetCheckButtonState(pEntry) == SvButtonState::Checked) + { + results.insert(GetEntryText(pEntry)); + } + pEntry = GetEntry(++nRootPos); + } + + return results; +} + bool ScCheckListBox::IsChecked( const OUString& sName, SvTreeListEntry* pParent ) { SvTreeListEntry* pEntry = FindEntry( pParent, sName ); @@ -1907,6 +1924,7 @@ bool ScCheckListMenuWindow::isAllSelected() const void ScCheckListMenuWindow::getResult(ResultType& rResult) { ResultType aResult; + std::unordered_set checkeds = maChecks->GetAllChecked(); size_t n = maMembers.size(); for (size_t i = 0; i < n; ++i) { @@ -1915,7 +1933,7 @@ void ScCheckListMenuWindow::getResult(ResultType& rResult) OUString aLabel = maMembers[i].maName; if (aLabel.isEmpty()) aLabel = ScGlobal::GetRscString(STR_EMPTYDATA); - bool bState = maChecks->IsChecked( aLabel, maMembers[i].mpParent ); + bool bState = checkeds.find(aLabel) != checkeds.end(); ResultEntry aResultEntry; aResultEntry.bValid = bState; if ( maMembers[i].mbDate ) diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx index 9c1a1f3fd07f..7bae3853e82e 100644 --- a/sc/source/ui/inc/checklistmenu.hxx +++ b/sc/source/ui/inc/checklistmenu.hxx @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -239,6 +240,7 @@ class ScCheckListBox : public SvTreeListBox void CheckEntry( const OUString& sName, SvTreeListEntry* pParent, bool bCheck ); void CheckEntry( SvTreeListEntry* pEntry, bool bCheck ); SvTreeListEntry* ShowCheckEntry( const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true ); + std::unordered_set GetAllChecked(); bool IsChecked( const OUString& sName, SvTreeListEntry* pParent ); SvTreeListEntry* FindEntry( SvTreeListEntry* pParent, const OUString& sNode ); sal_uInt16 GetCheckedEntryCount() const; -- cgit