summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2020-11-12 16:30:46 +0000
committerCaolán McNamara <caolanm@redhat.com>2020-11-16 09:49:48 +0100
commitf57b158701fb082ad9016819a2af7cdb13e6fa30 (patch)
tree4d7be5c4c5318b0c1243b23b0db44e868b5d592b /sc
parent577b6be9ba4d55804e088dabfc2f40473ea3e726 (diff)
tdf#122419 optimize autofilter search when there are no dates
Change-Id: Id679b4a2e7a290780142daae39d28a429fb3b11d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105765 Tested-by: Jenkins Reviewed-by: Kevin Suo <suokunlong@126.com> Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'sc')
-rw-r--r--sc/source/ui/cctrl/checklistmenu.cxx95
1 files changed, 65 insertions, 30 deletions
diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx
index 07eb9b45b3df..a55547cbc12b 100644
--- a/sc/source/ui/cctrl/checklistmenu.cxx
+++ b/sc/source/ui/cctrl/checklistmenu.cxx
@@ -662,6 +662,18 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, TriStateHdl, weld::ToggleButton&, void)
mePrevToggleAllState = mxChkToggleAll->get_state();
}
+namespace
+{
+ void insertMember(weld::TreeView& rView, const weld::TreeIter& rIter, const ScCheckListMember& rMember, bool bChecked)
+ {
+ OUString aLabel = rMember.maName;
+ if (aLabel.isEmpty())
+ aLabel = ScResId(STR_EMPTYDATA);
+ rView.set_toggle(rIter, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
+ rView.set_text(rIter, aLabel, 0);
+ }
+}
+
IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
{
OUString aSearchText = mxEdSearch->get_text();
@@ -669,18 +681,15 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
bool bSearchTextEmpty = aSearchText.isEmpty();
size_t n = maMembers.size();
size_t nSelCount = 0;
- bool bSomeDateDeletes = false;
mpChecks->freeze();
- if (bSearchTextEmpty && !mbHasDates)
- {
- // when there are a lot of rows, it is cheaper to simply clear the tree and re-initialise
- mpChecks->clear();
- nSelCount = initMembers();
- }
- else
+ // This branch is the general case, the other is an optimized variant of
+ // this one where we can take advantage of knowing we have no hierarchy
+ if (mbHasDates)
{
+ bool bSomeDateDeletes = false;
+
for (size_t i = 0; i < n; ++i)
{
bool bIsDate = maMembers[i].mbDate;
@@ -725,20 +734,58 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
bSomeDateDeletes = true;
}
}
- }
- if ( bSomeDateDeletes )
+ if ( bSomeDateDeletes )
+ {
+ for (size_t i = 0; i < n; ++i)
+ {
+ if (!maMembers[i].mbDate)
+ continue;
+ if (maMembers[i].meDatePartType != ScCheckListMember::DAY)
+ continue;
+ updateMemberParents(nullptr, i);
+ }
+ }
+ }
+ else
{
- for (size_t i = 0; i < n; ++i)
+ // when there are a lot of rows, it is cheaper to simply clear the tree and either
+ // re-initialise or just insert the filtered lines
+ mpChecks->clear();
+
+ if (bSearchTextEmpty)
+ nSelCount = initMembers();
+ else
{
- if (!maMembers[i].mbDate)
- continue;
- if (maMembers[i].meDatePartType != ScCheckListMember::DAY)
- continue;
- updateMemberParents(nullptr, i);
+ std::vector<size_t> aShownIndexes;
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ assert(!maMembers[i].mbDate);
+
+ OUString aLabelDisp = maMembers[i].maName;
+ if ( aLabelDisp.isEmpty() )
+ aLabelDisp = ScResId( STR_EMPTYDATA );
+
+ bool bPartialMatch = ScGlobal::getCharClassPtr()->lowercase( aLabelDisp ).indexOf( aSearchText ) != -1;
+
+ if (!bPartialMatch)
+ continue;
+
+ aShownIndexes.push_back(i);
+ }
+
+ std::vector<int> aFixedWidths { mnCheckWidthReq };
+ // tdf#122419 insert in the fastest order, this might be backwards.
+ mpChecks->bulk_insert_for_each(aShownIndexes.size(), [this, &aShownIndexes, &nSelCount](weld::TreeIter& rIter, int i) {
+ size_t nIndex = aShownIndexes[i];
+ insertMember(*mpChecks, rIter, maMembers[nIndex], true);
+ ++nSelCount;
+ }, &aFixedWidths);
}
}
+
mpChecks->thaw();
if ( nSelCount == n )
@@ -1167,18 +1214,6 @@ IMPL_LINK(ScCheckListMenuControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
return false;
}
-namespace
-{
- 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(int nMaxMemberWidth)
{
size_t n = maMembers.size();
@@ -1195,7 +1230,7 @@ size_t ScCheckListMenuControl::initMembers(int nMaxMemberWidth)
// 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]);
+ insertMember(*mpChecks, rIter, maMembers[i], maMembers[i].mbVisible);
if (maMembers[i].mbVisible)
++nVisMemCount;
}, &aFixedWidths);
@@ -1223,7 +1258,7 @@ size_t ScCheckListMenuControl::initMembers(int nMaxMemberWidth)
else
{
mpChecks->append(xEntry.get());
- insertMember(*mpChecks, *xEntry, maMembers[i]);
+ insertMember(*mpChecks, *xEntry, maMembers[i], maMembers[i].mbVisible);
}
if (maMembers[i].mbVisible)