sc/inc/filterentries.hxx | 7 + sc/qa/uitest/autofilter2/tdf159420.py | 126 ++++++++++++++++++++++++++++++++++ sc/source/core/data/column3.cxx | 17 +++- 3 files changed, 145 insertions(+), 5 deletions(-)
New commits: commit e66f5cb353bc0ea1020061bab4981380f98499b9 Author: Xisco Fauli <xiscofa...@libreoffice.org> AuthorDate: Tue Jan 30 13:57:18 2024 +0100 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Thu Feb 29 12:59:36 2024 +0100 tdf#159420: Show empty option even if empty is filtered out in other columns Regression from 89e032e9c4c51f52680c7d8bacf59ab2a34f2180 "tdf#158314: show Empty and Error entries as non-selected and inactive... ...when hidden by autofilter." The mbHasEmpties variable was added in 9c1826d98065c30411cbf2e731560165ca2b7668 "sc-perf: do not add a million empty filter entries just to sort and discard" Change-Id: Ie0d81fd57f68038fac62cb6a3442e93ed547167a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162752 Tested-by: Jenkins Reviewed-by: Kevin Suo <suokunl...@126.com> diff --git a/sc/inc/filterentries.hxx b/sc/inc/filterentries.hxx index 02110c879b03..1ec3f22a324b 100644 --- a/sc/inc/filterentries.hxx +++ b/sc/inc/filterentries.hxx @@ -18,11 +18,14 @@ struct ScFilterEntries { std::vector<ScTypedStrData> maStrData; bool mbHasDates; - bool mbHasEmpties; + bool mbHasHiddenEmpties; + bool mbHasUnHiddenEmpties; std::set<Color> maTextColors; std::set<Color> maBackgroundColors; - ScFilterEntries() : mbHasDates(false), mbHasEmpties(false) {} + ScFilterEntries() : mbHasDates(false), + mbHasHiddenEmpties(false), + mbHasUnHiddenEmpties(false) {} std::vector<ScTypedStrData>::iterator begin() { return maStrData.begin(); } std::vector<ScTypedStrData>::iterator end() { return maStrData.end(); } diff --git a/sc/qa/uitest/autofilter2/tdf159420.py b/sc/qa/uitest/autofilter2/tdf159420.py new file mode 100644 index 000000000000..87ee159d2223 --- /dev/null +++ b/sc/qa/uitest/autofilter2/tdf159420.py @@ -0,0 +1,126 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +from uitest.framework import UITestCase +from uitest.uihelper.calc import enter_text_to_cell +from uitest.uihelper.common import get_state_as_dict +from libreoffice.uno.propertyvalue import mkPropertyValues +from libreoffice.calc.document import is_row_hidden + +class tdf159420(UITestCase): + + def testTdf159420(self): + with self.ui_test.create_doc_in_start_center("calc") as calcDoc: + xCalcDoc = self.xUITest.getTopFocusWindow() + xGridWin = xCalcDoc.getChild("grid_window") + + # Fill the sheet with test data + enter_text_to_cell(xGridWin, "A1", "a") + enter_text_to_cell(xGridWin, "A2", "2") + enter_text_to_cell(xGridWin, "A3", "2") + enter_text_to_cell(xGridWin, "A4", "2") + enter_text_to_cell(xGridWin, "A5", "4") + + enter_text_to_cell(xGridWin, "B1", "b") + enter_text_to_cell(xGridWin, "B2", "") + enter_text_to_cell(xGridWin, "B3", "") + enter_text_to_cell(xGridWin, "B4", "8") + enter_text_to_cell(xGridWin, "B5", "8") + + enter_text_to_cell(xGridWin, "C1", "c") + + # Select the data range and set autofilter + xGridWin.executeAction("SELECT", mkPropertyValues({"RANGE": "A1:C5"})) + self.xUITest.executeCommand(".uno:DataFilterAutoFilter") + + # Click the autofilter dropdown in column A + xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) + xFloatWindow = self.xUITest.getFloatWindow() + xCheckListMenu = xFloatWindow.getChild("FilterDropDown") + xTreeList = xCheckListMenu.getChild("check_list_box") + + self.assertEqual(2, len(xTreeList.getChildren())) + + xEntry1 = xTreeList.getChild(0) + self.assertEqual("2", get_state_as_dict(xEntry1)['Text']) + self.assertEqual("true", get_state_as_dict(xEntry1)['IsChecked']) + self.assertEqual("false", get_state_as_dict(xEntry1)['IsSemiTransparent']) + + xEntry2 = xTreeList.getChild(1) + self.assertEqual("4", get_state_as_dict(xEntry2)['Text']) + self.assertEqual("true", get_state_as_dict(xEntry2)['IsChecked']) + self.assertEqual("false", get_state_as_dict(xEntry2)['IsSemiTransparent']) + + # Uncheck the second entry + xEntry2.executeAction("CLICK", tuple()) + + xOkButton = xFloatWindow.getChild("ok") + xOkButton.executeAction("CLICK", tuple()) + + # Check that only row#2 is visible + self.assertFalse(is_row_hidden(calcDoc, 1)) + self.assertFalse(is_row_hidden(calcDoc, 2)) + self.assertFalse(is_row_hidden(calcDoc, 3)) + self.assertTrue(is_row_hidden(calcDoc, 4)) + + # Click the autofilter dropdown in column B + xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "1", "ROW": "0"})) + xFloatWindow = self.xUITest.getFloatWindow() + xCheckListMenu = xFloatWindow.getChild("FilterDropDown") + xTreeList = xCheckListMenu.getChild("check_list_box") + + self.assertEqual(2, len(xTreeList.getChildren())) + + xEntry1 = xTreeList.getChild(0) + self.assertEqual("(empty)", get_state_as_dict(xEntry1)['Text']) + self.assertEqual("true", get_state_as_dict(xEntry1)['IsChecked']) + self.assertEqual("false", get_state_as_dict(xEntry1)['IsSemiTransparent']) + + xEntry2 = xTreeList.getChild(1) + self.assertEqual("8", get_state_as_dict(xEntry2)['Text']) + self.assertEqual("true", get_state_as_dict(xEntry2)['IsChecked']) + self.assertEqual("false", get_state_as_dict(xEntry2)['IsSemiTransparent']) + + # Uncheck the first entry + xEntry1.executeAction("CLICK", tuple()) + + # Close the popup window + xOkButton = xFloatWindow.getChild("ok") + xOkButton.executeAction("CLICK", tuple()) + + self.assertTrue(is_row_hidden(calcDoc, 1)) + self.assertTrue(is_row_hidden(calcDoc, 2)) + self.assertFalse(is_row_hidden(calcDoc, 3)) + self.assertTrue(is_row_hidden(calcDoc, 4)) + + # Click the autofilter dropdown in column C + xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "2", "ROW": "0"})) + xFloatWindow = self.xUITest.getFloatWindow() + xCheckListMenu = xFloatWindow.getChild("FilterDropDown") + xTreeList = xCheckListMenu.getChild("check_list_box") + + self.assertEqual(1, len(xTreeList.getChildren())) + + xEntry1 = xTreeList.getChild(0) + self.assertEqual("(empty)", get_state_as_dict(xEntry1)['Text']) + + # Without the fix in place, this test would have failed with + # AssertionError: 'true' != 'false' + self.assertEqual("true", get_state_as_dict(xEntry1)['IsChecked']) + self.assertEqual("false", get_state_as_dict(xEntry1)['IsSemiTransparent']) + + # Close the popup window + xOkButton = xFloatWindow.getChild("ok") + xOkButton.executeAction("CLICK", tuple()) + + self.assertTrue(is_row_hidden(calcDoc, 1)) + self.assertTrue(is_row_hidden(calcDoc, 2)) + self.assertFalse(is_row_hidden(calcDoc, 3)) + self.assertTrue(is_row_hidden(calcDoc, 4)) + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index e01d6312506f..a03f3f172cd1 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -2583,10 +2583,21 @@ class FilterEntriesHandler if (bIsEmptyCell) { - if (!mrFilterEntries.mbHasEmpties) + if (mbFilteredRow) { - mrFilterEntries.push_back(ScTypedStrData(OUString(), 0.0, 0.0, ScTypedStrData::Standard, false, mbFilteredRow)); - mrFilterEntries.mbHasEmpties = true; + if (!mrFilterEntries.mbHasHiddenEmpties) + { + mrFilterEntries.push_back(ScTypedStrData(OUString(), 0.0, 0.0, ScTypedStrData::Standard, false, true)); + mrFilterEntries.mbHasHiddenEmpties = true; + } + } + else + { + if (!mrFilterEntries.mbHasUnHiddenEmpties) + { + mrFilterEntries.push_back(ScTypedStrData(OUString(), 0.0, 0.0, ScTypedStrData::Standard, false, false)); + mrFilterEntries.mbHasUnHiddenEmpties = true; + } } return; }