online.git: engine/sc

0 views
Skip to first unread message

"Andras Timar (via cogerrit)"

unread,
Apr 20, 2026, 4:04:26 PM (9 days ago) Apr 20
to collaboraon...@googlegroups.com
engine/sc/qa/extras/scsolverobj.cxx | 4 ++++
1 file changed, 4 insertions(+)

New commits:
commit 210b80c2bc7c184d335ed07f20e3c633960f84f8
Author: Andras Timar <andras...@collabora.com>
AuthorDate: Mon Apr 20 22:02:40 2026 +0200
Commit: Andras Timar <andras...@collabora.com>
CommitDate: Mon Apr 20 22:02:40 2026 +0200

sc: guard testCellAddress/testCellRangeAddress with ENABLE_LPSOLVE

The body of testXSolverSettings() is wrapped in #ifdef ENABLE_LPSOLVE,
so when LPSolve is disabled these helpers have no call sites and
loplugin:unreffun flags them as unreferenced externally visible
function definitions. Guard the declarations and definitions with the
same macro to match.

Signed-off-by: Andras Timar <andras...@collabora.com>
Change-Id: Iab42bcb932c776c65bdbe0d0da52450d6a5a001c

diff --git a/engine/sc/qa/extras/scsolverobj.cxx b/engine/sc/qa/extras/scsolverobj.cxx
index c637192e177f..783e767da379 100644
--- a/engine/sc/qa/extras/scsolverobj.cxx
+++ b/engine/sc/qa/extras/scsolverobj.cxx
@@ -35,8 +35,10 @@ public:

virtual void setUp() override;
void testXSolverSettings();
+#ifdef ENABLE_LPSOLVE
void testCellAddress(const table::CellAddress& rExpected, const uno::Any& rActual);
void testCellRangeAddress(const uno::Any& rExpected, const uno::Any& rActual);
+#endif

CPPUNIT_TEST_SUITE(ScSolverSettingsObj);
CPPUNIT_TEST(testXSolverSettings);
@@ -48,6 +50,7 @@ ScSolverSettingsObj::ScSolverSettingsObj()
{
}

+#ifdef ENABLE_LPSOLVE
void ScSolverSettingsObj::testCellAddress(const table::CellAddress& rExpected,
const uno::Any& rActual)
{
@@ -70,6 +73,7 @@ void ScSolverSettingsObj::testCellRangeAddress(const uno::Any& rExpected, const
CPPUNIT_ASSERT_EQUAL(aExpectedAddress.EndRow, aActualAddress.EndRow);
CPPUNIT_ASSERT_EQUAL(aExpectedAddress.EndColumn, aActualAddress.EndColumn);
}
+#endif

// Creates a model using the XSolverSettings API checks if it is accessible via the API
void ScSolverSettingsObj::testXSolverSettings()

"Tomaž Vajngerl (via cogerrit)"

unread,
Apr 24, 2026, 3:16:59 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/source/ui/inc/operation/Operation.hxx | 5 ++
engine/sc/source/ui/operation/ApplyAttributesOperation.cxx | 2
engine/sc/source/ui/operation/Operation.cxx | 30 +++++++++++++
3 files changed, 36 insertions(+), 1 deletion(-)

New commits:
commit 090d8053b0fae20b0ba1a384f678b3a6b6207b26
Author: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
AuthorDate: Thu Apr 23 11:00:52 2026 +0900
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri Apr 24 07:16:40 2026 +0000

sc: Fast path sheet view sync for ApplyAttributesToCellOperation

Add syncCellPatternToSheetViews that applies the pattern directly
at the row mapped for each sheet view, and strips overridden
edit-text char attribs on CELLTYPE_EDIT cells.

No auto-filter fallback needed as there is no data extension with
patterns.

Signed-off-by: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
Change-Id: If8a6ea29dea53e483590f7135ae8cdbf5092321d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1426
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sc/source/ui/inc/operation/Operation.hxx b/engine/sc/source/ui/inc/operation/Operation.hxx
index 271768cf8635..a8f32a1fc893 100644
--- a/engine/sc/source/ui/inc/operation/Operation.hxx
+++ b/engine/sc/source/ui/inc/operation/Operation.hxx
@@ -18,6 +18,7 @@ class ScAddress;
class ScRange;
class ScRangeList;
class ScViewData;
+class ScPatternAttr;

namespace sc
{
@@ -71,6 +72,10 @@ protected:
void syncCellToSheetViews(const ScAddress& rDefaultViewAddress,
UndoSheetViewSortData* pUndoSortData = nullptr);

+ /** Propagates a single-cell pattern change to all sheet views. */
+ void syncCellPatternToSheetViews(const ScAddress& rDefaultViewAddress,
+ const ScPatternAttr& rPattern);
+
/** Check if the input is on a sheet view tab */
bool isInputOnSheetView() const;

diff --git a/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx b/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx
index 18429c9021a3..a0ab41c881f4 100644
--- a/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx
+++ b/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx
@@ -247,7 +247,7 @@ bool ApplyAttributesToCellOperation::runImplementation()
}
pOldPat.reset(); // is copied in undo (Pool)

- syncSheetViews();
+ syncCellPatternToSheetViews(aPosition, mrPattern);

mrDocShell.PostPaint(nCol, nRow, nTab, nCol, nRow, nTab, PaintPartFlags::Grid,
mnExtFlags | SC_PF_TESTMERGE);
diff --git a/engine/sc/source/ui/operation/Operation.cxx b/engine/sc/source/ui/operation/Operation.cxx
index 687b1020aec2..1334d3dc455a 100644
--- a/engine/sc/source/ui/operation/Operation.cxx
+++ b/engine/sc/source/ui/operation/Operation.cxx
@@ -351,6 +351,36 @@ void Operation::syncCellToSheetViews(const ScAddress& rDefaultViewAddress,
}
}

+void Operation::syncCellPatternToSheetViews(const ScAddress& rDefaultViewAddress,
+ const ScPatternAttr& rPattern)
+{
+ if (!mpViewData)
+ return;
+
+ auto& rDocument = mpViewData->GetDocument();
+ SCTAB nDefaultViewTab = mpViewData->GetDefaultViewTab();
+
+ std::shared_ptr<SheetViewManager> pManager = rDocument.GetSheetViewManager(nDefaultViewTab);
+ if (!pManager || pManager->isEmpty())
+ return;
+
+ SCCOL nColumn = rDefaultViewAddress.Col();
+ SCROW nDefaultRow = rDefaultViewAddress.Row();
+
+ for (auto& rSheetView : pManager->iterateValidSheetViews())
+ {
+ SCTAB nSheetViewTab = rSheetView.getTableNumber();
+ SCROW nSheetViewRow = rSheetView.reverseDefaultViewToSheetView(nDefaultRow, nColumn);
+ ScAddress aSheetViewAddress(nColumn, nSheetViewRow, nSheetViewTab);
+
+ ScRefCellValue aCell(rDocument, aSheetViewAddress);
+ if (aCell.getType() == CELLTYPE_EDIT)
+ rDocument.RemoveEditTextCharAttribs(aSheetViewAddress, rPattern);
+
+ rDocument.ApplyPattern(nColumn, nSheetViewRow, nSheetViewTab, rPattern);
+ }
+}
+
bool Operation::isInputOnSheetView() const { return getCurrentSheetView(mpViewData) != nullptr; }

bool Operation::isInputOnSheetViewAutoFilter(ScRange const& rRange) const

"Tomaž Vajngerl (via cogerrit)"

unread,
Apr 24, 2026, 3:37:45 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/source/ui/inc/operation/Operation.hxx | 4
engine/sc/source/ui/operation/ApplyAttributesOperation.cxx | 4
engine/sc/source/ui/operation/Operation.cxx | 89 +++++++++++++
3 files changed, 95 insertions(+), 2 deletions(-)

New commits:
commit e34ef663c855af595125f968a47f55ad80dcc5b1
Author: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
AuthorDate: Thu Apr 23 13:05:24 2026 +0900
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri Apr 24 07:36:43 2026 +0000

sc: Fast path sheet view sync for ApplyAttribute operations

Add syncMarkPatternToSheetViews() which for each sheet view
rebuilds the mark in that view's coordinate space and re-runs
ApplySelectionPattern there. Patterns don't grow data extent,
so no full-sync fallback is needed.

Signed-off-by: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
Change-Id: Ibb6217df81684b46c86f4c6a687bd3e62a8ba462
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1427
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sc/source/ui/inc/operation/Operation.hxx b/engine/sc/source/ui/inc/operation/Operation.hxx
index a8f32a1fc893..6ec990bb2c75 100644
--- a/engine/sc/source/ui/inc/operation/Operation.hxx
+++ b/engine/sc/source/ui/inc/operation/Operation.hxx
@@ -76,6 +76,10 @@ protected:
void syncCellPatternToSheetViews(const ScAddress& rDefaultViewAddress,
const ScPatternAttr& rPattern);

+ /** Propagates a multi-range pattern change to all sheet views. */
+ void syncMarkPatternToSheetViews(const ScMarkData& rDefaultViewMark,
+ const ScPatternAttr& rPattern);
+
/** Check if the input is on a sheet view tab */
bool isInputOnSheetView() const;

diff --git a/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx b/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx
index a0ab41c881f4..26e75a20d230 100644
--- a/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx
+++ b/engine/sc/source/ui/operation/ApplyAttributesOperation.cxx
@@ -98,7 +98,7 @@ bool ApplyAttributesOperation::runImplementation()
else if (nExtFlags & SC_PF_LINES)
ScDocFunc::PaintAbove(mrDocShell, aMultiRange); // because of lines above the range

- syncSheetViews();
+ syncMarkPatternToSheetViews(aMark, mrPattern);
aModificator.SetDocumentModified();
}

@@ -176,7 +176,7 @@ bool ApplyAttributesWithChangedRangeOperation::runImplementation()

rDoc.ApplySelectionPattern(mrPattern, aMark, pEditDataArray);

- syncSheetViews();
+ syncMarkPatternToSheetViews(aMark, mrPattern);

mrDocShell.PostPaint(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
PaintPartFlags::Grid, mnExtFlags | SC_PF_TESTMERGE);
diff --git a/engine/sc/source/ui/operation/Operation.cxx b/engine/sc/source/ui/operation/Operation.cxx
index 1334d3dc455a..d45ed89c9fc8 100644
--- a/engine/sc/source/ui/operation/Operation.cxx
+++ b/engine/sc/source/ui/operation/Operation.cxx
@@ -381,6 +381,95 @@ void Operation::syncCellPatternToSheetViews(const ScAddress& rDefaultViewAddress
}
}

+void Operation::syncMarkPatternToSheetViews(const ScMarkData& rDefaultViewMark,
+ const ScPatternAttr& rPattern)
+{
+ if (!mpViewData)
+ return;
+
+ auto& rDocument = mpViewData->GetDocument();
+ SCTAB nDefaultViewTab = mpViewData->GetDefaultViewTab();
+
+ std::shared_ptr<SheetViewManager> pManager = rDocument.GetSheetViewManager(nDefaultViewTab);
+ if (!pManager || pManager->isEmpty())
+ return;
+
+ for (auto& rSheetView : pManager->iterateValidSheetViews())
+ {
+ SCTAB nSheetViewTab = rSheetView.getTableNumber();
+
+ // Rebuild the mark in this sheet view's coordinate space.
+ ScMarkData aSheetViewMark(rDefaultViewMark);
+ aSheetViewMark.MarkToMulti();
+
+ // Swap tab selection and area tab: default view to sheet view.
+ if (aSheetViewMark.GetTableSelect(nDefaultViewTab))
+ {
+ aSheetViewMark.SelectTable(nDefaultViewTab, false);
+ aSheetViewMark.SelectTable(nSheetViewTab, true);
+ }
+ ScRange aArea = aSheetViewMark.GetMultiMarkArea();
+ if (aArea.aStart.Tab() == nDefaultViewTab && aArea.aEnd.Tab() == nDefaultViewTab)
+ aSheetViewMark.SetAreaTab(nSheetViewTab);
+
+ // Re-map marked rows through the sheet view's sort permutation.
+ SortOrderReverser const* pSortOrder = rSheetView.getSortOrder();
+ ReorderParam const* pReorderParams = rSheetView.getReorderParameters();
+ if ((pSortOrder || pReorderParams) && aSheetViewMark.GetTableSelect(nSheetViewTab))
+ {
+ SCROW nRowStart = -1;
+ SCROW nRowEnd = -1;
+ SCCOL nColumnStart = -1;
+ SCCOL nColumnEnd = -1;
+
+ if (pSortOrder)
+ {
+ SortOrderInfo const& rSortInfo = pSortOrder->maSortInfo;
+ nRowStart = rSortInfo.mnFirstRow;
+ nRowEnd = rSortInfo.mnLastRow;
+ nColumnStart = rSortInfo.mnFirstColumn;
+ nColumnEnd = rSortInfo.mnLastColumn;
+ }
+ else
+ {
+ ScRange const& rSortRange = pReorderParams->maSortRange;
+ nRowStart = rSortRange.aStart.Row();
+ nRowEnd = rSortRange.aEnd.Row();
+ nColumnStart = rSortRange.aStart.Col();
+ nColumnEnd = rSortRange.aEnd.Col();
+ }
+
+ std::vector<std::pair<SCCOL, SCROW>> aMarkedCells;
+ for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
+ {
+ for (SCCOL nColumn = nColumnStart; nColumn <= nColumnEnd; ++nColumn)
+ {
+ if (aSheetViewMark.IsCellMarked(nColumn, nRow))
+ {
+ ScRange aCellRange(nColumn, nRow, nSheetViewTab, nColumn, nRow,
+ nSheetViewTab);
+ aSheetViewMark.SetMultiMarkArea(aCellRange, false);
+ aMarkedCells.emplace_back(nColumn, nRow);
+ }
+ }
+ }
+ for (auto& [nColumn, nRow] : aMarkedCells)
+ {
+ SCROW nMappedRow = rSheetView.reverseDefaultViewToSheetView(nRow, nColumn);
+ ScRange aCellRange(nColumn, nMappedRow, nSheetViewTab, nColumn, nMappedRow,
+ nSheetViewTab);
+ aSheetViewMark.SetMultiMarkArea(aCellRange, true);
+ }
+ }
+
+ if (!aSheetViewMark.HasAnyMultiMarks())
+ aSheetViewMark.ResetMark();
+ aSheetViewMark.MarkToSimple();
+
+ rDocument.ApplySelectionPattern(rPattern, aSheetViewMark, nullptr);

"Tomaž Vajngerl (via cogerrit)"

unread,
Apr 24, 2026, 3:39:52 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/sdi/scalc.sdi | 2 +-
engine/sc/source/ui/inc/viewfunc.hxx | 5 -----
engine/sc/source/ui/unoobj/docuno.cxx | 16 ++++++++--------
3 files changed, 9 insertions(+), 14 deletions(-)

New commits:
commit 80d41944b9f37c2079d8fbdc03cb68ca61406d70
Author: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
AuthorDate: Thu Apr 23 15:48:19 2026 +0900
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri Apr 24 07:39:27 2026 +0000

sc: Some fixes for SheetView found during code review

- guard GetHashCode() return value in getPartInfo / part hash
- remove empty namespace declaration
- allow .uno:SelectSheetView when the document is read only

Signed-off-by: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
Change-Id: Ie093f25d91e4f8c71d67dfb53e7af3dbef13e513
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1428
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sc/sdi/scalc.sdi b/engine/sc/sdi/scalc.sdi
index a295a223a109..1d7936929db1 100644
--- a/engine/sc/sdi/scalc.sdi
+++ b/engine/sc/sdi/scalc.sdi
@@ -6180,7 +6180,7 @@ SfxVoidItem SelectSheetView FID_SELECT_SHEET_VIEW
/* flags */
AutoUpdate = FALSE,
FastCall = TRUE,
- ReadOnlyDoc = FALSE,
+ ReadOnlyDoc = TRUE,
Toggle = FALSE,
Container = FALSE,
RecordAbsolute = FALSE,
diff --git a/engine/sc/source/ui/inc/viewfunc.hxx b/engine/sc/source/ui/inc/viewfunc.hxx
index cb8917d8b140..271ae9a41461 100644
--- a/engine/sc/source/ui/inc/viewfunc.hxx
+++ b/engine/sc/source/ui/inc/viewfunc.hxx
@@ -67,11 +67,6 @@ struct ScDataFormFragment
ScDataFormFragment(weld::Grid* pGrid, int nLine);
};

-namespace sc
-{
-
-}
-
class ScViewFunc : public ScTabView
{
private:
diff --git a/engine/sc/source/ui/unoobj/docuno.cxx b/engine/sc/source/ui/unoobj/docuno.cxx
index aca32c99fc74..5705aab83b2e 100644
--- a/engine/sc/source/ui/unoobj/docuno.cxx
+++ b/engine/sc/source/ui/unoobj/docuno.cxx
@@ -671,21 +671,21 @@ OUString ScModelObj::getPartInfo( int nPart )
const sc::SheetViewID nSheetViewID = pViewData->GetSheetViewIDForSheet(nPart);
if (nSheetViewID != sc::DefaultSheetViewID)
{
- SCTAB nDefaultViewTableNumber = rDocument.GetDefaultViewTableNumber(nPart);
- sal_Int64 nDefaultViewHashCode;
- rDocument.GetHashCode(nDefaultViewTableNumber, nDefaultViewHashCode);
-
jsonWriter.put("sheetviewid", int32_t(nSheetViewID));
- jsonWriter.put("defaultviewhash", int64_t(nDefaultViewHashCode));
+
+ SCTAB nDefaultViewTableNumber = rDocument.GetDefaultViewTableNumber(nPart);
+ sal_Int64 nDefaultViewHashCode = 0;
+ if (rDocument.GetHashCode(nDefaultViewTableNumber, nDefaultViewHashCode))
+ jsonWriter.put("defaultviewhash", int64_t(nDefaultViewHashCode));
}

OUString tabName;
pViewData->GetDocument().GetName(nPart, tabName);
jsonWriter.put("name", tabName);

- sal_Int64 hashCode;
- pViewData->GetDocument().GetHashCode(nPart, hashCode);
- jsonWriter.put("hash", hashCode);
+ sal_Int64 hashCode = 0;
+ if (pViewData->GetDocument().GetHashCode(nPart, hashCode))
+ jsonWriter.put("hash", hashCode);

Size lastColRow = getDataArea(nPart);
jsonWriter.put("lastcolumn", lastColRow.getWidth());

"Tomaž Vajngerl (via cogerrit)"

unread,
Apr 24, 2026, 3:47:08 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/source/filter/excel/export/NamedSheetViews.cxx | 4 ++--
engine/sc/source/ui/inc/undo/UndoSheetViewSortData.hxx | 4 ++--
engine/sc/source/ui/undo/UndoSheetViewSortData.cxx | 8 ++++----
3 files changed, 8 insertions(+), 8 deletions(-)

New commits:
commit 34d328a41b0b4651deef435b96f3ac821d3c22d8
Author: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
AuthorDate: Thu Apr 23 13:24:27 2026 +0900
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri Apr 24 07:46:48 2026 +0000

sc: Change the variable name, don't write XML_tableId

Rename:
maAutoFilterRangeBefore -> moAutoFilterRangeBefore
maAutoFilterRangeAfter -> moAutoFilterRangeAfter

We write XML_tableId with ID 0 for XML_nsvFilter, which is
probably wrong as auto-filter isn't a table, so remove that
and write a todo to add it when table support is added.

Signed-off-by: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
Change-Id: I1ac4a4c097add397dabbd2cc1c7acf8634d96f0c
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1429
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sc/source/filter/excel/export/NamedSheetViews.cxx b/engine/sc/source/filter/excel/export/NamedSheetViews.cxx
index 6979cce2971f..9902e1e9b231 100644
--- a/engine/sc/source/filter/excel/export/NamedSheetViews.cxx
+++ b/engine/sc/source/filter/excel/export/NamedSheetViews.cxx
@@ -300,8 +300,8 @@ void xcl::exp::NamedSheetViews::saveSheetView(const sax_fastparser::FSHelperPtr&
OString aRangeString = XclXmlUtils::ToOString(GetDoc(), aRange);
OString aFilterGUID = comphelper::xml::generateGUIDString();

- pStream->startElement(XML_nsvFilter, XML_filterId, aFilterGUID, XML_ref, aRangeString,
- XML_tableId, "0");
+ // TODO: emit XML_tableId when the filter is bound to a real table, not an anonymous DB range.
+ pStream->startElement(XML_nsvFilter, XML_filterId, aFilterGUID, XML_ref, aRangeString);

ScQueryParam aQueryParam;
pDBData->GetQueryParam(aQueryParam);
diff --git a/engine/sc/source/ui/inc/undo/UndoSheetViewSortData.hxx b/engine/sc/source/ui/inc/undo/UndoSheetViewSortData.hxx
index ab6aba4352bc..d2f6efdd2aff 100644
--- a/engine/sc/source/ui/inc/undo/UndoSheetViewSortData.hxx
+++ b/engine/sc/source/ui/inc/undo/UndoSheetViewSortData.hxx
@@ -37,8 +37,8 @@ class UndoSheetViewSortData
std::shared_ptr<DefaultViewSortData> mpDefaultViewSortDataAfter;

// Auto-filter DB range before/after
- std::optional<ScRange> maAutoFilterRangeBefore;
- std::optional<ScRange> maAutoFilterRangeAfter;
+ std::optional<ScRange> moAutoFilterRangeBefore;
+ std::optional<ScRange> moAutoFilterRangeAfter;

public:
/** Set context for operations on a sheet view tab. */
diff --git a/engine/sc/source/ui/undo/UndoSheetViewSortData.cxx b/engine/sc/source/ui/undo/UndoSheetViewSortData.cxx
index 31d170ae1bdc..1c696227967c 100644
--- a/engine/sc/source/ui/undo/UndoSheetViewSortData.cxx
+++ b/engine/sc/source/ui/undo/UndoSheetViewSortData.cxx
@@ -35,8 +35,8 @@ void UndoSheetViewSortData::setDefaultViewContext(SCTAB nDefaultViewTab,

void UndoSheetViewSortData::setAutoFilterRange(ScRange const& rBefore, ScRange const& rAfter)
{
- maAutoFilterRangeBefore = rBefore;
- maAutoFilterRangeAfter = rAfter;
+ moAutoFilterRangeBefore = rBefore;
+ moAutoFilterRangeAfter = rAfter;
}

void UndoSheetViewSortData::restore(ScDocShell& rDocShell, bool bUndo) const
@@ -71,12 +71,12 @@ void UndoSheetViewSortData::restore(ScDocShell& rDocShell, bool bUndo) const
}

// Restore auto-filter DB range
- if (maAutoFilterRangeBefore || maAutoFilterRangeAfter)
+ if (moAutoFilterRangeBefore || moAutoFilterRangeAfter)
{
ScDBData* pDBData = rDocument.GetAnonymousDBData(mnDefaultViewTab);
if (pDBData)
{
- ScRange const& rRange = bUndo ? *maAutoFilterRangeBefore : *maAutoFilterRangeAfter;
+ ScRange const& rRange = bUndo ? *moAutoFilterRangeBefore : *moAutoFilterRangeAfter;
pDBData->SetArea(rRange);
}
}

"Tomaž Vajngerl (via cogerrit)"

unread,
Apr 24, 2026, 3:57:33 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/inc/SheetView.hxx | 11 ++
engine/sc/qa/unit/NamedSheetViewsImportExportTest.cxx | 60 +++++++++++++++
engine/sc/source/core/data/SheetViewManager.cxx | 6 +
engine/sc/source/filter/excel/export/NamedSheetViews.cxx | 11 +-
engine/sc/source/filter/oox/NamedSheetViewImporter.cxx | 5 +
5 files changed, 85 insertions(+), 8 deletions(-)

New commits:
commit bb58d472a9b1d0045c01ff9d344c81def3264978
Author: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
AuthorDate: Thu Apr 23 13:50:26 2026 +0900
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri Apr 24 07:57:05 2026 +0000

sc: Preserve SheetView GUID in OOXML round-trip, generate if new

Element namedSheetView attribute @id and nsvFilter attribute
@filterId were regenerated on every save, so each round trip
churned the view's identity. Store both on SheetView and create
fresh ones when a new sheet view is created.

Signed-off-by: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
Change-Id: I64aeb233e1bed4abd6ec900cb1061dfebe73865c
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1430
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sc/inc/SheetView.hxx b/engine/sc/inc/SheetView.hxx
index bf97c6dc59ee..9e84b98b59d1 100644
--- a/engine/sc/inc/SheetView.hxx
+++ b/engine/sc/inc/SheetView.hxx
@@ -11,6 +11,7 @@

#include "scdllapi.h"
#include "types.hxx"
+#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include "SheetViewTypes.hxx"
#include "sortparam.hxx"
@@ -86,6 +87,10 @@ private:
OUString maName;
SheetViewID mnID;

+ // GUIDs
+ OString maGUID;
+ OString maFilterGUID;
+
/** Sort data - nullptr when no sort has been performed. */
std::shared_ptr<SheetViewSortData> mpSortData;

@@ -113,6 +118,12 @@ public:
OUString const& GetName() const { return maName; }
void SetName(OUString const& rName) { maName = rName; }

+ OString const& GetGUID() const { return maGUID; }
+ void SetGUID(OString const& rGUID) { maGUID = rGUID; }
+
+ OString const& GetFilterGUID() const { return maFilterGUID; }
+ void SetFilterGUID(OString const& rGUID) { maFilterGUID = rGUID; }
+
/** A sheet view is valid if the pointer to the table is set */
bool isValid() const;

diff --git a/engine/sc/qa/unit/NamedSheetViewsImportExportTest.cxx b/engine/sc/qa/unit/NamedSheetViewsImportExportTest.cxx
index a8fd68e3544e..9b830b3dd001 100644
--- a/engine/sc/qa/unit/NamedSheetViewsImportExportTest.cxx
+++ b/engine/sc/qa/unit/NamedSheetViewsImportExportTest.cxx
@@ -175,6 +175,66 @@ CPPUNIT_TEST_FIXTURE(NamedSheetViewsImportExportTest, testRoundtripModelState)
}
}

+CPPUNIT_TEST_FIXTURE(NamedSheetViewsImportExportTest, testRoundtripGUIDs)
+{
+ loadFromFile(u"xlsx/NamedSheetViews.xlsx");
+
+ OString aView1GUID;
+ OString aView1FilterGUID;
+ OString aView2GUID;
+ OString aView2FilterGUID;
+ {
+ ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(mxComponent);
+ CPPUNIT_ASSERT(pModelObj);
+ ScDocument* pDocument = pModelObj->GetDocument();
+ CPPUNIT_ASSERT(pDocument);
+
+ auto pManager = pDocument->GetSheetViewManager(SCTAB(0));
+ CPPUNIT_ASSERT(pManager);
+
+ for (auto& rSheetView : pManager->iterateValidSheetViews())
+ {
+ if (rSheetView.GetName() == u"View1")
+ {
+ aView1GUID = rSheetView.GetGUID();
+ aView1FilterGUID = rSheetView.GetFilterGUID();
+ }
+ else if (rSheetView.GetName() == u"View2")
+ {
+ aView2GUID = rSheetView.GetGUID();
+ aView2FilterGUID = rSheetView.GetFilterGUID();
+ }
+ }
+
+ // Imported GUIDs must not be empty.
+ CPPUNIT_ASSERT(!aView1GUID.isEmpty());
+ CPPUNIT_ASSERT(!aView1FilterGUID.isEmpty());
+ CPPUNIT_ASSERT(!aView2GUID.isEmpty());
+ CPPUNIT_ASSERT(!aView2FilterGUID.isEmpty());
+ }
+
+ save(TestFilter::XLSX);
+
+ xmlDocUniquePtr pNsv = parseExport(u"xl/namedSheetViews/namedSheetView1.xml"_ustr);
+ CPPUNIT_ASSERT(pNsv);
+
+ // Exported @id / @filterId must match the GUIDs held on the runtime SheetView
+ CPPUNIT_ASSERT_EQUAL(
+ aView1GUID,
+ getXPath(pNsv, "/xnsv:namedSheetViews/xnsv:namedSheetView[1]", "id").toUtf8());
+ CPPUNIT_ASSERT_EQUAL(
+ aView1FilterGUID,
+ getXPath(pNsv, "/xnsv:namedSheetViews/xnsv:namedSheetView[1]/xnsv:nsvFilter", "filterId")
+ .toUtf8());
+ CPPUNIT_ASSERT_EQUAL(
+ aView2GUID,
+ getXPath(pNsv, "/xnsv:namedSheetViews/xnsv:namedSheetView[2]", "id").toUtf8());
+ CPPUNIT_ASSERT_EQUAL(
+ aView2FilterGUID,
+ getXPath(pNsv, "/xnsv:namedSheetViews/xnsv:namedSheetView[2]/xnsv:nsvFilter", "filterId")
+ .toUtf8());
+}
+
CPPUNIT_TEST_FIXTURE(NamedSheetViewsImportExportTest, testMultiSheetRoundtripVisibility)
{
loadFromFile(u"xlsx/NamedSheetViews.xlsx");
diff --git a/engine/sc/source/core/data/SheetViewManager.cxx b/engine/sc/source/core/data/SheetViewManager.cxx
index 8193fea6adf0..b8b07cad313b 100644
--- a/engine/sc/source/core/data/SheetViewManager.cxx
+++ b/engine/sc/source/core/data/SheetViewManager.cxx
@@ -11,6 +11,7 @@
#include <table.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
+#include <comphelper/xmltools.hxx>

namespace sc
{
@@ -19,7 +20,10 @@ SheetViewManager::SheetViewManager() {}
SheetViewID SheetViewManager::create(ScTable* pSheetViewTable)
{
SheetViewID nID(maViews.size());
- maViews.emplace_back(std::make_shared<SheetView>(pSheetViewTable, generateName(), nID));
+ auto pView = std::make_shared<SheetView>(pSheetViewTable, generateName(), nID);
+ pView->SetGUID(comphelper::xml::generateGUIDString());
+ pView->SetFilterGUID(comphelper::xml::generateGUIDString());
+ maViews.emplace_back(std::move(pView));
mnSheetViewCount++;
return nID;
}
diff --git a/engine/sc/source/filter/excel/export/NamedSheetViews.cxx b/engine/sc/source/filter/excel/export/NamedSheetViews.cxx
index 9902e1e9b231..62b55085d4a1 100644
--- a/engine/sc/source/filter/excel/export/NamedSheetViews.cxx
+++ b/engine/sc/source/filter/excel/export/NamedSheetViews.cxx
@@ -281,10 +281,8 @@ void xcl::exp::NamedSheetViews::saveSortRules(const sax_fastparser::FSHelperPtr&
void xcl::exp::NamedSheetViews::saveSheetView(const sax_fastparser::FSHelperPtr& pStream,
const sc::SheetView& rSheetView)
{
- OString aGUID = comphelper::xml::generateGUIDString();
-
pStream->startElement(XML_namedSheetView, XML_name, rSheetView.GetName().toUtf8(), XML_id,
- aGUID);
+ rSheetView.GetGUID());

// Get the view tab to access its filter/sort data
SCTAB nViewTab = rSheetView.getTableNumber();
@@ -298,10 +296,9 @@ void xcl::exp::NamedSheetViews::saveSheetView(const sax_fastparser::FSHelperPtr&
aRange.aEnd.SetTab(nViewTab);

OString aRangeString = XclXmlUtils::ToOString(GetDoc(), aRange);
- OString aFilterGUID = comphelper::xml::generateGUIDString();
-
- // TODO: emit XML_tableId when the filter is bound to a real table, not an anonymous DB range.
- pStream->startElement(XML_nsvFilter, XML_filterId, aFilterGUID, XML_ref, aRangeString);
+ // TODO: emit XML_tableId when the filter is bound to a real table
+ pStream->startElement(XML_nsvFilter, XML_filterId, rSheetView.GetFilterGUID(), XML_ref,
+ aRangeString);

ScQueryParam aQueryParam;
pDBData->GetQueryParam(aQueryParam);
diff --git a/engine/sc/source/filter/oox/NamedSheetViewImporter.cxx b/engine/sc/source/filter/oox/NamedSheetViewImporter.cxx
index fba97611292d..cb2063efc785 100644
--- a/engine/sc/source/filter/oox/NamedSheetViewImporter.cxx
+++ b/engine/sc/source/filter/oox/NamedSheetViewImporter.cxx
@@ -57,7 +57,12 @@ void NamedSheetViewImporter::finalizeImport()

auto pSheetView = pSheetViewManager->get(nSheetViewID);
if (pSheetView)
+ {
pSheetView->SetName(rViewData.maName);
+ pSheetView->SetGUID(rViewData.maID.toUtf8());
+ if (!rViewData.maNsvFilters.empty())
+ pSheetView->SetFilterGUID(rViewData.maNsvFilters.front().maFilterID.toUtf8());
+ }

// Apply filters and sort for each nsvFilter
for (const auto& rNsvFilter : rViewData.maNsvFilters)

"Tomaž Vajngerl (via cogerrit)"

unread,
Apr 24, 2026, 7:24:42 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/inc/document.hxx | 30 +++++++++++++
engine/sc/source/ui/operation/InsertSheetViewOperation.cxx | 3 -
2 files changed, 31 insertions(+), 2 deletions(-)

New commits:
commit 9c1c6d14aee1285c0bf7be1efbfdb1e5c794c39f
Author: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
AuthorDate: Thu Apr 23 15:40:08 2026 +0900
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri Apr 24 11:23:56 2026 +0000

sc: Guard for BeginDrawUndo() capture windows

Add sc::DrawUndoGuard - constructor opens the capture window (when
enabled), destructor drains any still-pending states. If an undo
action consumes the window in between, the destructor's drain is
a harmless no-op.

Use it in InsertSheetViewOperation, but could be used in other
places as well. Will be done in a follow-up.

Signed-off-by: Tomaž Vajngerl <tomaz.v...@collabora.co.uk>
Change-Id: I0e829c6b025a1fab91b63a350d2a8034f0041100
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1431
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sc/inc/document.hxx b/engine/sc/inc/document.hxx
index cbc849a9e102..f402d280ddd0 100644
--- a/engine/sc/inc/document.hxx
+++ b/engine/sc/inc/document.hxx
@@ -2876,6 +2876,36 @@ private:

typedef std::unique_ptr<ScDocument, o3tl::default_delete<ScDocument>> ScDocumentUniquePtr;

+namespace sc
+{
+/** Guard for a BeginDrawUndo() capture window.
+ * Opens on construction, drains on destruction. If an undo action
+ * consumes the window in between, the destructor's drain is
+ * a harmless no-op. */
+class DrawUndoGuard
+{
+ ScDocument* mpDoc;
+
+public:
+ DrawUndoGuard(ScDocument& rDoc, bool bEnabled)
+ : mpDoc(bEnabled ? &rDoc : nullptr)
+ {
+ if (mpDoc)
+ mpDoc->BeginDrawUndo();
+ }
+ ~DrawUndoGuard()
+ {
+ if (mpDoc)
+ {
+ if (auto* pLayer = mpDoc->GetDrawLayer())
+ (void)pLayer->GetCalcUndo();
+ }
+ }
+ DrawUndoGuard(const DrawUndoGuard&) = delete;
+ DrawUndoGuard& operator=(const DrawUndoGuard&) = delete;
+};
+} // end sc namespace
+
/**
* Instantiate this to ensure that subsequent modification of
* the document will cause an assertion failure while this is
diff --git a/engine/sc/source/ui/operation/InsertSheetViewOperation.cxx b/engine/sc/source/ui/operation/InsertSheetViewOperation.cxx
index f22c3f38729d..232c1dc0345c 100644
--- a/engine/sc/source/ui/operation/InsertSheetViewOperation.cxx
+++ b/engine/sc/source/ui/operation/InsertSheetViewOperation.cxx
@@ -40,8 +40,7 @@ bool InsertSheetViewOperation::runImplementation()
if (mbRecord && !rDoc.IsUndoEnabled())
mbRecord = false;

- if (mbRecord)
- rDoc.BeginDrawUndo();
+ DrawUndoGuard aDrawUndoGuard(rDoc, mbRecord);

auto[nSheetViewID, nSheetViewTab] = rDoc.CreateNewSheetView(mnTab);
if (nSheetViewID == InvalidSheetViewID)

"Noel Grandin (via cogerrit)"

unread,
Apr 24, 2026, 8:11:52 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/source/filter/excel/xistream.cxx | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

New commits:
commit b71a8f85dd1b99a8d879bcf5ddebd185a4354c85
Author: Noel Grandin <noel.g...@collabora.co.uk>
AuthorDate: Thu Apr 23 10:28:05 2026 +0200
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Fri Apr 24 12:10:43 2026 +0000

ccrashtesting: assert on exporting forum-mso-en4-531883.xls to xlsx

since:
commit 5c841b381fe16634c51121b351c89154a25eb8d9
Date: Tue Mar 17 16:33:19 2026 +0530
XLSX: Truncate external sheet names if the length is > 31

Bug document: forum-mso-en4-109082.xls

Change-Id: I0050bd63a28c74d2e337073f2815c6ffd17478c9
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1433
Tested-by: Caolán McNamara <caolan....@collabora.com>
Reviewed-by: Caolán McNamara <caolan....@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sc/source/filter/excel/xistream.cxx b/engine/sc/source/filter/excel/xistream.cxx
index 1fa5119a0e26..961074d688d0 100644
--- a/engine/sc/source/filter/excel/xistream.cxx
+++ b/engine/sc/source/filter/excel/xistream.cxx
@@ -894,6 +894,18 @@ OUString XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
OUString aRet( ReadRawUniString( nChars, b16Bit ) );
Ignore( nExtSize );
+
+ OString aUtf8Check;
+ if (!aRet.convertToString(
+ &aUtf8Check, RTL_TEXTENCODING_UTF8,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+ {
+ SAL_WARN("sc", "invalid utf8 string, doing best-effort fix");
+ aRet.convertToString(&aUtf8Check, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
+ aRet = OStringToOUString(aUtf8Check, RTL_TEXTENCODING_UTF8);
+ }
+
return aRet;
}

@@ -953,6 +965,17 @@ OUString XclImpStream::ReadRawByteString( sal_uInt16 nChars )
sal_uInt16 nCharsRead = ReadRawData( pcBuffer.get(), nChars );
pcBuffer[ nCharsRead ] = '\0';
OUString aRet( pcBuffer.get(), strlen(pcBuffer.get()), mrRoot.GetTextEncoding() );
+
+ OString aUtf8Check;
+ if (!aRet.convertToString(
+ &aUtf8Check, RTL_TEXTENCODING_UTF8,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+ {
+ SAL_WARN("sc", "invalid utf8 string, doing best-effort fix");
+ aRet.convertToString(&aUtf8Check, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
+ aRet = OStringToOUString(aUtf8Check, RTL_TEXTENCODING_UTF8);
+ }
return aRet;
}


"Caolán McNamara (via cogerrit)"

unread,
Apr 24, 2026, 2:52:25 PM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sc/source/filter/xml/xmlexprt.cxx | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

New commits:
commit 017fee252d9ef2648da3f231416f39f71933d77c
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Mon Apr 20 18:42:55 2026 +0000
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Fri Apr 24 18:52:04 2026 +0000

crashtesting: divide by zero results in corrupted values

this is an issue since:

commit 5bc6f478d8b977b9c28967bb32c9cb4bea638c34
Date: Thu Mar 26 14:47:10 2026 +0200

Fraction->double in sc

reproducible with instdir/program/soffice --headless --convert-to ods gnome597720-1.xlsx

Change-Id: Ife3f5552e1fc66e983e39196f64f0118f4825e43
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1230
Reviewed-by: Noel Grandin <noel.g...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1380
Reviewed-by: Caolán McNamara <caolan....@collabora.com>

diff --git a/engine/sc/source/filter/xml/xmlexprt.cxx b/engine/sc/source/filter/xml/xmlexprt.cxx
index cd10964b13bf..9763a6cd3b0f 100644
--- a/engine/sc/source/filter/xml/xmlexprt.cxx
+++ b/engine/sc/source/filter/xml/xmlexprt.cxx
@@ -3657,8 +3657,22 @@ void ScXMLExport::WriteShapes(const ScDocument& rDoc, const ScMyCell& rMyCell)

if (bNeedsRestoreSize)
{
- double fScaleWidthInvers = 1.0 / fScaleWidth;
- double fScaleHeightInvers = 1.0 / fScaleHeight;
+ double fScaleWidthInvers;
+ if (fScaleWidth == 0.0)
+ {
+ SAL_WARN("sc", "WriteShapes: zero scale width, skipping inverse resize");
+ fScaleWidthInvers = 1.0;
+ }
+ else
+ fScaleWidthInvers = 1.0 / fScaleWidth;
+ double fScaleHeightInvers;
+ if (fScaleHeight == 0.0)
+ {
+ SAL_WARN("sc", "WriteShapes: zero scale height, skipping inverse resize");
+ fScaleHeightInvers = 1.0;
+ }
+ else
+ fScaleHeightInvers = 1.0 / fScaleHeight;
pObj->NbcResize(aFullTopPoint, fScaleWidthInvers, fScaleHeightInvers);
}
if (bNeedsRestorePosition)

"Caolán McNamara (via cogerrit)"

unread,
Apr 28, 2026, 7:52:24 AM (23 hours ago) Apr 28
to collaboraon...@googlegroups.com
engine/sc/inc/chgtrack.hxx | 3 +-
engine/sc/source/core/tool/chgtrack.cxx | 7 +++-
engine/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx | 15 ++++++----
3 files changed, 17 insertions(+), 8 deletions(-)

New commits:
commit b5b56a2239369e45d7fac2ea965558a1f337b602
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Sun Apr 26 17:48:52 2026 +0000
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Tue Apr 28 11:51:48 2026 +0000

drop malformed duplicate-id calc change track actions

Signed-off-by: Caolán McNamara <caolan....@collabora.com>
Change-Id: I0d532eb84d122e39ce71e94b4760b94cd636eeea
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1691
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sc/inc/chgtrack.hxx b/engine/sc/inc/chgtrack.hxx
index b6c1612fb987..6cb1270c5a00 100644
--- a/engine/sc/inc/chgtrack.hxx
+++ b/engine/sc/inc/chgtrack.hxx
@@ -1115,7 +1115,8 @@ public:

sal_uLong AddLoadedGenerated( const ScCellValue& rNewCell,
const ScBigRange& aBigRange, const OUString& sNewValue ); // only to use in the XML import
- void AppendLoaded( std::unique_ptr<ScChangeAction> pAppend ); // this is only for the XML import public, it should be protected
+ // returns false if the action number is already in use, in which case the new duplicate is dropped
+ bool AppendLoaded( std::unique_ptr<ScChangeAction> pAppend ); // this is only for the XML import public, it should be protected
void SetActionMax(sal_uLong nTempActionMax)
{ nActionMax = nTempActionMax; } // only to use in the XML import

diff --git a/engine/sc/source/core/tool/chgtrack.cxx b/engine/sc/source/core/tool/chgtrack.cxx
index 0300388bd669..96bfb1916154 100644
--- a/engine/sc/source/core/tool/chgtrack.cxx
+++ b/engine/sc/source/core/tool/chgtrack.cxx
@@ -2315,10 +2315,12 @@ void ScChangeTrack::MasterLinks( ScChangeAction* pAppend )
}
}

-void ScChangeTrack::AppendLoaded( std::unique_ptr<ScChangeAction> pActionParam )
+bool ScChangeTrack::AppendLoaded( std::unique_ptr<ScChangeAction> pActionParam )
{
+ auto [it, inserted] = aMap.insert(std::make_pair(pActionParam->GetActionNumber(), pActionParam.get()));
+ if (!inserted)
+ return false;
ScChangeAction* pAppend = pActionParam.release();
- aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) );
if ( !pLast )
pFirst = pLast = pAppend;
else
@@ -2328,6 +2330,7 @@ void ScChangeTrack::AppendLoaded( std::unique_ptr<ScChangeAction> pActionParam )
pLast = pAppend;
}
MasterLinks( pAppend );
+ return true;
}

void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction )
diff --git a/engine/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx b/engine/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
index 45b6c0cd34d2..f26422e7d218 100644
--- a/engine/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
+++ b/engine/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
@@ -719,8 +719,10 @@ void ScXMLChangeTrackingImportHelper::CreateChangeTrack(ScDocument* pDoc)
// old files didn't store nanoseconds, disable until encountered
pTrack->SetTimeNanoSeconds( false );

- for (const auto & rAction : aActions)
+ auto aItr = aActions.begin();
+ while (aItr != aActions.end())
{
+ const auto& rAction = *aItr;
std::unique_ptr<ScChangeAction> pAction;

switch (rAction->nActionType)
@@ -764,17 +766,20 @@ void ScXMLChangeTrackingImportHelper::CreateChangeTrack(ScDocument* pDoc)
}
}

- if (pAction)
- pTrack->AppendLoaded(std::move(pAction));
+ // Malformed documents can repeat the same XML id across actions. If
+ // this happens drop entries whose action number is already in the track.
+ if (pAction && pTrack->AppendLoaded(std::move(pAction)))
+ ++aItr;
else
{
- OSL_FAIL("no action");
+ SAL_WARN("sc.filter", "Dropping malformed change track entry");
+ aItr = aActions.erase(aItr);
}
}
if (pTrack->GetLast())
pTrack->SetActionMax(pTrack->GetLast()->GetActionNumber());

- auto aItr = aActions.begin();
+ aItr = aActions.begin();
while (aItr != aActions.end())
{
SetDependencies(aItr->get(), *pDoc);

"Caolán McNamara (via cogerrit)"

unread,
Apr 28, 2026, 9:13:52 AM (21 hours ago) Apr 28
to collaboraon...@googlegroups.com
engine/sc/source/filter/inc/sheetdatacontext.hxx | 1 +
engine/sc/source/filter/oox/sheetdatacontext.cxx | 10 +++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)

New commits:
commit b42191f53b2013c452faa86adc741db82297e8cf
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Sun Apr 26 21:11:09 2026 +0100
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Tue Apr 28 13:13:18 2026 +0000

crashtesting: failure to load forum-mso-en4-726282.xlsx

since:

commit d825eef9ced628fc460f4d539cd1b19d6ad5fe42
Date: Mon Mar 30 12:07:52 2026 +0530

XLSX: Handle import of empty formula

Change-Id: I07dda61f531407bf6b57709a316b6f38406e0b2f
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1692
Reviewed-by: Karthik Godha <karthi...@collabora.com>
Tested-by: Caolán McNamara <caolan....@collabora.com>

diff --git a/engine/sc/source/filter/inc/sheetdatacontext.hxx b/engine/sc/source/filter/inc/sheetdatacontext.hxx
index af1fe77e70ea..997d9d8d8295 100644
--- a/engine/sc/source/filter/inc/sheetdatacontext.hxx
+++ b/engine/sc/source/filter/inc/sheetdatacontext.hxx
@@ -114,6 +114,7 @@ private:
BinAddress maCurrPos; /// Current cell position (BIFF12 only).
bool mbHasFormula; /// True = current cell has formula data (OOXML only).
bool mbValidRange; /// True = maFmlaData.maFormulaRef is valid (OOXML only).
+ bool mbCalcAlways; /// True = formula has ca="1" (often a matrix-reference placeholder).

sal_Int32 mnRow; /// row index (0-based)
sal_Int32 mnCol; /// column index (0-based)
diff --git a/engine/sc/source/filter/oox/sheetdatacontext.cxx b/engine/sc/source/filter/oox/sheetdatacontext.cxx
index ca419be590be..7b6c928483e3 100644
--- a/engine/sc/source/filter/oox/sheetdatacontext.cxx
+++ b/engine/sc/source/filter/oox/sheetdatacontext.cxx
@@ -63,6 +63,7 @@ SheetDataContext::SheetDataContext( WorksheetFragmentBase& rFragment ) :
mnSheet( rFragment.getSheetIndex() ),
mbHasFormula( false ),
mbValidRange( false ),
+ mbCalcAlways( false ),
mnRow( -1 ),
mnCol( -1 )
{
@@ -134,7 +135,13 @@ void SheetDataContext::onEndElement()
// a) need to set format first
// :/
case XML_normal:
- if (!maFormulaStr.isEmpty())
+ // An empty <f/> without ca is a standalone broken formula and
+ // should be skipped to avoid creating a formula cell with no
+ // tokens.
+ // An empty <f/> with ca="1" is a matrix-reference placeholder
+ // for an array formula whose master is a different cell; the
+ // master will create the matrix cells via setMatrixCells.
+ if (!maFormulaStr.isEmpty() || mbCalcAlways)
{
setCellFormula(maCellData.maCellAddr, maFormulaStr);
mrSheetData.setCellFormat(maCellData);
@@ -370,6 +377,7 @@ void SheetDataContext::importFormula( const AttributeList& rAttribs )

maFmlaData.mnFormulaType = rAttribs.getToken( XML_t, XML_normal );
maFmlaData.mnSharedId = rAttribs.getInteger( XML_si, -1 );
+ mbCalcAlways = rAttribs.getBool( XML_ca, false );

if( maFmlaData.mnFormulaType == XML_dataTable )
{

"Caolán McNamara (via cogerrit)"

unread,
6:21 AM (22 minutes ago) 6:21 AM
to collaboraon...@googlegroups.com
engine/sc/source/core/tool/compiler.cxx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

New commits:
commit 0b7a9149d7c7b5e044bb4f02668297bdf41b64d6
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Sun Apr 26 17:12:34 2026 +0100
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Wed Apr 29 10:20:26 2026 +0000

A formula of length L, composed entirely of open tokens, needs L+1 slots

Signed-off-by: Caolán McNamara <caolan....@collabora.com>
Change-Id: I7cf1fd4fdaca780a8f0cf0d0b9d10def9b3af1ef
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1690
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sc/source/core/tool/compiler.cxx b/engine/sc/source/core/tool/compiler.cxx
index e94d331d58c4..efed76f1e4c6 100644
--- a/engine/sc/source/core/tool/compiler.cxx
+++ b/engine/sc/source/core/tool/compiler.cxx
@@ -5058,8 +5058,9 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul
bool bUseFunctionStack = (bPODF || bOOXML);
const size_t nAlloc = 512;
FunctionStack aFuncs[ nAlloc ];
- FunctionStack* pFunctionStack = (bUseFunctionStack && o3tl::make_unsigned(rFormula.getLength()) > nAlloc ?
- new FunctionStack[rFormula.getLength()] : &aFuncs[0]);
+ // A formula of length L composed entirely of open tokens needs L+1 slots,
+ FunctionStack* pFunctionStack = (bUseFunctionStack && o3tl::make_unsigned(rFormula.getLength()) >= nAlloc ?
+ new FunctionStack[rFormula.getLength() + 1] : &aFuncs[0]);
pFunctionStack[0].eOp = ocNone;
pFunctionStack[0].nSep = 0;
size_t nFunction = 0;

Reply all
Reply to author
Forward
0 new messages