summaryrefslogtreecommitdiffstats
path: root/sc
diff options
context:
space:
mode:
Diffstat (limited to 'sc')
-rw-r--r--sc/CppunitTest_sc_parallelism.mk81
-rw-r--r--sc/Module_sc.mk1
-rw-r--r--sc/qa/extras/scpdfexport.cxx14
-rw-r--r--sc/qa/extras/testdocuments/tdf159094.odsbin0 -> 10716 bytes
-rwxr-xr-xsc/qa/uitest/pasteSpecial/tdf160765.py75
-rw-r--r--sc/qa/unit/data/ods/tdf160368.odsbin0 -> 25405 bytes
-rw-r--r--sc/qa/unit/data/ods/tdf160369_groupshape.odsbin0 -> 97614 bytes
-rw-r--r--sc/qa/unit/parallelism.cxx88
-rw-r--r--sc/qa/unit/scshapetest.cxx68
-rw-r--r--sc/qa/unit/ucalc_parallelism.cxx3
-rw-r--r--sc/source/core/data/documen9.cxx9
-rw-r--r--sc/source/core/data/drwlayer.cxx4
-rw-r--r--sc/source/core/data/formulacell.cxx11
-rw-r--r--sc/source/core/data/table1.cxx16
-rw-r--r--sc/source/filter/html/htmlpars.cxx134
-rw-r--r--sc/source/filter/inc/htmlpars.hxx8
-rw-r--r--sc/source/filter/xml/xmlexprt.cxx41
-rw-r--r--sc/source/ui/docshell/impex.cxx6
-rw-r--r--sc/source/ui/inc/tabview.hxx2
-rw-r--r--sc/source/ui/miscdlgs/solveroptions.cxx2
-rw-r--r--sc/source/ui/unoobj/docuno.cxx192
-rw-r--r--sc/source/ui/view/output2.cxx14
-rw-r--r--sc/source/ui/view/tabview.cxx22
-rw-r--r--sc/source/ui/view/tabview4.cxx45
-rw-r--r--sc/source/ui/view/viewfun3.cxx3
25 files changed, 714 insertions, 125 deletions
diff --git a/sc/CppunitTest_sc_parallelism.mk b/sc/CppunitTest_sc_parallelism.mk
new file mode 100644
index 0000000000..f7f3cc9fa7
--- /dev/null
+++ b/sc/CppunitTest_sc_parallelism.mk
@@ -0,0 +1,81 @@
+# -*- 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_parallelism))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_parallelism))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sc_parallelism, \
+ sc/qa/unit/parallelism \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sc_parallelism, \
+ boost_headers \
+ mdds_headers \
+ libxml2 \
+ $(call gb_Helper_optional,OPENCL, \
+ clew) \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sc_parallelism, \
+ basegfx \
+ comphelper \
+ cppu \
+ cppuhelper \
+ i18nlangtag \
+ sal \
+ sax \
+ sc \
+ scqahelper \
+ sfx \
+ subsequenttest \
+ svl \
+ svx \
+ svxcore \
+ test \
+ tl \
+ unotest \
+ utl \
+ vcl \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sc_parallelism,\
+ -I$(SRCDIR)/sc/source/ui/inc \
+ -I$(SRCDIR)/sc/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sc_parallelism,\
+ offapi \
+ udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sc_parallelism,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,sc_parallelism))
+
+$(eval $(call gb_CppunitTest_use_ure,sc_parallelism))
+
+$(eval $(call gb_CppunitTest_use_vcl,sc_parallelism))
+
+$(eval $(call gb_CppunitTest_use_rdb,sc_parallelism,services))
+
+$(eval $(call gb_CppunitTest_use_components,sc_parallelism))
+
+$(eval $(call gb_CppunitTest_use_configuration,sc_parallelism))
+
+$(eval $(call gb_CppunitTest_add_arguments,sc_parallelism, \
+ -env:arg-env=$(gb_Helper_LIBRARY_PATH_VAR)"$$$${$(gb_Helper_LIBRARY_PATH_VAR)+=$$$$$(gb_Helper_LIBRARY_PATH_VAR)}" \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index a01c9115f3..3281184d82 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -62,6 +62,7 @@ $(eval $(call gb_Module_add_check_targets,sc,\
CppunitTest_sc_core \
CppunitTest_sc_dataprovider \
CppunitTest_sc_cache_test \
+ CppunitTest_sc_parallelism \
CppunitTest_sc_shapetest \
))
endif
diff --git a/sc/qa/extras/scpdfexport.cxx b/sc/qa/extras/scpdfexport.cxx
index bcca563ec9..78084b30b3 100644
--- a/sc/qa/extras/scpdfexport.cxx
+++ b/sc/qa/extras/scpdfexport.cxx
@@ -58,6 +58,7 @@ private:
// unit tests
public:
+ void testMediaShapeScreen_Tdf159094();
void testExportRange_Tdf120161();
void testExportFitToPage_Tdf103516();
void testUnoCommands_Tdf120161();
@@ -69,6 +70,7 @@ public:
void testForcepoint97();
CPPUNIT_TEST_SUITE(ScPDFExportTest);
+ CPPUNIT_TEST(testMediaShapeScreen_Tdf159094);
CPPUNIT_TEST(testExportRange_Tdf120161);
CPPUNIT_TEST(testExportFitToPage_Tdf103516);
CPPUNIT_TEST(testUnoCommands_Tdf120161);
@@ -199,6 +201,18 @@ void ScPDFExportTest::setFont(ScFieldEditEngine& rEE, sal_Int32 nStart, sal_Int3
rEE.QuickSetAttribs(aItemSet, aSel);
}
+void ScPDFExportTest::testMediaShapeScreen_Tdf159094()
+{
+ loadFromFile(u"tdf159094.ods");
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+
+ // A1:B8
+ ScRange aRange(0, 0, 0, 1, 7, 0);
+
+ // Without the fix, this test would crash on export media file to pdf
+ exportToPDF(xModel, aRange);
+}
+
// Selection was not taken into account during export into PDF
void ScPDFExportTest::testExportRange_Tdf120161()
{
diff --git a/sc/qa/extras/testdocuments/tdf159094.ods b/sc/qa/extras/testdocuments/tdf159094.ods
new file mode 100644
index 0000000000..c267b21521
--- /dev/null
+++ b/sc/qa/extras/testdocuments/tdf159094.ods
Binary files differ
diff --git a/sc/qa/uitest/pasteSpecial/tdf160765.py b/sc/qa/uitest/pasteSpecial/tdf160765.py
new file mode 100755
index 0000000000..0b56be4c2d
--- /dev/null
+++ b/sc/qa/uitest/pasteSpecial/tdf160765.py
@@ -0,0 +1,75 @@
+# -*- 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 libreoffice.calc.document import get_cell_by_position
+from libreoffice.uno.propertyvalue import mkPropertyValues
+from uitest.uihelper.calc import enter_text_to_cell
+from libreoffice.calc.paste_special import reset_default_values
+
+class tdf160765(UITestCase):
+ def test_tdf160765_undo_paste_comment(self):
+ with self.ui_test.create_doc_in_start_center("calc") as document:
+ xGridWin = self.xUITest.getTopFocusWindow().getChild("grid_window")
+
+ # Write text to cell A1 and B1
+ enter_text_to_cell(xGridWin, "A1", "A1 sample text")
+ enter_text_to_cell(xGridWin, "B1", "B1 sample text")
+
+ # Insert a comment in cell B1
+ xArgs = mkPropertyValues({"Text": "Comment 1"})
+ self.xUITest.executeCommandWithParameters(".uno:InsertAnnotation", xArgs)
+
+ # Insert a comment in cell A2
+ xGridWin.executeAction("SELECT", mkPropertyValues({"CELL":"A2"}))
+ xArgs = mkPropertyValues({"Text": "Comment 2"})
+ self.xUITest.executeCommandWithParameters(".uno:InsertAnnotation", xArgs)
+
+ # Copy cell A2 to clipboard
+ xGridWin.executeAction("SELECT", mkPropertyValues({"CELL": "A2"}))
+ self.xUITest.executeCommand(".uno:Copy")
+
+ # Set cursor to cells and paste data using special options (check only comments)
+ targetCells = ["A1", "B1"]
+ for index, targetCell in enumerate(targetCells):
+ xGridWin.executeAction("SELECT", mkPropertyValues({"CELL": targetCell}))
+ with self.ui_test.execute_dialog_through_command(".uno:PasteSpecial") as xPasteSpecialDlg:
+ reset_default_values(self, xPasteSpecialDlg)
+ xDateTimeChkBox = xPasteSpecialDlg.getChild("datetime")
+ xDateTimeChkBox.executeAction("CLICK", tuple())
+ xTextChkBox = xPasteSpecialDlg.getChild("text")
+ xTextChkBox.executeAction("CLICK", tuple())
+ xNumbersChkBox = xPasteSpecialDlg.getChild("numbers")
+ xNumbersChkBox.executeAction("CLICK", tuple())
+ xCommentsChkBox = xPasteSpecialDlg.getChild("comments")
+ xCommentsChkBox.executeAction("CLICK", tuple())
+
+ # Undo both inserted comments
+ self.xUITest.executeCommand(".uno:Undo")
+ # Without the fix in place, this test would have failed with
+ # AssertionError: 'Comment 1' != ''
+ # i.e., the cell does not contain any comment
+ self.assertEqual("Comment 1", get_cell_by_position(document, 0, 1, 0).Annotation.String)
+ self.xUITest.executeCommand(".uno:Undo")
+ self.assertEqual("", get_cell_by_position(document, 0, 0, 0).Annotation.String)
+
+ # Redo both inserted comments
+ self.xUITest.executeCommand(".uno:Redo")
+ # Without the fix in place, this test would have failed with
+ # AssertionError: 'Comment 2' != ''
+ # i.e., the cell does not contain the restored comment
+ self.assertEqual("Comment 2", get_cell_by_position(document, 0, 0, 0).Annotation.String)
+ self.xUITest.executeCommand(".uno:Redo")
+ # Without the fix in place, this test would have failed with
+ # AssertionError: 'Comment 2' != ''
+ # i.e., the cell does not contain the restored comment
+ self.assertEqual("Comment 2", get_cell_by_position(document, 0, 0, 0).Annotation.String)
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sc/qa/unit/data/ods/tdf160368.ods b/sc/qa/unit/data/ods/tdf160368.ods
new file mode 100644
index 0000000000..f9da81d278
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf160368.ods
Binary files differ
diff --git a/sc/qa/unit/data/ods/tdf160369_groupshape.ods b/sc/qa/unit/data/ods/tdf160369_groupshape.ods
new file mode 100644
index 0000000000..8c26fe8ce5
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf160369_groupshape.ods
Binary files differ
diff --git a/sc/qa/unit/parallelism.cxx b/sc/qa/unit/parallelism.cxx
new file mode 100644
index 0000000000..0ced71c442
--- /dev/null
+++ b/sc/qa/unit/parallelism.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 <sal/config.h>
+
+#include "helper/qahelper.hxx"
+
+#include <document.hxx>
+#include <formulagroup.hxx>
+
+#include <officecfg/Office/Calc.hxx>
+
+using namespace sc;
+
+// test-suite suitable for loading documents to test parallelism in
+// with access only to exported symbols
+
+class ScParallelismTest : public ScModelTestBase
+{
+public:
+ ScParallelismTest()
+ : ScModelTestBase("sc/qa/unit/data")
+ {
+ }
+
+ virtual void setUp() override;
+ virtual void tearDown() override;
+
+private:
+ bool getThreadingFlag() const;
+ void setThreadingFlag(bool bSet);
+
+ bool m_bThreadingFlagCfg;
+};
+
+bool ScParallelismTest::getThreadingFlag() const
+{
+ return officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::
+ get();
+}
+
+void ScParallelismTest::setThreadingFlag(bool bSet)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> xBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::set(
+ bSet, xBatch);
+ xBatch->commit();
+}
+
+void ScParallelismTest::setUp()
+{
+ ScModelTestBase::setUp();
+
+ sc::FormulaGroupInterpreter::disableOpenCL_UnitTestsOnly();
+
+ m_bThreadingFlagCfg = getThreadingFlag();
+ if (!m_bThreadingFlagCfg)
+ setThreadingFlag(true);
+}
+
+void ScParallelismTest::tearDown()
+{
+ // Restore threading flag
+ if (!m_bThreadingFlagCfg)
+ setThreadingFlag(false);
+
+ ScModelTestBase::tearDown();
+}
+
+// Dependency range in this document was detected as I9:I9 instead of expected I9:I367
+CPPUNIT_TEST_FIXTURE(ScParallelismTest, testTdf160368)
+{
+ createScDoc("ods/tdf160368.ods");
+ ScDocShell* pDocSh = getScDocShell();
+ // without fix: ScFormulaCell::MaybeInterpret(): Assertion `!rDocument.IsThreadedGroupCalcInProgress()' failed.
+ pDocSh->DoHardRecalc();
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sc/qa/unit/scshapetest.cxx b/sc/qa/unit/scshapetest.cxx
index 5e48270053..c5b4b098c8 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -1231,6 +1231,74 @@ CPPUNIT_TEST_FIXTURE(ScShapeTest, testTdf160003_copy_page_anchored)
CPPUNIT_ASSERT_EQUAL(size_t(1), pPage->GetObjCount());
}
+CPPUNIT_TEST_FIXTURE(ScShapeTest, testTdf160369_groupshape)
+{
+ // The document contains a group spanning range C5:F12. It is currently anchored to page to
+ // make sure its position does not change. When the group was anchored 'To Cell' and rows or
+ // columns were hidden before the group, saving changed the anchor position and anchor
+ // offset. This happened both with using 'resize with cell' and not.
+ createScDoc("ods/tdf160369_groupshape.ods");
+
+ // Get document and group object
+ ScDocument* pDoc = getScDoc();
+ SdrObject* pObj = lcl_getSdrObjectWithAssert(*pDoc, 0);
+
+ // Anchor group 'To Cell (resize with cell)' to prepare the test.
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *pDoc, 0 /*SCTAB*/, true /*bResizeWithCell*/);
+
+ // Hide rows 3 and 4 (UI number), which are before the group
+ // Hide column D, which is inside the group
+ pDoc->SetRowHidden(2, 3, 0, true);
+ pDoc->SetDrawPageSize(0); // trigger recalcpos, otherwise shapes are not changed
+ pDoc->SetColHidden(3, 3, 0, true);
+ pDoc->SetDrawPageSize(0);
+
+ // Get geometry of the group
+ ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj);
+ ScAddress aOrigStart = (*pObjData).maStart;
+ ScAddress aOrigEnd = (*pObjData).maEnd;
+ tools::Rectangle aOrigRect = pObj->GetSnapRect();
+
+ // Save document but do not reload. Saving alone had already caused the error.
+ save("calc8");
+
+ // Get geometry of the group again
+ ScDrawObjData* pAfterObjData = ScDrawLayer::GetObjData(pObj);
+ ScAddress aAfterStart = (*pAfterObjData).maStart;
+ ScAddress aAfterEnd = (*pAfterObjData).maEnd;
+ tools::Rectangle aAfterRect = pObj->GetSnapRect();
+
+ // verify Orig equals After
+ CPPUNIT_ASSERT_EQUAL(aOrigStart, aAfterStart);
+ CPPUNIT_ASSERT_EQUAL(aOrigEnd, aAfterEnd);
+ CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aOrigRect, aAfterRect, 1);
+
+ // The same but with saveAndReload.
+ createScDoc("ods/tdf160369_groupshape.ods");
+ pDoc = getScDoc();
+ pObj = lcl_getSdrObjectWithAssert(*pDoc, 0);
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *pDoc, 0 /*SCTAB*/, true /*bResizeWithCell*/);
+ pDoc->SetRowHidden(2, 3, 0, true);
+ pDoc->SetDrawPageSize(0); // trigger recalcpos, otherwise shapes are not changed
+ pDoc->SetColHidden(3, 3, 0, true);
+ pDoc->SetDrawPageSize(0);
+
+ saveAndReload("calc8");
+
+ // Verify geometry is same as before save
+ pDoc = getScDoc();
+ pObj = lcl_getSdrObjectWithAssert(*pDoc, 0);
+ pAfterObjData = ScDrawLayer::GetObjData(pObj);
+ aAfterStart = (*pAfterObjData).maStart;
+ aAfterEnd = (*pAfterObjData).maEnd;
+ aAfterRect = pObj->GetSnapRect();
+
+ // verify Orig equals After
+ CPPUNIT_ASSERT_EQUAL(aOrigStart, aAfterStart);
+ CPPUNIT_ASSERT_EQUAL(aOrigEnd, aAfterEnd);
+ CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aOrigRect, aAfterRect, 1);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/ucalc_parallelism.cxx b/sc/qa/unit/ucalc_parallelism.cxx
index 2ee55708db..8996fb5fdc 100644
--- a/sc/qa/unit/ucalc_parallelism.cxx
+++ b/sc/qa/unit/ucalc_parallelism.cxx
@@ -21,6 +21,9 @@
using namespace css;
using namespace css::uno;
+// test-suite suitable for creating documents to test parallelism in
+// with access to internal unexported symbols
+
class ScParallelismTest : public ScUcalcTestBase
{
public:
diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
index a9f04943c0..ee72637fa9 100644
--- a/sc/source/core/data/documen9.cxx
+++ b/sc/source/core/data/documen9.cxx
@@ -440,13 +440,8 @@ bool ScDocument::IsPrintEmpty( SCCOL nStartCol, SCROW nStartRow,
// keep vertical part of aMMRect, only update horizontal position
aMMRect = *pLastMM;
- tools::Long nLeft = 0;
- SCCOL i;
- for (i=0; i<nStartCol; i++)
- nLeft += GetColWidth(i,nTab);
- tools::Long nRight = nLeft;
- for (i=nStartCol; i<=nEndCol; i++)
- nRight += GetColWidth(i,nTab);
+ tools::Long nLeft = GetColWidth(0, nStartCol-1, nTab);
+ tools::Long nRight = nLeft + GetColWidth(nStartCol,nEndCol, nTab);
aMMRect.SetLeft(o3tl::convert(nLeft, o3tl::Length::twip, o3tl::Length::mm100));
aMMRect.SetRight(o3tl::convert(nRight, o3tl::Length::twip, o3tl::Length::mm100));
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index d5f2cc09b9..d03f3572dc 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -1055,6 +1055,10 @@ void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rDat
UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1,
true /*bUseLogicRect*/);
}
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ // nothing to do.
+ }
else
{
// In case there are hidden rows or cols, versions 7.0 and earlier have written width and
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index f278492b09..93d712d106 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -4607,10 +4607,17 @@ struct ScDependantsCalculator
continue;
}
+ SCROW nFirstRefStartRow = bIsRef1RowRel ? aAbs.aStart.Row() + mnStartOffset : aAbs.aStart.Row();
+ SCROW nLastRefEndRow = bIsRef2RowRel ? aAbs.aEnd.Row() + mnEndOffset : aAbs.aEnd.Row();
+
+ SCROW nFirstRefEndRow = bIsRef1RowRel ? aAbs.aStart.Row() + mnEndOffset : aAbs.aStart.Row();
+ SCROW nLastRefStartRow = bIsRef2RowRel ? aAbs.aEnd.Row() + mnStartOffset : aAbs.aEnd.Row();
+
// The first row that will be referenced through the doubleref.
- SCROW nFirstRefRow = bIsRef1RowRel ? aAbs.aStart.Row() + mnStartOffset : aAbs.aStart.Row();
+ SCROW nFirstRefRow = std::min(nFirstRefStartRow, nLastRefStartRow);
// The last row that will be referenced through the doubleref.
- SCROW nLastRefRow = bIsRef2RowRel ? aAbs.aEnd.Row() + mnEndOffset : aAbs.aEnd.Row();
+ SCROW nLastRefRow = std::max(nLastRefEndRow, nFirstRefEndRow);
+
// Number of rows to be evaluated from nFirstRefRow.
SCROW nArrayLength = nLastRefRow - nFirstRefRow + 1;
assert(nArrayLength > 0);
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 93d023f962..4df5d92ec5 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2091,17 +2091,19 @@ void ScTable::ExtendPrintArea( OutputDevice* pDev,
else
{
// These columns are visible. Check for empty columns.
- for (SCCOL j = i; j <= nLastCol; ++j)
+ SCCOL nEmptyCount = 0;
+ SCCOL j = i;
+ for (; j <= nLastCol; ++j)
{
if ( j >= aCol.size() )
- {
- aSkipCols.setTrue( j, rDocument.MaxCol() );
break;
- }
- if (aCol[j].GetCellCount() == 0)
- // empty
- aSkipCols.setTrue(j,j);
+ if (aCol[j].GetCellCount() == 0) // empty
+ nEmptyCount++;
}
+ if (nEmptyCount)
+ aSkipCols.setTrue(i,i+nEmptyCount);
+ if ( j >= aCol.size() )
+ aSkipCols.setTrue( j, rDocument.MaxCol() );
}
i = nLastCol;
}
diff --git a/sc/source/filter/html/htmlpars.cxx b/sc/source/filter/html/htmlpars.cxx
index c9d53d93be..c6507bd54e 100644
--- a/sc/source/filter/html/htmlpars.cxx
+++ b/sc/source/filter/html/htmlpars.cxx
@@ -301,7 +301,7 @@ ScHTMLLayoutParser::ScHTMLLayoutParser(
aPageSize( aPageSizeP ),
aBaseURL(std::move( _aBaseURL )),
xLockedList( new ScRangeList ),
- pLocalColOffset( new ScHTMLColOffset ),
+ xLocalColOffset( new ScHTMLColOffset ),
nFirstTableCell(0),
nTableLevel(0),
nTable(0),
@@ -317,20 +317,15 @@ ScHTMLLayoutParser::ScHTMLLayoutParser(
bInCell( false ),
bInTitle( false )
{
- MakeColNoRef( pLocalColOffset, 0, 0, 0, 0 );
+ MakeColNoRef( xLocalColOffset.get(), 0, 0, 0, 0 );
MakeColNoRef( &maColOffset, 0, 0, 0, 0 );
}
ScHTMLLayoutParser::~ScHTMLLayoutParser()
{
- while ( !aTableStack.empty() )
- {
- ScHTMLTableStackEntry * pS = aTableStack.top().get();
- if ( pS->pLocalColOffset != pLocalColOffset )
- delete pS->pLocalColOffset;
+ while (!aTableStack.empty())
aTableStack.pop();
- }
- delete pLocalColOffset;
+ xLocalColOffset.reset();
if ( pTables )
{
for( const auto& rEntry : *pTables)
@@ -676,8 +671,8 @@ void ScHTMLLayoutParser::Adjust()
SkipLocked(pE.get(), false);
if ( pE->nCol != nColBeforeSkip )
{
- SCCOL nCount = static_cast<SCCOL>(maColOffset.size());
- if ( nCount <= pE->nCol )
+ size_t nCount = maColOffset.size();
+ if ( nCount <= o3tl::make_unsigned(pE->nCol) )
{
pE->nOffset = static_cast<sal_uInt16>(maColOffset[nCount-1]);
MakeCol( &maColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
@@ -713,9 +708,9 @@ sal_uInt16 ScHTMLLayoutParser::GetWidth( const ScEEParseEntry* pE )
return pE->nWidth;
sal_Int32 nTmp = std::min( static_cast<sal_Int32>( pE->nCol -
nColCntStart + pE->nColOverlap),
- static_cast<sal_Int32>( pLocalColOffset->size() - 1));
+ static_cast<sal_Int32>( xLocalColOffset->size() - 1));
SCCOL nPos = (nTmp < 0 ? 0 : static_cast<SCCOL>(nTmp));
- sal_uInt16 nOff2 = static_cast<sal_uInt16>((*pLocalColOffset)[nPos]);
+ sal_uInt16 nOff2 = static_cast<sal_uInt16>((*xLocalColOffset)[nPos]);
if ( pE->nOffset < nOff2 )
return nOff2 - pE->nOffset;
return 0;
@@ -723,28 +718,27 @@ sal_uInt16 ScHTMLLayoutParser::GetWidth( const ScEEParseEntry* pE )
void ScHTMLLayoutParser::SetWidths()
{
- SCCOL nCol;
if ( !nTableWidth )
nTableWidth = static_cast<sal_uInt16>(aPageSize.Width());
SCCOL nColsPerRow = nMaxCol - nColCntStart;
if ( nColsPerRow <= 0 )
nColsPerRow = 1;
- if ( pLocalColOffset->size() <= 2 )
+ if ( xLocalColOffset->size() <= 2 )
{ // Only PageSize, there was no width setting
sal_uInt16 nWidth = nTableWidth / static_cast<sal_uInt16>(nColsPerRow);
sal_uInt16 nOff = nColOffsetStart;
- pLocalColOffset->clear();
- for ( nCol = 0; nCol <= nColsPerRow; ++nCol, nOff = nOff + nWidth )
+ xLocalColOffset->clear();
+ for (int nCol = 0; nCol <= nColsPerRow; ++nCol, nOff = nOff + nWidth)
{
- MakeColNoRef( pLocalColOffset, nOff, 0, 0, 0 );
+ MakeColNoRef( xLocalColOffset.get(), nOff, 0, 0, 0 );
}
- nTableWidth = static_cast<sal_uInt16>(pLocalColOffset->back() - pLocalColOffset->front());
+ nTableWidth = static_cast<sal_uInt16>(xLocalColOffset->back() - xLocalColOffset->front());
for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
{
auto& pE = maList[ i ];
if ( pE->nTab == nTable )
{
- pE->nOffset = static_cast<sal_uInt16>((*pLocalColOffset)[pE->nCol - nColCntStart]);
+ pE->nOffset = static_cast<sal_uInt16>((*xLocalColOffset)[pE->nCol - nColCntStart]);
pE->nWidth = 0; // to be recalculated later
}
}
@@ -764,7 +758,7 @@ void ScHTMLLayoutParser::SetWidths()
auto& pE = maList[ i ];
if ( pE->nTab == nTable && pE->nWidth )
{
- nCol = pE->nCol - nColCntStart;
+ SCCOL nCol = pE->nCol - nColCntStart;
if ( nCol < nColsPerRow )
{
if ( pE->nColOverlap == 1 )
@@ -801,7 +795,7 @@ void ScHTMLLayoutParser::SetWidths()
}
sal_uInt16 nWidths = 0;
sal_uInt16 nUnknown = 0;
- for ( nCol = 0; nCol < nColsPerRow; nCol++ )
+ for (SCCOL nCol = 0; nCol < nColsPerRow; nCol++)
{
if ( pWidths[nCol] )
nWidths = nWidths + pWidths[nCol];
@@ -813,51 +807,59 @@ void ScHTMLLayoutParser::SetWidths()
sal_uInt16 nW = ((nWidths < nTableWidth) ?
((nTableWidth - nWidths) / nUnknown) :
(nTableWidth / nUnknown));
- for ( nCol = 0; nCol < nColsPerRow; nCol++ )
+ for (SCCOL nCol = 0; nCol < nColsPerRow; nCol++)
{
if ( !pWidths[nCol] )
pWidths[nCol] = nW;
}
}
- for ( nCol = 1; nCol <= nColsPerRow; nCol++ )
+ for (SCCOL nCol = 1; nCol <= nColsPerRow; nCol++)
{
pOffsets[nCol] = pOffsets[nCol-1] + pWidths[nCol-1];
}
- pLocalColOffset->clear();
- for ( nCol = 0; nCol <= nColsPerRow; nCol++ )
+ xLocalColOffset->clear();
+ for (SCCOL nCol = 0; nCol <= nColsPerRow; nCol++)
{
- MakeColNoRef( pLocalColOffset, pOffsets[nCol], 0, 0, 0 );
+ MakeColNoRef( xLocalColOffset.get(), pOffsets[nCol], 0, 0, 0 );
}
nTableWidth = pOffsets[nColsPerRow] - pOffsets[0];
for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
{
auto& pE = maList[ i ];
- if ( pE->nTab == nTable )
+ if (pE->nTab != nTable)
+ continue;
+ SCCOL nCol = pE->nCol - nColCntStart;
+ OSL_ENSURE( nCol < nColsPerRow, "ScHTMLLayoutParser::SetWidths: column overflow" );
+ if (nCol >= nColsPerRow)
+ continue;
+ if (nCol < 0)
{
- nCol = pE->nCol - nColCntStart;
- OSL_ENSURE( nCol < nColsPerRow, "ScHTMLLayoutParser::SetWidths: column overflow" );
- if ( nCol < nColsPerRow )
- {
- pE->nOffset = pOffsets[nCol];
- nCol = nCol + pE->nColOverlap;
- if ( nCol > nColsPerRow )
- nCol = nColsPerRow;
- pE->nWidth = pOffsets[nCol] - pE->nOffset;
- }
+ SAL_WARN("sc", "negative offset: " << nCol);
+ continue;
}
+ pE->nOffset = pOffsets[nCol];
+ nCol = nCol + pE->nColOverlap;
+ if ( nCol > nColsPerRow )
+ nCol = nColsPerRow;
+ if (nCol < 0)
+ {
+ SAL_WARN("sc", "negative offset: " << nCol);
+ continue;
+ }
+ pE->nWidth = pOffsets[nCol] - pE->nOffset;
}
}
}
- if ( !pLocalColOffset->empty() )
+ if ( !xLocalColOffset->empty() )
{
- sal_uInt16 nMax = static_cast<sal_uInt16>(pLocalColOffset->back());
+ sal_uInt16 nMax = static_cast<sal_uInt16>(xLocalColOffset->back());
if ( aPageSize.Width() < nMax )
aPageSize.setWidth( nMax );
if (nTableLevel == 0)
{
// Local table is very outer table, create missing offsets.
- for (auto it = pLocalColOffset->begin(); it != pLocalColOffset->end(); ++it)
+ for (auto it = xLocalColOffset->begin(); it != xLocalColOffset->end(); ++it)
{
// Only exact offsets, do not use MakeColNoRef().
maColOffset.insert(*it);
@@ -891,15 +893,15 @@ void ScHTMLLayoutParser::Colonize( ScEEParseEntry* pE )
if ( nCol < pE->nCol )
{ // Replaced
nCol = pE->nCol - nColCntStart;
- SCCOL nCount = static_cast<SCCOL>(pLocalColOffset->size());
+ SCCOL nCount = static_cast<SCCOL>(xLocalColOffset->size());
if ( nCol < nCount )
- nColOffset = static_cast<sal_uInt16>((*pLocalColOffset)[nCol]);
+ nColOffset = static_cast<sal_uInt16>((*xLocalColOffset)[nCol]);
else
- nColOffset = static_cast<sal_uInt16>((*pLocalColOffset)[nCount - 1]);
+ nColOffset = static_cast<sal_uInt16>((*xLocalColOffset)[nCount - 1]);
}
pE->nOffset = nColOffset;
sal_uInt16 nWidth = GetWidth( pE );
- MakeCol( pLocalColOffset, pE->nOffset, nWidth, nOffsetTolerance, nOffsetTolerance );
+ MakeCol( xLocalColOffset.get(), pE->nOffset, nWidth, nOffsetTolerance, nOffsetTolerance );
if ( pE->nWidth )
pE->nWidth = nWidth;
nColOffset = pE->nOffset + nWidth;
@@ -913,7 +915,8 @@ void ScHTMLLayoutParser::CloseEntry( const HtmlImportInfo* pInfo )
if ( bTabInTabCell )
{ // From the stack in TableOff
bTabInTabCell = false;
- NewActEntry(maList.back().get()); // New free flying mxActEntry
+ SAL_WARN_IF(maList.empty(), "sc", "unexpected close entry without open");
+ NewActEntry(maList.empty() ? nullptr : maList.back().get()); // New free flying mxActEntry
return ;
}
if (mxActEntry->nTab == 0)
@@ -1035,12 +1038,20 @@ void ScHTMLLayoutParser::TableDataOn( HtmlImportInfo* pInfo )
{
case HtmlOptionId::COLSPAN:
{
- mxActEntry->nColOverlap = static_cast<SCCOL>(rOption.GetString().toInt32());
+ sal_Int32 nColOverlap = rOption.GetString().toInt32();
+ if (nColOverlap >= 0 && nColOverlap <= SCCOL_MAX)
+ mxActEntry->nColOverlap = static_cast<SCCOL>(nColOverlap);
+ else
+ SAL_WARN("sc", "ScHTMLLayoutParser::TableDataOn ignoring colspan: " << nColOverlap);
}
break;
case HtmlOptionId::ROWSPAN:
{
- mxActEntry->nRowOverlap = static_cast<SCROW>(rOption.GetString().toInt32());
+ sal_Int32 nRowOverlap = rOption.GetString().toInt32();
+ if (nRowOverlap >= 0)
+ mxActEntry->nRowOverlap = static_cast<SCROW>(nRowOverlap);
+ else
+ SAL_WARN("sc", "ScHTMLLayoutParser::TableDataOn ignoring rowspan: " << nRowOverlap);
}
break;
case HtmlOptionId::ALIGN:
@@ -1143,7 +1154,7 @@ void ScHTMLLayoutParser::TableOn( HtmlImportInfo* pInfo )
sal_uInt16 nTmpColOffset = nColOffset; // Will be changed in Colonize()
Colonize(mxActEntry.get());
aTableStack.push( std::make_unique<ScHTMLTableStackEntry>(
- mxActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
+ mxActEntry, xLockedList, xLocalColOffset, nFirstTableCell,
nRowCnt, nColCntStart, nMaxCol, nTable,
nTableWidth, nColOffset, nColOffsetStart,
bFirstRow ) );
@@ -1199,7 +1210,7 @@ void ScHTMLLayoutParser::TableOn( HtmlImportInfo* pInfo )
NextRow( pInfo );
}
aTableStack.push( std::make_unique<ScHTMLTableStackEntry>(
- mxActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
+ mxActEntry, xLockedList, xLocalColOffset, nFirstTableCell,
nRowCnt, nColCntStart, nMaxCol, nTable,
nTableWidth, nColOffset, nColOffsetStart,
bFirstRow ) );
@@ -1232,8 +1243,8 @@ void ScHTMLLayoutParser::TableOn( HtmlImportInfo* pInfo )
bFirstRow = true;
nFirstTableCell = maList.size();
- pLocalColOffset = new ScHTMLColOffset;
- MakeColNoRef( pLocalColOffset, nColOffsetStart, 0, 0, 0 );
+ xLocalColOffset.reset(new ScHTMLColOffset);
+ MakeColNoRef( xLocalColOffset.get(), nColOffsetStart, 0, 0, 0 );
}
void ScHTMLLayoutParser::TableOff( const HtmlImportInfo* pInfo )
@@ -1349,7 +1360,7 @@ void ScHTMLLayoutParser::TableOff( const HtmlImportInfo* pInfo )
{
sal_uInt16 nOldOffset = pE->nOffset + pE->nWidth;
sal_uInt16 nNewOffset = pE->nOffset + nTableWidth;
- ModifyOffset( pS->pLocalColOffset, nOldOffset, nNewOffset, nOffsetTolerance );
+ ModifyOffset( pS->xLocalColOffset.get(), nOldOffset, nNewOffset, nOffsetTolerance );
sal_uInt16 nTmp = nNewOffset - pE->nOffset - pE->nWidth;
pE->nWidth = nNewOffset - pE->nOffset;
pS->nTableWidth = pS->nTableWidth + nTmp;
@@ -1368,7 +1379,7 @@ void ScHTMLLayoutParser::TableOff( const HtmlImportInfo* pInfo )
nColOffsetStart = pS->nColOffsetStart;
bFirstRow = pS->bFirstRow;
xLockedList = pS->xLockedList;
- pLocalColOffset = pS->pLocalColOffset;
+ xLocalColOffset = pS->xLocalColOffset;
// mxActEntry is kept around if a table is started in the same row
// (anything's possible in HTML); will be deleted by CloseEntry
mxActEntry = pE;
@@ -1384,8 +1395,7 @@ void ScHTMLLayoutParser::TableOff( const HtmlImportInfo* pInfo )
if ( !aTableStack.empty() )
{
ScHTMLTableStackEntry* pS = aTableStack.top().get();
- delete pLocalColOffset;
- pLocalColOffset = pS->pLocalColOffset;
+ xLocalColOffset = std::move(pS->xLocalColOffset);
aTableStack.pop();
}
}
@@ -1491,7 +1501,7 @@ void ScHTMLLayoutParser::ColOn( HtmlImportInfo* pInfo )
if( rOption.GetToken() == HtmlOptionId::WIDTH )
{
sal_uInt16 nVal = GetWidthPixel( rOption );
- MakeCol( pLocalColOffset, nColOffset, nVal, 0, 0 );
+ MakeCol( xLocalColOffset.get(), nColOffset, nVal, 0, 0 );
nColOffset = nColOffset + nVal;
}
}
@@ -1595,13 +1605,14 @@ void ScHTMLLayoutParser::ProcToken( HtmlImportInfo* pInfo )
switch ( pInfo->nToken )
{
case HtmlTokenId::META:
+ if (ScDocShell* pDocSh = mpDoc->GetDocumentShell())
{
HTMLParser* pParser = static_cast<HTMLParser*>(pInfo->pParser);
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
- static_cast<cppu::OWeakObject*>(mpDoc->GetDocumentShell()->GetModel()), uno::UNO_QUERY_THROW);
+ static_cast<cppu::OWeakObject*>(pDocSh->GetModel()), uno::UNO_QUERY_THROW);
pParser->ParseMetaOptions(
xDPS->getDocumentProperties(),
- mpDoc->GetDocumentShell()->GetHeaderAttributes() );
+ pDocSh->GetHeaderAttributes() );
}
break;
case HtmlTokenId::TITLE_ON:
@@ -1612,12 +1623,13 @@ void ScHTMLLayoutParser::ProcToken( HtmlImportInfo* pInfo )
break;
case HtmlTokenId::TITLE_OFF:
{
- if ( bInTitle && !aString.isEmpty() )
+ ScDocShell* pDocSh = mpDoc->GetDocumentShell();
+ if ( bInTitle && !aString.isEmpty() && pDocSh )
{
// Remove blanks from line breaks
aString = aString.trim();
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
- static_cast<cppu::OWeakObject*>(mpDoc->GetDocumentShell()->GetModel()),
+ static_cast<cppu::OWeakObject*>(pDocSh->GetModel()),
uno::UNO_QUERY_THROW);
xDPS->getDocumentProperties()->setTitle(aString);
}
diff --git a/sc/source/filter/inc/htmlpars.hxx b/sc/source/filter/inc/htmlpars.hxx
index 1ac9aa0002..7043c91761 100644
--- a/sc/source/filter/inc/htmlpars.hxx
+++ b/sc/source/filter/inc/htmlpars.hxx
@@ -102,7 +102,7 @@ struct ScHTMLTableStackEntry
{
ScRangeListRef xLockedList;
std::shared_ptr<ScEEParseEntry> xCellEntry;
- ScHTMLColOffset* pLocalColOffset;
+ std::shared_ptr<ScHTMLColOffset> xLocalColOffset;
sal_uLong nFirstTableCell;
SCROW nRowCnt;
SCCOL nColCntStart;
@@ -113,14 +113,14 @@ struct ScHTMLTableStackEntry
sal_uInt16 nColOffsetStart;
bool bFirstRow;
ScHTMLTableStackEntry( std::shared_ptr<ScEEParseEntry> xE,
- ScRangeListRef xL, ScHTMLColOffset* pTO,
+ ScRangeListRef xL, std::shared_ptr<ScHTMLColOffset> xTO,
sal_uLong nFTC,
SCROW nRow,
SCCOL nStart, SCCOL nMax, sal_uInt16 nTab,
sal_uInt16 nTW, sal_uInt16 nCO, sal_uInt16 nCOS,
bool bFR )
: xLockedList(std::move( xL )), xCellEntry(std::move(xE)),
- pLocalColOffset( pTO ),
+ xLocalColOffset( std::move(xTO) ),
nFirstTableCell( nFTC ),
nRowCnt( nRow ),
nColCntStart( nStart ), nMaxCol( nMax ),
@@ -162,7 +162,7 @@ private:
ScRangeListRef xLockedList; // per table
std::unique_ptr<OuterMap> pTables;
ScHTMLColOffset maColOffset;
- ScHTMLColOffset* pLocalColOffset; // per table
+ std::shared_ptr<ScHTMLColOffset> xLocalColOffset; // per table
sal_uLong nFirstTableCell; // per table
short nTableLevel;
sal_uInt16 nTable;
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index 9da5da65b7..74c9d093d5 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -3530,10 +3530,12 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
// rectangle from the anchor as if all column/rows are shown. Then we move and resize
// (in case of "resize with cell") the object to meet this snap rectangle. We need to
// manipulate the object itself, because the used methods in xmloff do not evaluate the
- // ObjData. This manipulation is only done temporarily for export. Thus we stash the geometry
- // and restore it when export is done and we use NbcFoo methods.
- bool bNeedsRestore = false;
- std::unique_ptr<SdrObjGeoData> pGeoData = pObj->GetGeoData();
+ // ObjData. We remember the transformations and restore them later.
+ Point aMoveBy(0, 0);
+ bool bNeedsRestorePosition = false;
+ Fraction aScaleWidth(1, 1);
+ Fraction aScaleHeight(1, 1);
+ bool bNeedsRestoreSize = false;
// Determine top point of fictive snap rectangle ('Full' rectangle).
SCTAB aTab(aSnapStartAddress.Tab());
@@ -3554,8 +3556,8 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
Point aActualTopPoint = bNegativePage ? aOrigSnapRect.TopRight() : aOrigSnapRect.TopLeft();
if (aFullTopPoint != aActualTopPoint)
{
- bNeedsRestore = true;
- Point aMoveBy = aFullTopPoint - aActualTopPoint;
+ bNeedsRestorePosition = true;
+ aMoveBy = aFullTopPoint - aActualTopPoint;
pObj->NbcMove(Size(aMoveBy.X(), aMoveBy.Y()));
}
@@ -3567,6 +3569,7 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
// Object is anchored "To cell (resize with cell)". Compare size of actual snap rectangle
// and fictive full one. Resize object accordingly.
tools::Rectangle aActualSnapRect(pObj->GetSnapRect());
+
Point aSnapEndOffset(pObjData->maEndOffset);
aCol = aSnapEndAddress.Col();
aRow = aSnapEndAddress.Row();
@@ -3583,12 +3586,13 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
if (aFullSnapRect != aActualSnapRect)
{
- bNeedsRestore = true;
- Fraction aScaleWidth(aFullSnapRect.getOpenWidth(), aActualSnapRect.getOpenWidth());
+ bNeedsRestoreSize = true;
+ aScaleWidth
+ = Fraction(aFullSnapRect.getOpenWidth(), aActualSnapRect.getOpenWidth());
if (!aScaleWidth.IsValid())
aScaleWidth = Fraction(1, 1);
- Fraction aScaleHeight(aFullSnapRect.getOpenHeight(),
- aActualSnapRect.getOpenHeight());
+ aScaleHeight
+ = Fraction(aFullSnapRect.getOpenHeight(), aActualSnapRect.getOpenHeight());
if (!aScaleHeight.IsValid())
aScaleHeight = Fraction(1, 1);
pObj->NbcResize(aFullTopPoint, aScaleWidth, aScaleHeight);
@@ -3636,9 +3640,20 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
ExportShape(rShape.xShape, &aPoint);
- // Restore object geometry
- if (bNeedsRestore && pGeoData)
- pObj->SetGeoData(*pGeoData);
+ if (bNeedsRestoreSize)
+ {
+ Fraction aScaleWidthInvers(aScaleWidth.GetDenominator(), aScaleWidth.GetNumerator());
+ if (!aScaleWidthInvers.IsValid())
+ aScaleWidthInvers = Fraction(1, 1);
+ Fraction aScaleHeightInvers(aScaleHeight.GetDenominator(), aScaleHeight.GetNumerator());
+ if (!aScaleHeightInvers.IsValid())
+ aScaleHeightInvers = Fraction(1, 1);
+ pObj->NbcResize(aFullTopPoint, aScaleWidthInvers, aScaleHeightInvers);
+ }
+ if (bNeedsRestorePosition)
+ {
+ pObj->NbcMove(Size(-aMoveBy.X(), -aMoveBy.Y()));
+ }
}
}
diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx
index 8e6315db94..a61ee53d25 100644
--- a/sc/source/ui/docshell/impex.cxx
+++ b/sc/source/ui/docshell/impex.cxx
@@ -1662,7 +1662,7 @@ bool ScImportExport::ExtText2Doc( SvStream& rStrm )
ScDocumentImport aDocImport(rDoc);
do
{
- SCCOL nLastCol = nEndCol; // tdf#129701 preserve value of nEndCol
+ const SCCOL nLastCol = nEndCol; // tdf#129701 preserve value of nEndCol
for( ;; )
{
aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep);
@@ -1784,15 +1784,15 @@ bool ScImportExport::ExtText2Doc( SvStream& rStrm )
aTransliteration, aCalendar,
pEnglishTransliteration.get(), pEnglishCalendar.get());
}
+ ++nCol;
if (bIsLastColEmpty)
{
bIsLastColEmpty = false; // toggle to stop
}
else
{
- ++nCol;
// tdf#129701 detect if there is a last empty column when we need it
- bIsLastColEmpty = !(*p) && !bSkipEmptyCells && !bDetermineRange && nCol == nLastCol;
+ bIsLastColEmpty = (nCol == nLastCol) && !(*p) && !bSkipEmptyCells && !bDetermineRange;
}
}
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 66bbc010ea..e13488e302 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -241,7 +241,7 @@ private:
void UpdateVarZoom();
static void SetScrollBar( ScrollAdaptor& rScroll, tools::Long nRangeMax, tools::Long nVisible, tools::Long nPos, bool bLayoutRTL );
- static tools::Long GetScrollBarPos( const ScrollAdaptor& rScroll );
+ static tools::Long GetScrollBarPos( const ScrollAdaptor& rScroll, bool bLayoutRTL );
void GetAreaMoveEndPosition(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
SCCOL& rAreaX, SCROW& rAreaY, ScFollowMode& rMode,
diff --git a/sc/source/ui/miscdlgs/solveroptions.cxx b/sc/source/ui/miscdlgs/solveroptions.cxx
index 3d5b2b47c1..81f5c8b7b4 100644
--- a/sc/source/ui/miscdlgs/solveroptions.cxx
+++ b/sc/source/ui/miscdlgs/solveroptions.cxx
@@ -69,7 +69,7 @@ ScSolverOptionsDialog::ScSolverOptionsDialog(weld::Window* pParent,
, m_xBtnEdit(m_xBuilder->weld_button("edit"))
{
m_xLbSettings->set_size_request(m_xLbSettings->get_approximate_digit_width() * 32,
- m_xLbSettings->get_height_rows(6));
+ m_xLbSettings->get_height_rows(12));
m_xLbSettings->enable_toggle_buttons(weld::ColumnToggleType::Check);
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index c906f39336..6d94542095 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -27,6 +27,9 @@
#include <editeng/editview.hxx>
#include <editeng/memberids.h>
#include <editeng/outliner.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/sizeitem.hxx>
#include <o3tl/any.hxx>
#include <o3tl/safeint.hxx>
#include <svx/fmview.hxx>
@@ -131,6 +134,7 @@
#include <table.hxx>
#include <appoptio.hxx>
#include <formulaopt.hxx>
+#include <stlpool.hxx>
#include <strings.hrc>
@@ -2059,7 +2063,7 @@ uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32
bWasCellRange = pPrintFunc->GetLastSourceRange( aCellRange );
Size aTwips = pPrintFunc->GetPageSize();
- if (!m_pPrintState)
+ if (!m_pPrintState || nRenderer == nTabStart)
{
m_pPrintState.reset(new ScPrintState());
pPrintFunc->GetPrintState(*m_pPrintState, true);
@@ -2105,6 +2109,174 @@ uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32
return aSequence;
}
+static void lcl_SetMediaScreen(const uno::Reference<drawing::XShape>& xMediaShape,
+ const OutputDevice* pDev, tools::Rectangle& aRect,
+ sal_Int32 nPageNumb)
+{
+ OUString sMediaURL;
+ uno::Reference<beans::XPropertySet> xPropSet(xMediaShape, uno::UNO_QUERY);
+ xPropSet->getPropertyValue("MediaURL") >>= sMediaURL;
+ if (sMediaURL.isEmpty())
+ return;
+ vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
+ if (!pPDF)
+ return;
+
+ OUString sTitle;
+ xPropSet->getPropertyValue("Title") >>= sTitle;
+ OUString sDescription;
+ xPropSet->getPropertyValue("Description") >>= sDescription;
+ OUString const altText(sTitle.isEmpty() ? sDescription
+ : sDescription.isEmpty()
+ ? sTitle
+ : OUString::Concat(sTitle) + OUString::Concat("\n")
+ + OUString::Concat(sDescription));
+
+ OUString const mimeType(xPropSet->getPropertyValue("MediaMimeType").get<OUString>());
+ SdrObject* pSdrObj(SdrObject::getSdrObjectFromXShape(xMediaShape));
+ sal_Int32 nScreenId = pPDF->CreateScreen(aRect, altText, mimeType, nPageNumb, pSdrObj);
+ if (sMediaURL.startsWith("vnd.sun.star.Package:"))
+ {
+ // Embedded media
+ OUString aTempFileURL;
+ xPropSet->getPropertyValue("PrivateTempFileURL") >>= aTempFileURL;
+ pPDF->SetScreenStream(nScreenId, aTempFileURL);
+ }
+ else // Linked media
+ pPDF->SetScreenURL(nScreenId, sMediaURL);
+}
+
+static void lcl_PDFExportMediaShapeScreen(const OutputDevice* pDev, const ScPrintState& rState,
+ ScDocument& rDoc, SCTAB nTab, tools::Long nStartPage,
+ bool bSinglePageSheets)
+{
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
+ if (pPDF && pPDF->GetIsExportTaggedPDF() && pDrawLayer)
+ {
+
+ if (!bSinglePageSheets)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page ?");
+ if (pPage)
+ {
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find(rDoc.GetPageStyle(nTab), SfxStyleFamily::Page);
+ SfxItemSet* pItemSet = &pStyleSheet->GetItemSet();
+
+ tools::Long nLeftMargin(pItemSet->Get(ATTR_LRSPACE).GetLeft());
+ nLeftMargin = o3tl::convert(nLeftMargin, o3tl::Length::twip, o3tl::Length::mm100);
+
+ tools::Long nTopMargin(pItemSet->Get(ATTR_ULSPACE).GetUpper());
+ nTopMargin = o3tl::convert(nTopMargin, o3tl::Length::twip, o3tl::Length::mm100);
+
+ tools::Long nHeader = 0;
+ const SvxSetItem* pHeaderSetItem = &pItemSet->Get(ATTR_PAGE_HEADERSET);
+ bool bHasHdr = pHeaderSetItem->GetItemSet().Get(ATTR_PAGE_ON).GetValue();
+ if (bHasHdr)
+ {
+ const SfxItemSet* pHeaderSet = &pHeaderSetItem->GetItemSet();
+ tools::Long nHdrHeight = pHeaderSet->Get(ATTR_PAGE_SIZE).GetSize().Height();
+ nHeader = o3tl::convert(nHdrHeight, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+
+ bool bTopDown = pItemSet->Get(ATTR_PAGE_TOPDOWN).GetValue();
+
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
+ SdrObject* pObj = aIter.Next();
+ while (pObj && pObj->IsVisible())
+ {
+ uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
+ if (xShape->getShapeType() == "com.sun.star.drawing.MediaShape")
+ {
+ SCCOL nX1, nX2;
+ SCROW nY1, nY2;
+ sal_Int32 nPageNumb = nStartPage;
+ if (bTopDown) // top-bottom page order
+ {
+ nX1 = 0;
+ for (size_t i = 0; i < rState.nPagesX; ++i)
+ {
+ nX2 = (*rState.xPageEndX)[i];
+ for (size_t j = 0; j < rState.nPagesY; ++j)
+ {
+ auto& rPageRow = (*rState.xPageRows)[j];
+ nY1 = rPageRow.GetStartRow();
+ nY2 = rPageRow.GetEndRow();
+
+ tools::Rectangle aPageRect(rDoc.GetMMRect(nX1, nY1, nX2, nY2, nTab));
+ tools::Rectangle aTmpRect(aPageRect.GetIntersection(pObj->GetCurrentBoundRect()));
+ if (!aTmpRect.IsEmpty())
+ {
+ tools::Long nPosX(aTmpRect.getX() - aPageRect.getX() + nLeftMargin);
+ tools::Long nPosY(aTmpRect.getY() - aPageRect.getY() + nHeader + nTopMargin);
+ tools::Rectangle aRect(Point(nPosX, nPosY), aTmpRect.GetSize());
+ lcl_SetMediaScreen(xShape, pDev, aRect, nPageNumb);
+ }
+ ++nPageNumb;
+ }
+ nX1 = nX2 + 1;
+ }
+ }
+ else // left to right page order
+ {
+ for (size_t i = 0; i < rState.nPagesY; ++i)
+ {
+ auto& rPageRow = (*rState.xPageRows)[i];
+ nY1 = rPageRow.GetStartRow();
+ nY2 = rPageRow.GetEndRow();
+ nX1 = 0;
+ for (size_t j = 0; j < rState.nPagesX; ++j)
+ {
+ nX2 = (*rState.xPageEndX)[j];
+
+ tools::Rectangle aPageRect(rDoc.GetMMRect(nX1, nY1, nX2, nY2, nTab));
+ tools::Rectangle aTmpRect(aPageRect.GetIntersection(pObj->GetCurrentBoundRect()));
+ if (!aTmpRect.IsEmpty())
+ {
+ tools::Long nPosX(aTmpRect.getX() - aPageRect.getX() + nLeftMargin);
+ tools::Long nPosY(aTmpRect.getY() - aPageRect.getY() + nHeader + nTopMargin);
+ tools::Rectangle aRect(Point(nPosX, nPosY), aTmpRect.GetSize());
+ lcl_SetMediaScreen(xShape, pDev, aRect, nPageNumb);
+ }
+ ++nPageNumb;
+ nX1 = nX2 + 1;
+ }
+ }
+ }
+ }
+ pObj = aIter.Next();
+ }
+ }
+ }
+ else // export whole sheet
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i = 0; i < nTabCount; ++i)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(i));
+ OSL_ENSURE(pPage, "Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
+ SdrObject* pObj = aIter.Next();
+ while (pObj && pObj->IsVisible())
+ {
+ uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
+ if (xShape->getShapeType() == "com.sun.star.drawing.MediaShape")
+ {
+ tools::Rectangle aRect(pObj->GetCurrentBoundRect());
+ lcl_SetMediaScreen(xShape, pDev, aRect, i);
+ }
+ pObj = aIter.Next();
+ }
+ }
+ }
+ }
+ }
+}
+
void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelection,
const uno::Sequence<beans::PropertyValue>& rOptions )
{
@@ -2151,6 +2323,17 @@ void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelec
ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab;
+ if (!maValidPages.empty())
+ nTab = pPrintFuncCache->GetTabForPage(maValidPages.at(nRenderer) - 1);
+ else
+ nTab = pPrintFuncCache->GetTabForPage(nRenderer);
+
+ tools::Long nTabStart = pPrintFuncCache->GetTabStart(nTab);
+
+ if (nRenderer == nTabStart)
+ lcl_PDFExportMediaShapeScreen(pDev, *m_pPrintState, rDoc, nTab, nTabStart, bSinglePageSheets);
+
ScRange aRange;
const ScRange* pSelRange = nullptr;
if ( bSinglePageSheets )
@@ -2225,12 +2408,6 @@ void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelec
}
} aDrawViewKeeper;
- SCTAB nTab;
- if ( !maValidPages.empty() )
- nTab = pPrintFuncCache->GetTabForPage( maValidPages.at( nRenderer )-1 );
- else
- nTab = pPrintFuncCache->GetTabForPage( nRenderer );
-
ScDrawLayer* pModel = rDoc.GetDrawLayer();
if( pModel )
@@ -2285,7 +2462,6 @@ void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelec
aPage.Select( nRenderer+1 );
tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
- tools::Long nTabStart = pPrintFuncCache->GetTabStart( nTab );
vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >(pDev->GetExtOutDevData() );
if ( nRenderer == nTabStart )
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index d419981d8e..877675c0ac 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -1877,8 +1877,7 @@ void ScOutputData::LayoutStrings(bool bPixelToLogic)
// Cells to the left are marked directly, cells to the
// right are handled by the flag for nX2
SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
- RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
- pMarkRowInfo->basicCellInfo(nMarkX).bEditEngine = true;
+ pThisRowInfo->basicCellInfo(nMarkX).bEditEngine = true;
bDoCell = false; // don't draw here
}
if ( bDoCell )
@@ -4429,14 +4428,17 @@ void ScOutputData::DrawEdit(bool bPixelToLogic)
SCROW nCellY = nY;
bool bDoCell = false;
+ // if merged cell contains hidden row or column or both
+ const ScMergeFlagAttr* pMergeFlag = mpDoc->GetAttr(nX, nY, nTab, ATTR_MERGE_FLAG);
+ bool bOverlapped = (pMergeFlag->IsHorOverlapped() || pMergeFlag->IsVerOverlapped());
+
tools::Long nPosY = nRowPosY;
- if ( nArrY == 0 )
+ if (bOverlapped)
{
- nPosY = nScrY;
- nY = pRowInfo[1].nRowNo;
+ nY = pRowInfo[nArrY].nRowNo;
SCCOL nOverX; // start of the merged cells
SCROW nOverY;
- if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, true ))
+ if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, true ))
{
nCellX = nOverX;
nCellY = nOverY;
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
index 9eff50195e..a69ab1447f 100644
--- a/sc/source/ui/view/tabview.cxx
+++ b/sc/source/ui/view/tabview.cxx
@@ -1091,7 +1091,7 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
nViewPos = aViewData.GetPosY( (pScroll == aVScrollTop.get()) ?
SC_SPLIT_TOP : SC_SPLIT_BOTTOM );
- bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+ bool bLayoutRTL = bHoriz && aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
ScrollType eType = pScroll->GetScrollType();
if ( eType == ScrollType::Drag )
@@ -1129,7 +1129,7 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
nScrollMin = aViewData.GetFixPosX();
if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == aVScrollBottom.get() )
nScrollMin = aViewData.GetFixPosY();
- tools::Long nScrollPos = GetScrollBarPos( *pScroll ) + nScrollMin;
+ tools::Long nScrollPos = GetScrollBarPos( *pScroll, bLayoutRTL ) + nScrollMin;
OUString aHelpStr;
tools::Rectangle aRect;
@@ -1162,6 +1162,22 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
else
bDragging = false;
+ if ( bHoriz && bLayoutRTL )
+ {
+ // change scroll type so visible/previous cells calculation below remains the same
+ switch ( eType )
+ {
+ case ScrollType::LineUp: eType = ScrollType::LineDown; break;
+ case ScrollType::LineDown: eType = ScrollType::LineUp; break;
+ case ScrollType::PageUp: eType = ScrollType::PageDown; break;
+ case ScrollType::PageDown: eType = ScrollType::PageUp; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
tools::Long nDelta(0);
switch ( eType )
{
@@ -1194,7 +1210,7 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == aVScrollBottom.get() )
nScrollMin = aViewData.GetFixPosY();
- tools::Long nScrollPos = GetScrollBarPos( *pScroll ) + nScrollMin;
+ tools::Long nScrollPos = GetScrollBarPos( *pScroll, bLayoutRTL ) + nScrollMin;
nDelta = nScrollPos - nViewPos;
// tdf#152406 Disable anti-jitter code for scroll wheel events
diff --git a/sc/source/ui/view/tabview4.cxx b/sc/source/ui/view/tabview4.cxx
index a7de6bdf67..5c19b6cf07 100644
--- a/sc/source/ui/view/tabview4.cxx
+++ b/sc/source/ui/view/tabview4.cxx
@@ -352,16 +352,45 @@ void ScTabView::SetScrollBar( ScrollAdaptor& rScroll, tools::Long nRangeMax, too
if ( nVisible == 0 )
nVisible = 1; // #i59893# don't use visible size 0
- rScroll.SetRange( Range( 0, nRangeMax ) );
- rScroll.SetVisibleSize( nVisible );
- rScroll.SetThumbPos( nPos );
+ // RTL layout uses a negative range to simulate a mirrored scroll bar.
+ // SetScrollBar/GetScrollBarPos hide this so outside of these functions normal cell
+ // addresses can be used.
+ if ( bLayoutRTL )
+ {
+ rScroll.SetRange( Range( -nRangeMax, 0 ) );
+ rScroll.SetVisibleSize( nVisible );
+ rScroll.SetThumbPos( -nPos - nVisible );
+ }
+ else
+ {
+ rScroll.SetRange( Range( 0, nRangeMax ) );
+ rScroll.SetVisibleSize( nVisible );
+ rScroll.SetThumbPos( nPos );
+ }
- rScroll.EnableRTL( bLayoutRTL );
+ // Related: tdf#93352 always disable RTL for scrollbars
+ // Enabling RTL causes the following bugs when clicking or
+ // dragging the mouse in scrollbars in Calc's RTL UI:
+ // - Click or drag events get mirrored so you must click or
+ // drag in unexpected locations to move the scrollbar thumb
+ // in the desired direction
+ // - Repeatedly dragging the scrollbar thumb leftward can only
+ // move no highter than the R, S, or T columns
+ rScroll.EnableRTL( false );
+
+ // Related: tdf#93352 swap arrows if layout is RTL
+ // We cannot use EnableRTL(true) to signal that the arrows
+ // should be swapped (see comment above) so explicitly enable
+ // or disable arrow swapping.
+ rScroll.SetSwapArrows( bLayoutRTL );
}
-tools::Long ScTabView::GetScrollBarPos( const ScrollAdaptor& rScroll )
+tools::Long ScTabView::GetScrollBarPos( const ScrollAdaptor& rScroll, bool bLayoutRTL )
{
- return rScroll.GetThumbPos();
+ if ( bLayoutRTL )
+ return -rScroll.GetThumbPos() - rScroll.GetVisibleSize();
+ else
+ return rScroll.GetThumbPos();
}
// UpdateScrollBars - set visible area and scroll width of scroll bars
@@ -425,7 +454,7 @@ void ScTabView::UpdateScrollBars( HeaderType eHeaderType )
nVisYB = aViewData.VisibleCellsY( SC_SPLIT_BOTTOM );
tools::Long nMaxYB = lcl_GetScrollRange( nUsedY, aViewData.GetPosY(SC_SPLIT_BOTTOM), nVisYB, rDoc.MaxRow(), nStartY );
- SetScrollBar( *aVScrollBottom, nMaxYB, nVisYB, aViewData.GetPosY( SC_SPLIT_BOTTOM ) - nStartY, bLayoutRTL );
+ SetScrollBar( *aVScrollBottom, nMaxYB, nVisYB, aViewData.GetPosY( SC_SPLIT_BOTTOM ) - nStartY, false );
if (bRight)
{
@@ -438,7 +467,7 @@ void ScTabView::UpdateScrollBars( HeaderType eHeaderType )
{
nVisYT = aViewData.VisibleCellsY( SC_SPLIT_TOP );
tools::Long nMaxYT = lcl_GetScrollRange( nUsedY, aViewData.GetPosY(SC_SPLIT_TOP), nVisYT, rDoc.MaxRow(), 0 );
- SetScrollBar( *aVScrollTop, nMaxYT, nVisYT, aViewData.GetPosY( SC_SPLIT_TOP ), bLayoutRTL );
+ SetScrollBar( *aVScrollTop, nMaxYT, nVisYT, aViewData.GetPosY( SC_SPLIT_TOP ), false );
}
// test the range
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
index 7a6403237b..e52357f808 100644
--- a/sc/source/ui/view/viewfun3.cxx
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -885,7 +885,8 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
// undo: save all or no content
InsertDeleteFlags nContFlags = InsertDeleteFlags::NONE;
- if (nFlags & InsertDeleteFlags::CONTENTS)
+ // tdf#160765 - save content for undo when pasting notes, even if no content was changed
+ if (nFlags & (InsertDeleteFlags::CONTENTS | InsertDeleteFlags::ADDNOTES))
nContFlags |= InsertDeleteFlags::CONTENTS;
if (nFlags & InsertDeleteFlags::ATTRIB)
nContFlags |= InsertDeleteFlags::ATTRIB;