diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 09:29:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 09:29:03 +0000 |
commit | 5a7157d319477830426797532e02ac39d3b859f4 (patch) | |
tree | 3773f5ce209bee14a5643e98672e0f3828c71434 /sc | |
parent | Releasing progress-linux version 4:24.2.0-3~progress7.99u1. (diff) | |
download | libreoffice-5a7157d319477830426797532e02ac39d3b859f4.tar.xz libreoffice-5a7157d319477830426797532e02ac39d3b859f4.zip |
Merging upstream version 4:24.2.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc')
37 files changed, 750 insertions, 120 deletions
diff --git a/sc/CppunitTest_sc_filter_html.mk b/sc/CppunitTest_sc_filter_html.mk new file mode 100644 index 0000000000..f3dec22c08 --- /dev/null +++ b/sc/CppunitTest_sc_filter_html.mk @@ -0,0 +1,83 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,sc_filter_html)) + +$(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_filter_html)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sc_filter_html, \ + sc/qa/filter/html/html \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sc_filter_html, \ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sc_filter_html, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + drawinglayercore \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sc \ + scqahelper \ + sfx \ + sot \ + subsequenttest \ + svl \ + svt \ + svx \ + svxcore \ + test \ + tk \ + tl \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_set_include,sc_filter_html,\ + -I$(SRCDIR)/sc/source/ui/inc \ + -I$(SRCDIR)/sc/inc \ + -I$(SRCDIR)/sc/qa/unit \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_api,sc_filter_html,\ + udkapi \ + offapi \ + oovbaapi \ +)) + +$(eval $(call gb_CppunitTest_use_packages,sc_filter_html, \ + filter_xhtml \ + filter_xslt \ +)) + +$(eval $(call gb_CppunitTest_use_ure,sc_filter_html)) +$(eval $(call gb_CppunitTest_use_vcl,sc_filter_html)) + +$(eval $(call gb_CppunitTest_use_rdb,sc_filter_html,services)) + +$(eval $(call gb_CppunitTest_use_configuration,sc_filter_html)) + +# vim: set noet sw=4 ts=4: diff --git a/sc/CppunitTest_sc_filters_test.mk b/sc/CppunitTest_sc_filters_test.mk index 67ef606640..3dae5136e1 100644 --- a/sc/CppunitTest_sc_filters_test.mk +++ b/sc/CppunitTest_sc_filters_test.mk @@ -118,6 +118,7 @@ $(eval $(call gb_CppunitTest_use_components,sc_filters_test,\ uui/util/uui \ vcl/vcl.common \ xmloff/util/xo \ + xmlsecurity/util/xsec_xmlsec \ )) $(eval $(call gb_CppunitTest_use_configuration,sc_filters_test)) diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index 0c2178b7fe..a01c9115f3 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -96,6 +96,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sc, \ CppunitTest_sc_uicalc2 \ CppunitTest_sc_vba_macro_test \ CppunitTest_sc_a11y \ + CppunitTest_sc_filter_html \ )) ifneq ($(ENABLE_JUMBO_SHEETS),) diff --git a/sc/inc/typedstrdata.hxx b/sc/inc/typedstrdata.hxx index b4a9bc5d37..b6bed2dfc2 100644 --- a/sc/inc/typedstrdata.hxx +++ b/sc/inc/typedstrdata.hxx @@ -54,11 +54,21 @@ public: bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const; }; + struct LessSortCaseSensitive + { + bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const; + }; + struct LessCaseInsensitive { bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const; }; + struct LessSortCaseInsensitive + { + bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const; + }; + struct EqualCaseSensitive { bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const; diff --git a/sc/qa/extras/macros-test.cxx b/sc/qa/extras/macros-test.cxx index 4494f3f65b..92878cf2be 100644 --- a/sc/qa/extras/macros-test.cxx +++ b/sc/qa/extras/macros-test.cxx @@ -897,6 +897,33 @@ CPPUNIT_TEST_FIXTURE(ScMacrosTest, testTdf116127) CPPUNIT_ASSERT_EQUAL(Any(true), aRet); } +CPPUNIT_TEST_FIXTURE(ScMacrosTest, testTdf159412) +{ + // Run a macro, that itself calls two other functions using invoke, + // passing a small integer value to agruments of types Long and Double + createScDoc("tdf159412.fods"); + + css::uno::Any aRet; + css::uno::Sequence<sal_Int16> aOutParamIndex; + css::uno::Sequence<css::uno::Any> aOutParam; + css::uno::Sequence<css::uno::Any> aParams; + + SfxObjectShell::CallXScript( + mxComponent, + "vnd.sun.Star.script:Standard.Module1.TestInvoke?language=Basic&location=document", + aParams, aRet, aOutParamIndex, aOutParam); + + OUString aReturnValue; + aRet >>= aReturnValue; + + // Without the fix in place, this test would have failed with + // - Expected: 1 Long/2 Double + // - Actual : 0 Long/0 Double + // i.e., the passed 1 and 2 values were lost. + + CPPUNIT_ASSERT_EQUAL(u"1 Long/2 Double"_ustr, aReturnValue); +} + ScMacrosTest::ScMacrosTest() : ScModelTestBase("/sc/qa/extras/testdocuments") { diff --git a/sc/qa/extras/testdocuments/tdf159412.fods b/sc/qa/extras/testdocuments/tdf159412.fods new file mode 100644 index 0000000000..ec537dd061 --- /dev/null +++ b/sc/qa/extras/testdocuments/tdf159412.fods @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.spreadsheet"> + <office:scripts> + <office:script script:language="ooo:Basic"> + <ooo:libraries> + <ooo:library-embedded ooo:name="Standard"> + <ooo:module ooo:name="Module1"> + <ooo:source-code>REM ***** BASIC ***** + +Function TestInvoke + script = ThisComponent.scriptProvider.getScript("vnd.sun.star.script:Standard.Module1.S_Ref_Long?language=Basic&location=document") + ret = script.invoke(Array(1), Array(), Array()) + + script = ThisComponent.scriptProvider.getScript("vnd.sun.star.script:Standard.Module1.S_Ref_Dbl?language=Basic&location=document") + ret = ret & "/" & script.invoke(Array(2), Array(), Array()) + + TestInvoke = ret +End Function + +Function S_Ref_Long(n As Long) + S_Ref_Long = CStr(n) & " " & TypeName(n) +End Function + +Function S_Ref_Dbl(n As Double) + S_Ref_Dbl = CStr(n) & " " & TypeName(n) +End Function + + + </ooo:source-code> + </ooo:module> + </ooo:library-embedded> + </ooo:libraries> + </office:script> + </office:scripts> + <office:body> + <office:spreadsheet> + <table:table table:name="Sheet1"/> + </office:spreadsheet> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sc/qa/filter/html/data/bool.html b/sc/qa/filter/html/data/bool.html new file mode 100644 index 0000000000..8fe27993f1 --- /dev/null +++ b/sc/qa/filter/html/data/bool.html @@ -0,0 +1,8 @@ +<table> + <tr> + <td data-sheets-value="{"1":4,"4":1}">WAHR</td> + </tr> + <tr> + <td data-sheets-value="{"1":4,"4":0}">FALSCH</td> + </tr> +</table> diff --git a/sc/qa/filter/html/data/text.html b/sc/qa/filter/html/data/text.html new file mode 100644 index 0000000000..eadb34b5e1 --- /dev/null +++ b/sc/qa/filter/html/data/text.html @@ -0,0 +1,8 @@ +<table> + <tr> + <td data-sheets-value="{"1":3,"3":1}">1</td> + </tr> + <tr> + <td data-sheets-value="{"1":2,"2":"01","6":1}">01</td> + </tr> +</table> diff --git a/sc/qa/filter/html/html.cxx b/sc/qa/filter/html/html.cxx new file mode 100644 index 0000000000..6ab2cc7fb0 --- /dev/null +++ b/sc/qa/filter/html/html.cxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-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/. + */ + +#include <test/unoapixml_test.hxx> +#include <test/htmltesttools.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/table/XCellRange.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <svl/numformat.hxx> +#include <svl/zformat.hxx> + +#include <helper/qahelper.hxx> +#include <impex.hxx> + +using namespace com::sun::star; + +namespace +{ +/// Covers sc/source/filter/html/ fixes. +class Test : public ScModelTestBase, public HtmlTestTools +{ +public: + Test() + : ScModelTestBase("/sc/qa/filter/html/data/") + { + } +}; + +CPPUNIT_TEST_FIXTURE(Test, testTdAsText) +{ + // Given a document with an A2 cell that contains "02" as text: + OUString aURL = createFileURL(u"text.html"); + + // When loading that document to Calc: + uno::Sequence<beans::PropertyValue> aParams = { + comphelper::makePropertyValue("DocumentService", + OUString("com.sun.star.sheet.SpreadsheetDocument")), + }; + loadWithParams(aURL, aParams); + + // Then make sure "01" is not auto-converted to 1, as a number: + uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xSheets(xDocument->getSheets(), uno::UNO_QUERY); + uno::Reference<table::XCellRange> xSheet(xSheets->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xCell(xSheet->getCellByPosition(0, 1), uno::UNO_QUERY); + table::CellContentType eType{}; + xCell->getPropertyValue("CellContentType") >>= eType; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 (TEXT) + // - Actual : 1 (VALUE) + // i.e. data-sheets-value was ignored on import. + CPPUNIT_ASSERT_EQUAL(table::CellContentType_TEXT, eType); +} + +CPPUNIT_TEST_FIXTURE(Test, testPasteTdAsText) +{ + // Given an empty document: + createScDoc(); + + // When pasting HTML with an A2 cell that contains "01" as text: + ScDocument* pDoc = getScDoc(); + ScAddress aCellPos(/*nColP=*/0, /*nRowP=*/0, /*nTabP=*/0); + ScImportExport aImporter(*pDoc, aCellPos); + SvFileStream aFile(createFileURL(u"text.html"), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + aMemory.Seek(0); + CPPUNIT_ASSERT(aImporter.ImportStream(aMemory, OUString(), SotClipboardFormatId::HTML)); + + // Then make sure "01" is not auto-converted to 1, as a number: + aCellPos = ScAddress(/*nColP=*/0, /*nRowP=*/1, /*nTabP=*/0); + CellType eCellType = pDoc->GetCellType(aCellPos); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 (CELLTYPE_STRING) + // - Actual : 1 (CELLTYPE_VALUE) + // i.e. data-sheets-value was ignored on paste. + CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, eCellType); +} + +CPPUNIT_TEST_FIXTURE(Test, testPasteTdAsBools) +{ + // Given an empty document: + createScDoc(); + + // When pasting HTML with bool cells: + ScDocument* pDoc = getScDoc(); + ScAddress aCellPos(/*nColP=*/0, /*nRowP=*/0, /*nTabP=*/0); + ScImportExport aImporter(*pDoc, aCellPos); + SvFileStream aFile(createFileURL(u"bool.html"), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + aMemory.Seek(0); + CPPUNIT_ASSERT(aImporter.ImportStream(aMemory, OUString(), SotClipboardFormatId::HTML)); + + // Then make sure A1's type is bool, value is true: + sal_uInt32 nNumberFormat = pDoc->GetNumberFormat(/*col=*/0, /*row=*/0, /*tab=*/0); + const SvNumberformat* pNumberFormat = pDoc->GetFormatTable()->GetEntry(nNumberFormat); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: BOOLEAN + // - Actual : General + // i.e. data-sheets-value's bool case was ignored. + CPPUNIT_ASSERT_EQUAL(OUString("BOOLEAN"), pNumberFormat->GetFormatstring()); + CPPUNIT_ASSERT_EQUAL(static_cast<double>(1), pDoc->GetValue(/*col=*/0, /*row=*/0, /*tab=*/0)); + // And make sure A2's type is bool, value is true: + nNumberFormat = pDoc->GetNumberFormat(/*col=*/0, /*row=*/1, /*tab=*/0); + pNumberFormat = pDoc->GetFormatTable()->GetEntry(nNumberFormat); + CPPUNIT_ASSERT_EQUAL(OUString("BOOLEAN"), pNumberFormat->GetFormatstring()); + CPPUNIT_ASSERT_EQUAL(static_cast<double>(0), pDoc->GetValue(/*col=*/0, /*row=*/1, /*tab=*/0)); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/uitest/autofilter/autofilterBugs.py b/sc/qa/uitest/autofilter/autofilterBugs.py index 6fa029985f..849351861d 100644 --- a/sc/qa/uitest/autofilter/autofilterBugs.py +++ b/sc/qa/uitest/autofilter/autofilterBugs.py @@ -73,6 +73,30 @@ class autofilter(UITestCase): self.assertEqual(get_state_as_dict(xTreeList.getChild("4"))["Text"], "vröude") self.assertEqual(get_state_as_dict(xTreeList.getChild("5"))["Text"], "vröudᵉ") + def test_tdf158326(self): + with self.ui_test.create_doc_in_start_center("calc"): + calcDoc = self.xUITest.getTopFocusWindow() + xGridWindow = calcDoc.getChild("grid_window") + enter_text_to_cell(xGridWindow, "A1", "vröude") + enter_text_to_cell(xGridWindow, "A2", "vröudᵉ") + enter_text_to_cell(xGridWindow, "A3", "vröude") + enter_text_to_cell(xGridWindow, "A4", "vröudᵉ") + enter_text_to_cell(xGridWindow, "A5", "vröude") + enter_text_to_cell(xGridWindow, "A6", "vröudᵉ") + xGridWindow.executeAction("SELECT", mkPropertyValues({"RANGE": "A1:A6"})) + + with self.ui_test.execute_dialog_through_command(".uno:DataFilterAutoFilter", close_button="no"): + pass + + xGridWindow.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) + xFloatWindow = self.xUITest.getFloatWindow() + xTreeList = xFloatWindow.getChild("check_list_box") + + # Without the fix in place, there would be 5 items since they will not be removed + self.assertEqual(2, len(xTreeList.getChildren())) + self.assertEqual(get_state_as_dict(xTreeList.getChild("0"))["Text"], "vröude") + self.assertEqual(get_state_as_dict(xTreeList.getChild("1"))["Text"], "vröudᵉ") + def test_tdf94055(self): with self.ui_test.create_doc_in_start_center("calc") as document: calcDoc = self.xUITest.getTopFocusWindow() diff --git a/sc/qa/uitest/autofilter2/tdf158314_EmptyError.py b/sc/qa/uitest/autofilter2/tdf158314_EmptyError.py new file mode 100644 index 0000000000..2ced88c80d --- /dev/null +++ b/sc/qa/uitest/autofilter2/tdf158314_EmptyError.py @@ -0,0 +1,94 @@ +# -*- 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 + +# Bug 158314 - Autofilter dropdown list always shows "Empty" entry as active + +class tdf158314_EmptyEntries(UITestCase): + def testTdf158314(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", "1") + enter_text_to_cell(xGridWin, "A3", "2") + enter_text_to_cell(xGridWin, "A4", "3") + enter_text_to_cell(xGridWin, "A5", "4") + + enter_text_to_cell(xGridWin, "B1", "b") + enter_text_to_cell(xGridWin, "B2", "5") + enter_text_to_cell(xGridWin, "B3", "") + enter_text_to_cell(xGridWin, "B4", "=1/0") + enter_text_to_cell(xGridWin, "B5", "8") + + # Select the data range and set autofilter + xGridWin.executeAction("SELECT", mkPropertyValues({"RANGE": "A1:B5"})) + 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") + + # Select the first entry only. Uncheck all other entries. + for i in xTreeList.getChildren(): + if i != "0": + xEntry = xTreeList.getChild(i) + xEntry.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.assertTrue(is_row_hidden(calcDoc, 2)) + self.assertTrue(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") + + # There should be at least one entry in the dropdown + # (i.e., the feature of showing inactive autofilter entries may be disabled) + self.assertEqual(True, len(xTreeList.getChildren()) >= 1) + + for i in xTreeList.getChildren(): + state = get_state_as_dict(xTreeList.getChild(i)) + # The Text of the first element should be '5' and it should be checked and active + if i == "0": + self.assertEqual("5", state["Text"]) + self.assertEqual("true", state["IsChecked"]) + self.assertEqual("true", state["IsSelected"]) + self.assertEqual("false", state["IsSemiTransparent"]) + # All other elements (including the Empty and #DIV/0!) should be unchecked and inactive + else: + self.assertEqual("false", state["IsChecked"]) + self.assertEqual("false", state["IsSelected"]) + self.assertEqual("true", state["IsSemiTransparent"]) + + # Close the popup window + xOkButton = xFloatWindow.getChild("ok") + xOkButton.executeAction("CLICK", tuple()) + + # Check again that only row#2 is visible + self.assertFalse(is_row_hidden(calcDoc, 1)) + self.assertTrue(is_row_hidden(calcDoc, 2)) + self.assertTrue(is_row_hidden(calcDoc, 3)) + self.assertTrue(is_row_hidden(calcDoc, 4)) +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sc/qa/uitest/calc_tests8/navigator.py b/sc/qa/uitest/calc_tests8/navigator.py index ec8fa2ae9a..9c1769dcf4 100644 --- a/sc/qa/uitest/calc_tests8/navigator.py +++ b/sc/qa/uitest/calc_tests8/navigator.py @@ -10,6 +10,7 @@ from uitest.framework import UITestCase from libreoffice.uno.propertyvalue import mkPropertyValues from uitest.uihelper.common import get_state_as_dict, get_url_for_data_file +from uitest.uihelper.calc import enter_text_to_cell class navigator(UITestCase): @@ -181,4 +182,30 @@ class navigator(UITestCase): self.xUITest.executeCommand(".uno:Sidebar") + + def test_tdf158652(self): + with self.ui_test.create_doc_in_start_center("calc"): + xCalcDoc = self.xUITest.getTopFocusWindow() + xGridWin = xCalcDoc.getChild("grid_window") + + self.xUITest.executeCommand(".uno:Sidebar") + + xGridWin.executeAction("SIDEBAR", mkPropertyValues({"PANEL": "ScNavigatorPanel"})) + + xCalcDoc = self.xUITest.getTopFocusWindow() + xNavigatorPanel = xCalcDoc.getChild("NavigatorPanel") + xContentBox = xNavigatorPanel.getChild('contentbox') + enter_text_to_cell(xGridWin, "A1", "1") + + commentText = mkPropertyValues({"Text":"CommentText"}) + self.xUITest.executeCommandWithParameters(".uno:InsertAnnotation", commentText) + xComments = xContentBox.getChild("6") + self.assertEqual(len(xComments.getChildren()), 1) + + self.xUITest.executeCommand(".uno:DeleteNote") + xComments = xContentBox.getChild("6") + self.assertEqual(len(xComments.getChildren()), 0) + + self.xUITest.executeCommand(".uno:Sidebar") + # vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sc/qa/unit/data/xlsx/tdf159581_optimalRowHeight.xlsx b/sc/qa/unit/data/xlsx/tdf159581_optimalRowHeight.xlsx Binary files differnew file mode 100644 index 0000000000..8df7720804 --- /dev/null +++ b/sc/qa/unit/data/xlsx/tdf159581_optimalRowHeight.xlsx diff --git a/sc/qa/unit/subsequent_filters_test2.cxx b/sc/qa/unit/subsequent_filters_test2.cxx index dd63f0b8a9..2b8ff43962 100644 --- a/sc/qa/unit/subsequent_filters_test2.cxx +++ b/sc/qa/unit/subsequent_filters_test2.cxx @@ -159,6 +159,17 @@ CPPUNIT_TEST_FIXTURE(ScFiltersTest2, testTdf123026_optimalRowHeight) CPPUNIT_ASSERT_GREATER(2000, nHeight); } +CPPUNIT_TEST_FIXTURE(ScFiltersTest2, testTdf159581_optimalRowHeight) +{ + createScDoc("xlsx/tdf159581_optimalRowHeight.xlsx"); + SCTAB nTab = 1; + SCROW nRow = 0; // row 1 + int nHeight = convertTwipToMm100(getScDoc()->GetRowHeight(nRow, nTab, false)); + + // Without the fix, this was 2027. It should be 450. + CPPUNIT_ASSERT_LESS(500, nHeight); +} + CPPUNIT_TEST_FIXTURE(ScFiltersTest2, testCustomNumFormatHybridCellODS) { createScDoc("ods/custom-numfmt-hybrid-cell.ods"); diff --git a/sc/qa/unit/tiledrendering/data/invalidate-on-save.ods b/sc/qa/unit/tiledrendering/data/invalidate-on-save.ods Binary files differnew file mode 100644 index 0000000000..efe2c225a4 --- /dev/null +++ b/sc/qa/unit/tiledrendering/data/invalidate-on-save.ods diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx index 00fda9336f..9e07c0c060 100644 --- a/sc/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx @@ -3113,6 +3113,36 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testGetViewRenderState) CPPUNIT_ASSERT_EQUAL(";Default"_ostr, pModelObj->getViewRenderState()); } +// Saving shouldn't trigger an invalidation +CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testNoInvalidateOnSave) +{ + comphelper::LibreOfficeKit::setCompatFlag( + comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs); + + loadFromFile(u"invalidate-on-save.ods"); + + // .uno:Save modifies the original file, make a copy first + saveAndReload("calc8"); + ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(mxComponent); + CPPUNIT_ASSERT(pModelObj); + pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + + ScTabViewShell* pView = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current()); + CPPUNIT_ASSERT(pView); + + Scheduler::ProcessEventsToIdle(); + + // track invalidations + ViewCallback aView; + + uno::Sequence<beans::PropertyValue> aArgs; + dispatchCommand(mxComponent, ".uno:Save", aArgs); + + Scheduler::ProcessEventsToIdle(); + + CPPUNIT_ASSERT(!aView.m_bInvalidateTiles); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/colcontainer.cxx b/sc/source/core/data/colcontainer.cxx index f6ef8ff7da..a0a9d84577 100644 --- a/sc/source/core/data/colcontainer.cxx +++ b/sc/source/core/data/colcontainer.cxx @@ -47,10 +47,9 @@ void ScColContainer::Clear() void ScColContainer::resize( ScSheetLimits const & rSheetLimits, const size_t aNewColSize ) { size_t aOldColSize = aCols.size(); - if (aNewColSize > aCols.capacity()) - aCols.reserve( aNewColSize ); + aCols.resize( aNewColSize ); for ( size_t nCol = aOldColSize; nCol < aNewColSize; ++nCol ) - aCols.emplace_back(new ScColumn(rSheetLimits)); + aCols[nCol].reset(new ScColumn(rSheetLimits)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index a0b0c639a0..7902722638 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -2584,7 +2584,7 @@ class FilterEntriesHandler { if (!mrFilterEntries.mbHasEmpties) { - mrFilterEntries.push_back(ScTypedStrData(OUString())); + mrFilterEntries.push_back(ScTypedStrData(OUString(), 0.0, 0.0, ScTypedStrData::Standard, false, mbFilteredRow)); mrFilterEntries.mbHasEmpties = true; } return; @@ -2614,7 +2614,7 @@ class FilterEntriesHandler OUString aErr = ScGlobal::GetErrorString(nErr); if (!aErr.isEmpty()) { - mrFilterEntries.push_back(ScTypedStrData(std::move(aErr))); + mrFilterEntries.push_back(ScTypedStrData(std::move(aErr), 0.0, 0.0, ScTypedStrData::Standard, false, mbFilteredRow)); return; } } diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index b1fca78c86..1fe1f5344d 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -1683,13 +1683,13 @@ void ScDocRowHeightUpdater::updateAll(const bool bOnlyUsedRows) ScProgress aProgress(mrDoc.GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true); Fraction aZoom(1, 1); - sc::RowHeightContext aCxt(mrDoc.MaxRow(), mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev); sal_uInt64 nProgressStart = 0; for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab) { if (!ValidTab(nTab) || !mrDoc.maTabs[nTab]) continue; + sc::RowHeightContext aCxt(mrDoc.MaxRow(), mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev); SCCOL nEndCol = 0; SCROW nEndRow = mrDoc.MaxRow(); if (!bOnlyUsedRows || mrDoc.GetPrintArea(nTab, nEndCol, nEndRow)) diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index b42a8d36b5..8ae4ff6c4e 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -89,6 +89,7 @@ void sortAndRemoveDuplicates(std::vector<ScTypedStrData>& rStrings, bool bCaseSe std::vector<ScTypedStrData>::iterator it = std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseSensitive()); rStrings.erase(it, rStrings.end()); + std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessSortCaseSensitive()); } else { @@ -96,6 +97,7 @@ void sortAndRemoveDuplicates(std::vector<ScTypedStrData>& rStrings, bool bCaseSe std::vector<ScTypedStrData>::iterator it = std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseInsensitive()); rStrings.erase(it, rStrings.end()); + std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessSortCaseInsensitive()); } if (std::any_of(rStrings.begin(), rStrings.end(), [](ScTypedStrData& rString) { return rString.IsHiddenByFilter(); })) { diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index ff6d77b432..15bb28fe61 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6896,6 +6896,8 @@ void ScDocument::GetNotesInRange( const ScRangeList& rRangeList, std::vector<sc: const ScRange & rRange = rRangeList[i]; for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab ) { + if (!maTabs[nTab]) + continue; maTabs[nTab]->GetNotesInRange( rRange, rNotes ); } } @@ -6914,6 +6916,8 @@ bool ScDocument::ContainsNotesInRange( const ScRangeList& rRangeList ) const const ScRange & rRange = rRangeList[i]; for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab ) { + if (!maTabs[nTab]) + continue; bool bContainsNote = maTabs[nTab]->ContainsNotesInRange( rRange ); if(bContainsNote) return true; diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index acf0f27672..df50575589 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -22,7 +22,7 @@ #include <refupdatecontext.hxx> #include <sal/log.hxx> -#include <editeng/colritem.hxx> +#include <svx/DocumentColorHelper.hxx> #include <scitems.hxx> #include <datamapper.hxx> #include <docsh.hxx> @@ -188,17 +188,10 @@ std::set<Color> ScDocument::GetDocColors() { std::set<Color> aDocColors; ScDocumentPool *pPool = GetPool(); - const sal_uInt16 pAttribs[] = {ATTR_BACKGROUND, ATTR_FONT_COLOR}; - for (sal_uInt16 nAttrib : pAttribs) - { - for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(nAttrib)) - { - const SvxColorItem *pColorItem = static_cast<const SvxColorItem*>(pItem); - Color aColor( pColorItem->GetValue() ); - if (COL_AUTO != aColor) - aDocColors.insert(aColor); - } - } + + svx::DocumentColorHelper::queryColors<SvxBrushItem>(ATTR_BACKGROUND, pPool, aDocColors); + svx::DocumentColorHelper::queryColors<SvxColorItem>(ATTR_FONT_COLOR, pPool, aDocColors); + return aDocColors; } diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index afe2216b1a..6d7c5b0ac8 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -503,6 +503,7 @@ void ScTable::CopyToClip( nCol2 = ClampToAllocatedColumns(nCol2); + pTable->CreateColumnIfNotExists(nCol2); // prevent repeated resizing for ( SCCOL i = nCol1; i <= nCol2; i++) aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->CreateColumnIfNotExists(i)); // notes are handled at column level @@ -638,6 +639,9 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO { ScRange aOldRange( nCol1 - nDx, nRow1 - nDy, pTable->nTab, nCol2 - nDx, nRow2 - nDy, pTable->nTab); ScRange aNewRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ); + // Don't deduplicate when undoing or creating an Undo document! It would disallow correct undo + bool bUndoContext = rDocument.IsUndo() || pTable->rDocument.IsUndo(); + // Note that Undo documents use same pool as the original document bool bSameDoc = rDocument.GetStyleSheetPool() == pTable->rDocument.GetStyleSheetPool(); for(const auto& rxCondFormat : *pTable->mpCondFormatList) @@ -658,7 +662,7 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO aRefCxt.mnTabDelta = nTab - pTable->nTab; pNewFormat->UpdateReference(aRefCxt, true); - if (bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab)) + if (!bUndoContext && bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab)) { continue; } @@ -668,7 +672,7 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO { // Check if there is the same format in the destination // If there is, then simply expand its range - if (CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab)) + if (!bUndoContext && CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab)) { bDuplicate = true; break; @@ -1348,6 +1352,7 @@ void ScTable::CopyToTable( // can lead to repetitive splitting and rejoining of the same formula group, which can get // quadratically expensive with large groups. So do the grouping just once at the end. sc::DelayFormulaGroupingSwitch delayGrouping( pDestTab->rDocument, true ); + pDestTab->CreateColumnIfNotExists(ClampToAllocatedColumns(nCol2)); // avoid repeated resizing for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++) aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : nTempFlags, bMarked, pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal); diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index 62b9dbb9e0..f8a03dd4c7 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -1314,7 +1314,7 @@ void ScTable::GetBackColorArea(SCCOL& rStartCol, SCROW& /*rStartRow*/, const ScPatternAttr* pPattern = ColumnData(nCol).GetPattern(rEndRow + 1); const SvxBrushItem* pBackground = &pPattern->GetItem(ATTR_BACKGROUND); if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty() || - pBackground != pDefBackground) + (pBackground->GetColor() != COL_TRANSPARENT && pBackground != pDefBackground)) { bExtend = true; break; diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx index a46b09986b..5a569ef944 100644 --- a/sc/source/core/data/validat.cxx +++ b/sc/source/core/data/validat.cxx @@ -381,6 +381,9 @@ bool ScValidationData::DoError(weld::Window* pParent, const OUString& rInput, if ( eErrorStyle == SC_VALERR_MACRO ) return DoMacro(rPos, rInput, nullptr, pParent); + if (!bShowError) + return true; + // Output error message OUString aTitle = aErrorTitle; diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 63b1f09692..c9934c26ff 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -4738,6 +4738,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul pFunctionStack[0].eOp = ocNone; pFunctionStack[0].nSep = 0; size_t nFunction = 0; + size_t nHighWatermark = 0; short nBrackets = 0; bool bInArray = false; eLastOp = ocOpen; @@ -4757,6 +4758,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul ++nFunction; pFunctionStack[ nFunction ].eOp = eLastOp; pFunctionStack[ nFunction ].nSep = 0; + nHighWatermark = nFunction; } } break; @@ -4795,6 +4797,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul ++nFunction; pFunctionStack[ nFunction ].eOp = eOp; pFunctionStack[ nFunction ].nSep = 0; + nHighWatermark = nFunction; } } break; @@ -4825,6 +4828,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul ++nFunction; pFunctionStack[ nFunction ].eOp = eOp; pFunctionStack[ nFunction ].nSep = 0; + nHighWatermark = nFunction; } } break; @@ -4867,9 +4871,9 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul // Append a parameter for WEEKNUM, all 1.0 // Function is already closed, parameter count is nSep+1 size_t nFunc = nFunction + 1; - if (eOp == ocClose && - (pFunctionStack[ nFunc ].eOp == ocWeek && // 2nd week start - pFunctionStack[ nFunc ].nSep == 0)) + if (eOp == ocClose && nFunc <= nHighWatermark && + pFunctionStack[ nFunc ].nSep == 0 && + pFunctionStack[ nFunc ].eOp == ocWeek) // 2nd week start { if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) || !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0))) diff --git a/sc/source/core/tool/typedstrdata.cxx b/sc/source/core/tool/typedstrdata.cxx index e00c1bc18d..4e3f862ae3 100644 --- a/sc/source/core/tool/typedstrdata.cxx +++ b/sc/source/core/tool/typedstrdata.cxx @@ -34,8 +34,31 @@ bool ScTypedStrData::LessCaseSensitive::operator() (const ScTypedStrData& left, if (left.mbIsDate != right.mbIsDate) return left.mbIsDate < right.mbIsDate; - sal_Int32 nEqual = ScGlobal::GetCaseCollator().compareString( - left.maStrValue, right.maStrValue); + sal_Int32 nEqual + = ScGlobal::GetCaseTransliteration().compareString(left.maStrValue, right.maStrValue); + + if (!nEqual) + return left.mbIsHiddenByFilter < right.mbIsHiddenByFilter; + + return nEqual < 0; +} + +bool ScTypedStrData::LessSortCaseSensitive::operator() (const ScTypedStrData& left, const ScTypedStrData& right) const +{ + if (left.meStrType != right.meStrType) + return left.meStrType < right.meStrType; + + if (left.meStrType == Value) + { + if (left.mfValue == right.mfValue) + return left.mbIsHiddenByFilter < right.mbIsHiddenByFilter; + return left.mfValue < right.mfValue; + } + + if (left.mbIsDate != right.mbIsDate) + return left.mbIsDate < right.mbIsDate; + + sal_Int32 nEqual = ScGlobal::GetCaseCollator().compareString(left.maStrValue, right.maStrValue); if (!nEqual) return left.mbIsHiddenByFilter < right.mbIsHiddenByFilter; @@ -58,8 +81,31 @@ bool ScTypedStrData::LessCaseInsensitive::operator() (const ScTypedStrData& left if (left.mbIsDate != right.mbIsDate) return left.mbIsDate < right.mbIsDate; - sal_Int32 nEqual = ScGlobal::GetCollator().compareString( - left.maStrValue, right.maStrValue); + sal_Int32 nEqual + = ScGlobal::GetTransliteration().compareString(left.maStrValue, right.maStrValue); + + if (!nEqual) + return left.mbIsHiddenByFilter < right.mbIsHiddenByFilter; + + return nEqual < 0; +} + +bool ScTypedStrData::LessSortCaseInsensitive::operator() (const ScTypedStrData& left, const ScTypedStrData& right) const +{ + if (left.meStrType != right.meStrType) + return left.meStrType < right.meStrType; + + if (left.meStrType == Value) + { + if (left.mfValue == right.mfValue) + return left.mbIsHiddenByFilter < right.mbIsHiddenByFilter; + return left.mfValue < right.mfValue; + } + + if (left.mbIsDate != right.mbIsDate) + return left.mbIsDate < right.mbIsDate; + + sal_Int32 nEqual = ScGlobal::GetCaseCollator().compareString(left.maStrValue, right.maStrValue); if (!nEqual) return left.mbIsHiddenByFilter < right.mbIsHiddenByFilter; diff --git a/sc/source/filter/excel/xeroot.cxx b/sc/source/filter/excel/xeroot.cxx index ce281890f8..c1959767d9 100644 --- a/sc/source/filter/excel/xeroot.cxx +++ b/sc/source/filter/excel/xeroot.cxx @@ -317,8 +317,10 @@ uno::Sequence< beans::NamedValue > XclExpRoot::GenerateEncryptionData( std::u16s { rtlRandomPool aRandomPool = rtl_random_createPool (); sal_uInt8 pnDocId[16]; - rtl_random_getBytes( aRandomPool, pnDocId, 16 ); - + if (rtl_random_getBytes(aRandomPool, pnDocId, 16) != rtl_Random_E_None) + { + throw uno::RuntimeException("rtl_random_getBytes failed"); + } rtl_random_destroyPool( aRandomPool ); sal_uInt16 pnPasswd[16] = {}; diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 4158fa2c15..a70e4e08bd 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -564,7 +564,10 @@ void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData ) // generate the salt here rtlRandomPool aRandomPool = rtl_random_createPool (); - rtl_random_getBytes( aRandomPool, mpnSalt, 16 ); + if (rtl_random_getBytes(aRandomPool, mpnSalt, 16) != rtl_Random_E_None) + { + throw uno::RuntimeException("rtl_random_getBytes failed"); + } rtl_random_destroyPool( aRandomPool ); memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) ); diff --git a/sc/source/filter/html/htmlpars.cxx b/sc/source/filter/html/htmlpars.cxx index f5f8900815..be957b1851 100644 --- a/sc/source/filter/html/htmlpars.cxx +++ b/sc/source/filter/html/htmlpars.cxx @@ -61,6 +61,7 @@ #include <rangelst.hxx> #include <orcus/css_parser.hpp> +#include <boost/property_tree/json_parser.hpp> #include <com/sun/star/document/XDocumentProperties.hpp> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> @@ -71,6 +72,48 @@ using ::editeng::SvxBorderLine; using namespace ::com::sun::star; +namespace +{ +/// data-sheets-value from google sheets, value is a JSON. +void ParseDataSheetsValue(const OUString& rDataSheetsValue, std::optional<OUString>& rVal, std::optional<OUString>& rNum) +{ + // data-sheets-value from google sheets, value is a JSON. + OString aEncodedOption = rDataSheetsValue.toUtf8(); + const char* pEncodedOption = aEncodedOption.getStr(); + std::stringstream aStream(pEncodedOption); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + // The "1" key describes the original data type. + auto it = aTree.find("1"); + if (it != aTree.not_found()) + { + int nValueType = std::stoi(it->second.get_value<std::string>()); + switch (nValueType) + { + case 2: + { + // 2 is text. + // See SfxHTMLParser::GetTableDataOptionsValNum(), we leave the parse and a number + // language unspecified. + rNum = ";;@"; + break; + } + case 4: + { + // 4 is boolean. + it = aTree.find("4"); + if (it != aTree.not_found()) + { + rVal = OUString::fromUtf8(it->second.get_value<std::string>()); + } + rNum = ";;BOOLEAN"; + break; + } + } + } +} +} + ScHTMLStyles::ScHTMLStyles() : maEmpty() {} void ScHTMLStyles::add(const char* pElemName, size_t nElemName, const char* pClassName, size_t nClassName, @@ -978,6 +1021,11 @@ void ScHTMLLayoutParser::TableDataOn( HtmlImportInfo* pInfo ) mxActEntry->pNumStr = rOption.GetString(); } break; + case HtmlOptionId::DSVAL: + { + ParseDataSheetsValue(rOption.GetString(), mxActEntry->pValStr, mxActEntry->pNumStr); + } + break; default: break; } } @@ -2116,6 +2164,11 @@ void ScHTMLTable::DataOn( const HtmlImportInfo& rInfo ) } } break; + case HtmlOptionId::DSVAL: + { + ParseDataSheetsValue(rOption.GetString(), pValStr, pNumStr); + } + break; default: break; } } diff --git a/sc/source/filter/inc/htmlpars.hxx b/sc/source/filter/inc/htmlpars.hxx index fcdf6b4443..5b2d441098 100644 --- a/sc/source/filter/inc/htmlpars.hxx +++ b/sc/source/filter/inc/htmlpars.hxx @@ -149,6 +149,7 @@ class HTMLOption; typedef ::std::map<SCROW, SCROW> InnerMap; typedef ::std::map<sal_uInt16, InnerMap*> OuterMap; +/// HTML parser used during paste into Calc. class ScHTMLLayoutParser : public ScHTMLParser { private: @@ -575,6 +576,8 @@ public: Builds the table structure correctly, ignores extended formatting like pictures or column widths. + + Used during file load / import into Calc. */ class ScHTMLQueryParser : public ScHTMLParser { diff --git a/sc/source/filter/rtf/rtfparse.cxx b/sc/source/filter/rtf/rtfparse.cxx index b2d2b8c252..0617a86c62 100644 --- a/sc/source/filter/rtf/rtfparse.cxx +++ b/sc/source/filter/rtf/rtfparse.cxx @@ -101,8 +101,8 @@ inline void ScRTFParser::NextRow() bool ScRTFParser::SeekTwips( sal_uInt16 nTwips, SCCOL* pCol ) { - ScRTFColTwips::const_iterator it = aColTwips.find( nTwips ); - bool bFound = it != aColTwips.end(); + ScRTFColTwips::const_iterator it = aColTwips.lower_bound( nTwips ); + bool bFound = it != aColTwips.end() && *it == nTwips; sal_uInt16 nPos = it - aColTwips.begin(); *pCol = static_cast<SCCOL>(nPos); if ( bFound ) diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index 809ba8520e..a640d71cb2 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -3159,7 +3159,7 @@ void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInL { ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument(); const ScValidationData* pData = rDoc.GetValidationEntry( nValidation ); - if (pData && pData->HasErrMsg()) + if (pData) { // #i67990# don't use pLastPattern in EnterHandler const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() ); @@ -3200,6 +3200,7 @@ void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInL if (pData->DoError(pActiveViewSh->GetFrameWeld(), aString, aCursorPos)) bForget = true; // Do not take over input + } } } diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx index 6a1ef6a046..5f0599c888 100644 --- a/sc/source/ui/app/transobj.cxx +++ b/sc/source/ui/app/transobj.cxx @@ -312,28 +312,34 @@ bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUSt ScAddress aPos(nCol, nRow, nTab); const ScPatternAttr* pPattern = m_pDoc->GetPattern( nCol, nRow, nTab ); - ScTabEditEngine aEngine( *pPattern, m_pDoc->GetEditPool(), m_pDoc.get() ); - ScRefCellValue aCell(*m_pDoc, aPos); - if (aCell.getType() == CELLTYPE_EDIT) + if (pPattern) { - const EditTextObject* pObj = aCell.getEditText(); - aEngine.SetTextCurrentDefaults(*pObj); - } - else - { - SvNumberFormatter* pFormatter = m_pDoc->GetFormatTable(); - sal_uInt32 nNumFmt = pPattern->GetNumberFormat(pFormatter); - const Color* pColor; - OUString aText = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, *m_pDoc); - if (!aText.isEmpty()) - aEngine.SetTextCurrentDefaults(aText); - } + ScTabEditEngine aEngine(*pPattern, m_pDoc->GetEditPool(), m_pDoc.get()); + ScRefCellValue aCell(*m_pDoc, aPos); + if (aCell.getType() == CELLTYPE_EDIT) + { + const EditTextObject* pObj = aCell.getEditText(); + aEngine.SetTextCurrentDefaults(*pObj); + } + else + { + SvNumberFormatter* pFormatter = m_pDoc->GetFormatTable(); + sal_uInt32 nNumFmt = pPattern->GetNumberFormat(pFormatter); + const Color* pColor; + OUString aText + = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, *m_pDoc); + if (!aText.isEmpty()) + aEngine.SetTextCurrentDefaults(aText); + } - bOK = SetObject( &aEngine, - ((nFormat == SotClipboardFormatId::RTF) ? SCTRANS_TYPE_EDIT_RTF : - ((nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT) ? - SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT : SCTRANS_TYPE_EDIT_BIN)), - rFlavor ); + bOK = SetObject(&aEngine, + ((nFormat == SotClipboardFormatId::RTF) + ? SCTRANS_TYPE_EDIT_RTF + : ((nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT) + ? SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT + : SCTRANS_TYPE_EDIT_BIN)), + rFlavor); + } } else if ( ScImportExport::IsFormatSupported( nFormat ) || nFormat == SotClipboardFormatId::RTF || nFormat == SotClipboardFormatId::RICHTEXT ) diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx index 92e7096fc2..578c248b7f 100644 --- a/sc/source/ui/cctrl/checklistmenu.cxx +++ b/sc/source/ui/cctrl/checklistmenu.cxx @@ -171,14 +171,7 @@ void ScCheckListMenuControl::CreateDropDown() { const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); - // tdf#151820 The color used for the arrow head depends on the background color - Color aBackgroundColor = rStyleSettings.GetWindowColor(); - Color aSpinColor; - if (aBackgroundColor.IsDark()) - aSpinColor = rStyleSettings.GetLightColor(); - else - aSpinColor = rStyleSettings.GetDarkShadowColor(); - + Color aSpinColor = rStyleSettings.GetDialogTextColor(); int nWidth = (mxMenu->get_text_height() * 3) / 4; mxDropDown->SetOutputSizePixel(Size(nWidth, nWidth), /*bErase*/true, /*bAlphaMaskTransparent*/true); DecorationView aDecoView(mxDropDown.get()); diff --git a/sc/source/ui/navipi/navipi.cxx b/sc/source/ui/navipi/navipi.cxx index 5fc6fee821..ae95220eef 100644 --- a/sc/source/ui/navipi/navipi.cxx +++ b/sc/source/ui/navipi/navipi.cxx @@ -540,6 +540,7 @@ void ScNavigatorDlg::Notify( SfxBroadcaster&, const SfxHint& rHint ) m_xLbEntries->Refresh( ScContentId::GRAPHIC ); m_xLbEntries->Refresh( ScContentId::OLEOBJECT ); m_xLbEntries->Refresh( ScContentId::DRAWING ); + m_xLbEntries->Refresh( ScContentId::NOTE ); break; case SfxHintId::ScAreaLinksChanged: diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 3f4f6b219c..ddbc8e2507 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -1041,8 +1041,8 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow) mpAutoFilterPopup->setMemberSize(aFilterEntries.size()); for (auto it = aFilterEntries.begin(); it != aFilterEntries.end(); ++it) { - // tdf#140745 show (empty) entry on top of the checkbox list - if (it->GetString().isEmpty()) + // tdf#140745 show (empty) entry on top of the checkbox list if not hidden by filter + if (it->GetString().isEmpty() && !it->IsHiddenByFilter()) { const OUString& aStringVal = it->GetString(); const double aDoubleVal = it->GetValue(); @@ -1051,7 +1051,8 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow) bSelected = aSelectedString.count(aStringVal) > 0; else if (bQueryByNonEmpty) bSelected = false; - mpAutoFilterPopup->addMember(aStringVal, aDoubleVal, bSelected, it->IsHiddenByFilter()); + // it->IsHiddenByFilter() is always false here so no need to evaluate it + mpAutoFilterPopup->addMember(aStringVal, aDoubleVal, bSelected, false); aFilterEntries.maStrData.erase(it); break; } @@ -6168,10 +6169,16 @@ void ScGridWindow::DeleteCopySourceOverlay() void ScGridWindow::UpdateCopySourceOverlay() { - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); DeleteCopySourceOverlay(); @@ -6222,9 +6229,6 @@ void ScGridWindow::UpdateCopySourceOverlay() xOverlayManager->add(*pDashedBorder); mpOOSelectionBorder->append(std::move(pDashedBorder)); } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } static std::vector<tools::Rectangle> convertPixelToLogical( @@ -6415,10 +6419,16 @@ void ScGridWindow::UpdateCursorOverlay() { ScDocument& rDoc = mrViewData.GetDocument(); - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); // Existing OverlayObjects may be transformed in later versions. // For now, just re-create them. @@ -6577,9 +6587,6 @@ void ScGridWindow::UpdateCursorOverlay() } } } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } void ScGridWindow::GetCellSelection(std::vector<tools::Rectangle>& rLogicRects) @@ -6601,10 +6608,16 @@ void ScGridWindow::DeleteSelectionOverlay() void ScGridWindow::UpdateSelectionOverlay() { - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); DeleteSelectionOverlay(); std::vector<tools::Rectangle> aRects; @@ -6676,9 +6689,6 @@ void ScGridWindow::UpdateSelectionOverlay() ScInputHandler::SendReferenceMarks(pViewShell, aReferenceMarks); } } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } void ScGridWindow::UpdateHighlightOverlay() @@ -6744,10 +6754,16 @@ void ScGridWindow::DeleteAutoFillOverlay() void ScGridWindow::UpdateAutoFillOverlay() { - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); DeleteAutoFillOverlay(); @@ -6826,9 +6842,6 @@ void ScGridWindow::UpdateAutoFillOverlay() mpOOAutoFill.reset(new sdr::overlay::OverlayObjectList); mpOOAutoFill->append(std::move(pOverlay)); } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } void ScGridWindow::DeleteDragRectOverlay() @@ -6841,10 +6854,16 @@ void ScGridWindow::UpdateDragRectOverlay() bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet( comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs); - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); DeleteDragRectOverlay(); @@ -6997,9 +7016,6 @@ void ScGridWindow::UpdateDragRectOverlay() pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aRectsString); } } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } void ScGridWindow::DeleteHeaderOverlay() @@ -7009,10 +7025,16 @@ void ScGridWindow::DeleteHeaderOverlay() void ScGridWindow::UpdateHeaderOverlay() { - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); DeleteHeaderOverlay(); @@ -7043,9 +7065,6 @@ void ScGridWindow::UpdateHeaderOverlay() mpOOHeader->append(std::move(pOverlay)); } } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } void ScGridWindow::DeleteShrinkOverlay() @@ -7055,10 +7074,16 @@ void ScGridWindow::DeleteShrinkOverlay() void ScGridWindow::UpdateShrinkOverlay() { - MapMode aDrawMode = GetDrawMapMode(); - MapMode aOldMode = GetMapMode(); - if ( aOldMode != aDrawMode ) - SetMapMode( aDrawMode ); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); + if (aOldMode != aDrawMode) + SetMapMode(aDrawMode); DeleteShrinkOverlay(); @@ -7110,9 +7135,6 @@ void ScGridWindow::UpdateShrinkOverlay() mpOOShrink->append(std::move(pOverlay)); } } - - if ( aOldMode != aDrawMode ) - SetMapMode( aOldMode ); } void ScGridWindow::DeleteSparklineGroupOverlay() @@ -7122,9 +7144,14 @@ void ScGridWindow::DeleteSparklineGroupOverlay() void ScGridWindow::UpdateSparklineGroupOverlay() { - MapMode aDrawMode = GetDrawMapMode(); - - MapMode aOldMode = GetMapMode(); + const MapMode aDrawMode = GetDrawMapMode(); + const MapMode aOldMode = GetMapMode(); + comphelper::ScopeGuard aMapModeGuard( + [&aOldMode, &aDrawMode, this] { + if (aOldMode != aDrawMode) + SetMapMode(aOldMode); + } + ); if (aOldMode != aDrawMode) SetMapMode(aDrawMode); @@ -7173,9 +7200,6 @@ void ScGridWindow::UpdateSparklineGroupOverlay() } } } - - if (aOldMode != aDrawMode) - SetMapMode(aOldMode); } // #i70788# central method to get the OverlayManager safely |