sw/inc/ndarr.hxx | 7 - sw/qa/extras/uiwriter/data/floattable-split.docx |binary sw/qa/extras/uiwriter/uiwriter9.cxx | 148 +++++++++++++++++++++++ sw/source/core/docnode/ndtbl.cxx | 141 ++++++++++++++++++++- sw/source/core/inc/UndoTable.hxx | 7 - sw/source/core/undo/untbl.cxx | 25 +++ sw/source/uibase/inc/wrtsh.hxx | 2 7 files changed, 315 insertions(+), 15 deletions(-)
New commits: commit 6f55b9a74f8fdd8609e1aa72388a5f8b97dfcea0 Author: Michael Stahl <michael.st...@collabora.com> AuthorDate: Thu Aug 21 18:00:02 2025 +0200 Commit: Michael Stahl <michael.st...@collabora.com> CommitDate: Fri Aug 22 17:33:21 2025 +0200 sw: floating table split The problem is that the Table Split feature on a floating table results in 2 tables inside 1 frame, which then cannot be exported to DOCX as a floating table. Split the fly frame in this case, and add an anchor node because every floating table needs its own anchor node. Change-Id: I7444a75a953fcea60ffc92c2fa7eaca1b044f54b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190009 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx index fdf0eec7849b..51aa50bc84ba 100644 --- a/sw/inc/ndarr.hxx +++ b/sw/inc/ndarr.hxx @@ -26,6 +26,7 @@ #include <vector> #include <memory> #include <optional> +#include <tuple> #include "bparr.hxx" #include "ndtyp.hxx" @@ -39,6 +40,7 @@ class SwAttrSet; class SfxItemSet; class SwContentNode; class SwDoc; +class SwFrameFormat; class SwGrfFormatColl; class SwGrfNode; class SwNode; @@ -302,11 +304,14 @@ public: Is the flag bCalcNewSize set to TRUE, the new SSize for both tables is calculated from the Maximum of the boxes, provided SSize is set "absolute" (LONG_MAX). - (Momentarily this is needed only for the RTF-parser.) */ + */ SwTableNode* SplitTable( SwNode& rPos, bool bAfter = true, bool bCalcNewSize = false ); + void SplitFloatingTableFrame(SwTableNode & rNewTableNode, + ::std::tuple<SwStartNode &, SwFrameFormat &, SwTextNode &> floatingFrame); /// Two Tables that are following one another are merged. bool MergeTable( SwNode& rPos, bool bWithPrev = true ); + void MergeFloatingTableFrame(SwNodeOffset nEndOfOldFlyIndex); /// Insert a new SwSection. SwSectionNode* InsertTextSection(SwNode& rNd, diff --git a/sw/qa/extras/uiwriter/data/floattable-split.docx b/sw/qa/extras/uiwriter/data/floattable-split.docx new file mode 100644 index 000000000000..2e2c9c705df9 Binary files /dev/null and b/sw/qa/extras/uiwriter/data/floattable-split.docx differ diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx b/sw/qa/extras/uiwriter/uiwriter9.cxx index 883db6d14a77..417f8302a939 100644 --- a/sw/qa/extras/uiwriter/uiwriter9.cxx +++ b/sw/qa/extras/uiwriter/uiwriter9.cxx @@ -165,6 +165,154 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159377) CPPUNIT_ASSERT_EQUAL(SwNodeOffset(28), pDoc->GetNodes().Count()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testSplitFloatingTable) +{ + createSwDoc("floattable-split.docx"); + + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + + { + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // apparently follow fly is on the text frame of page 1 even though + // positioned on page 2... + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 2); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab/row", + 5); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab/row", + 4); + } + + pWrtShell->GotoFly(u"Frame1"_ustr); + pWrtShell->Down(/*bSelect=*/false, 3); + + pWrtShell->SplitTable(SplitTable_HeadlineOption::BorderCopy); + + { + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/tab", 1); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/tab/row", 3); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly", 2); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab/row", + 2); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab/row", + 4); + } + + pWrtShell->Do(SwWrtShell::UNDO); + + { + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // apparently follow fly is on the text frame of page 1 even though + // positioned on page 2... + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 2); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab/row", + 5); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[2]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab/row", + 4); + } + + pWrtShell->Do(SwWrtShell::REDO); + + { + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/tab", 1); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/tab/row", 3); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly", 2); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab/row", + 2); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab/row", + 4); + } + + // now check that these round-trip as floating tables + saveAndReload(u"Office Open XML Text"_ustr); + + { + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/tab", 1); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/tab/row", 3); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly", 2); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly/txt", 0); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab", + 1); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top < " + "/root/page[2]/infos/bounds/@top]/tab/row", + 2); + assertXPath(pXmlDoc, + "/root/page[1]/body/txt[3]/anchored/fly[infos/bounds/@top > " + "/root/page[2]/infos/bounds/@top]/tab/row", + 4); + } +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testPasteTableInMiddleOfParagraph) { createSwDoc(); diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx index 0ee003d24c91..cd0f93908299 100644 --- a/sw/source/core/docnode/ndtbl.cxx +++ b/sw/source/core/docnode/ndtbl.cxx @@ -28,10 +28,12 @@ #include <svl/stritem.hxx> #include <editeng/shaditem.hxx> #include <fmtfsize.hxx> +#include <formatflysplit.hxx> #include <fmtornt.hxx> #include <fmtfordr.hxx> #include <fmtpdsc.hxx> #include <fmtanchr.hxx> +#include <fmtcntnt.hxx> #include <fmtlsplt.hxx> #include <frmatr.hxx> #include <cellfrm.hxx> @@ -80,6 +82,7 @@ #include <strings.hrc> #include <docsh.hxx> #include <unochart.hxx> +#include <unoframe.hxx> #include <node.hxx> #include <ndtxt.hxx> #include <cstdlib> @@ -3175,6 +3178,118 @@ void sw_BoxSetSplitBoxFormats( SwTableBox* pBox, SwCollectTableLineBoxes* pSplPa } } +namespace { + +::std::optional<::std::tuple<SwStartNode &, SwFrameFormat &, SwTextNode &>> +FindFloatingTable(SwTableNode & rTableNode) +{ + SwStartNode *const pStartNode{rTableNode.GetNodes()[rTableNode.GetIndex()-1]->GetStartNode()}; + if (pStartNode + && pStartNode->GetStartNodeType() == SwFlyStartNode + && pStartNode->EndOfSectionIndex()-1 == rTableNode.EndOfSectionIndex()) + { + SwFrameFormat *const pFormat{rTableNode.GetFlyFormat()}; + if (pFormat && pFormat->GetFlySplit().GetValue()) + { + SwFormatAnchor const& rAnchor{pFormat->GetAnchor()}; + SwNode *const pNode{rAnchor.GetAnchorNode()}; + if (pNode && pNode->IsTextNode() // cannot work for at-fly, at-page + && rAnchor.GetAnchorId() != RndStdIds::FLY_AS_CHAR) + { + return {{*pStartNode, *pFormat, *pNode->GetTextNode()}}; + } + } + } + return {}; +} + +} // namespace + +void SwNodes::MergeFloatingTableFrame(SwNodeOffset const nEndOfOldFlyIndex) +{ + SwEndNode *const pFrameEndNode{(*this)[nEndOfOldFlyIndex]->GetEndNode()}; + assert(pFrameEndNode); + SwStartNode *const pFrameStartNode{pFrameEndNode->StartOfSectionNode()}; + assert(pFrameStartNode && pFrameStartNode->GetStartNodeType() == SwFlyStartNode); + SwStartNode *const pNewFrameStartNode{(*this)[nEndOfOldFlyIndex+1]->GetStartNode()}; + assert(pNewFrameStartNode && pNewFrameStartNode->GetStartNodeType() == SwFlyStartNode); + SwTableNode *const pNewTableNode{(*this)[nEndOfOldFlyIndex+2]->GetTableNode()}; + assert(pNewTableNode); + assert(pNewTableNode->StartOfSectionNode() == pNewFrameStartNode); + SwTableNode *const pOldTableNode{(*this)[pFrameStartNode->GetIndex()+1]->GetTableNode()}; + assert(pOldTableNode); + assert(pOldTableNode->StartOfSectionNode() == pFrameStartNode); + + SwFrameFormat *const pNewFlyFormat{pNewTableNode->GetFlyFormat()}; + pNewFlyFormat->DelFrames(); + + // reset anchor item + SwFrameFormat & rFlyFormat{*pOldTableNode->GetFlyFormat()}; + SwFormatAnchor anchor{rFlyFormat.GetAnchor()}; + SwNodeIndex const newAnchor(*(*this)[anchor.GetAnchorNode()->GetIndex()]); + SwTextNode *const pOldAnchorNode{(*this)[anchor.GetAnchorNode()->GetIndex()+1]->GetTextNode()}; + assert(pOldAnchorNode); + SwPosition const pos{*pOldAnchorNode}; + anchor.SetAnchor(&pos); + rFlyFormat.SetFormatAttr(anchor); + + // delete inserted anchor node + { + SwPaM pamToCorr(newAnchor); + SwPaM pamSafe(newAnchor); + bool const success = pamSafe.Move(fnMoveForward, GoInContent); + assert(success); (void) success; // must move to old anchor node + ::PaMCorrAbs(pamToCorr, *pamSafe.GetPoint()); + } + Delete(newAnchor); + + // delete new format (also deletes its SdrObject) + m_rMyDoc.DelFrameFormat(pNewFlyFormat); + + // merge fly nodes/delete inserted nodes + pFrameStartNode->m_pEndOfSection = pNewFrameStartNode->EndOfSectionNode(); + pFrameStartNode->EndOfSectionNode()->m_pStartOfSection = pFrameStartNode; + pNewTableNode->m_pStartOfSection = pFrameStartNode; + DelNodes(SwNodeIndex(*pFrameEndNode), SwNodeOffset(2)); +} + +void SwNodes::SplitFloatingTableFrame(SwTableNode & rNewTableNode, + ::std::tuple<SwStartNode &, SwFrameFormat &, SwTextNode &> const floatingFrame) +{ + auto const [rFrameStartNode, rFlyFormat, rAnchorNode]{floatingFrame}; + SwEndNode *const pOldFrameEndNode{rFrameStartNode.EndOfSectionNode()->GetEndNode()}; + assert(pOldFrameEndNode); + + // insert new fly nodes between tables + new SwEndNode(rNewTableNode, rFrameStartNode); + SwStartNode *const pNewFrameStartNode{new SwStartNode{rNewTableNode, SwNodeType::Start, SwFlyStartNode}}; + pOldFrameEndNode->m_pStartOfSection = pNewFrameStartNode; + pNewFrameStartNode->m_pEndOfSection = pOldFrameEndNode; + rNewTableNode.m_pStartOfSection = pNewFrameStartNode; + + // relevant part of DocumentLayoutManager::CopyLayoutFormat() + OUString const newName{m_rMyDoc.GetUniqueFrameName()}; + SwFlyFrameFormat *const pNewFlyFormat{m_rMyDoc.MakeFlyFrameFormat(newName, + static_cast<SwFrameFormat *>(rFlyFormat.GetRegisteredIn()))}; + SwXFrame::GetOrCreateSdrObject(*pNewFlyFormat); + pNewFlyFormat->CopyAttrs(rFlyFormat); + pNewFlyFormat->ResetFormatAttr(RES_CHAIN); + + // deleting existing frames for anchor change should not be necessary, and + // crashes because it was already added to mpFlyDestroy by FndBox_::DelFrames() + + // create new anchor node *before* existing one + SwTextNode *const pNewAnchorNode{MakeTextNode(rAnchorNode, + m_rMyDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_TEXT))}; + SwFormatAnchor anchor{rFlyFormat.GetAnchor()}; + SwPosition const pos{*pNewAnchorNode}; + anchor.SetAnchor(&pos); + rFlyFormat.SetFormatAttr(anchor); + pNewFlyFormat->SetFormatAttr(SwFormatContent{pNewFrameStartNode}); + + pNewFlyFormat->MakeFrames(); +} + /** * Splits a Table in the top-level Line which contains the Index. * All succeeding top-level Lines go into a new Table/Node. @@ -3221,7 +3336,9 @@ void SwDoc::SplitTable( const SwPosition& rPos, SplitTable_HeadlineOption eHdlnM aFndBox.SetTableLines( rTable ); aFndBox.DelFrames( rTable ); - SwTableNode* pNew = GetNodes().SplitTable( rPos.GetNode(), false, bCalcNewSize ); + auto const oFloatingFrame{FindFloatingTable(*pTNd)}; + + SwTableNode* pNew = GetNodes().SplitTable(rPos.GetNode(), false, bCalcNewSize); if( pNew ) { @@ -3229,8 +3346,12 @@ void SwDoc::SplitTable( const SwPosition& rPos, SplitTable_HeadlineOption eHdlnM SwUndoSplitTable* pUndo = nullptr; if (GetIDocumentUndoRedo().DoesUndo()) { - pUndo = new SwUndoSplitTable( - *pNew, std::move(pSaveRowSp), eHdlnMode, bCalcNewSize); + pUndo = new SwUndoSplitTable(*pNew, std::move(pSaveRowSp), + eHdlnMode, bCalcNewSize, oFloatingFrame + ? ::std::get<0>(*oFloatingFrame).GetIndex() < ::std::get<2>(*oFloatingFrame).GetIndex() + ? SwUndoSplitTable::FloatingMode::FloatingAnchoredAfter + : SwUndoSplitTable::FloatingMode::FloatingAnchoredBefore + : SwUndoSplitTable::FloatingMode::Not); GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo)); if( aHistory.Count() ) pUndo->SaveFormula( aHistory ); @@ -3290,12 +3411,18 @@ void SwDoc::SplitTable( const SwPosition& rPos, SplitTable_HeadlineOption eHdlnM break; } - // And insert Frames - pNew->MakeOwnFrames(); + if (oFloatingFrame) + { + GetNodes().SplitFloatingTableFrame(*pNew, *oFloatingFrame); + } + else + { + pNew->MakeOwnFrames(); - // Insert a paragraph between the Table - GetNodes().MakeTextNode( *pNew, + // Insert a paragraph between the tables + GetNodes().MakeTextNode( *pNew, getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ) ); + } } // Update Layout diff --git a/sw/source/core/inc/UndoTable.hxx b/sw/source/core/inc/UndoTable.hxx index 40d4d0547b6a..4c85ed215f19 100644 --- a/sw/source/core/inc/UndoTable.hxx +++ b/sw/source/core/inc/UndoTable.hxx @@ -319,7 +319,12 @@ public: class SwUndoSplitTable final : public SwUndo { +public: + enum class FloatingMode { Not, FloatingAnchoredAfter, FloatingAnchoredBefore }; + +private: SwNodeOffset m_nTableNode, m_nOffset; + FloatingMode m_eFloatingMode; std::unique_ptr<SwSaveRowSpan> mpSaveRowSpan; // stores row span values at the splitting row std::unique_ptr<SaveTable> m_pSavedTable; std::unique_ptr<SwHistory> m_pHistory; @@ -329,7 +334,7 @@ class SwUndoSplitTable final : public SwUndo public: SwUndoSplitTable( const SwTableNode& rTableNd, std::unique_ptr<SwSaveRowSpan> pRowSp, - SplitTable_HeadlineOption nMode, bool bCalcNewSize ); + SplitTable_HeadlineOption nMode, bool bCalcNewSize, FloatingMode eMode); virtual ~SwUndoSplitTable() override; diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx index fcaa1b76a4cb..e6ff20d8e956 100644 --- a/sw/source/core/undo/untbl.cxx +++ b/sw/source/core/undo/untbl.cxx @@ -2821,9 +2821,13 @@ void SwUndoCpyTable::RedoImpl(::sw::UndoRedoContext & rContext) } SwUndoSplitTable::SwUndoSplitTable( const SwTableNode& rTableNd, - std::unique_ptr<SwSaveRowSpan> pRowSp, SplitTable_HeadlineOption eMode, bool bNewSize ) - : SwUndo( SwUndoId::SPLIT_TABLE, &rTableNd.GetDoc() ), - m_nTableNode( rTableNd.GetIndex() ), m_nOffset( 0 ), mpSaveRowSpan( std::move(pRowSp) ), + std::unique_ptr<SwSaveRowSpan> pRowSp, SplitTable_HeadlineOption const eMode, + bool const bNewSize, FloatingMode const eFloatingMode) + : SwUndo( SwUndoId::SPLIT_TABLE, &rTableNd.GetDoc() ) + , m_nTableNode( rTableNd.GetIndex() ) + , m_nOffset( 0 ) + , m_eFloatingMode(eFloatingMode) + , mpSaveRowSpan( std::move(pRowSp) ), m_nMode( eMode ), m_nFormulaEnd( 0 ), m_bCalcNewSize( bNewSize ) { switch( m_nMode ) @@ -2852,10 +2856,20 @@ void SwUndoSplitTable::UndoImpl(::sw::UndoRedoContext & rContext) SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); SwPosition& rPtPos = *pPam->GetPoint(); - rPtPos.Assign( m_nTableNode + m_nOffset ); - assert(rPtPos.GetNode().GetContentNode()->Len() == 0); // empty para inserted + if (m_eFloatingMode != FloatingMode::Not) { + // index members are *before* frame-split + auto const nEndOfOldFlyIndex{m_nTableNode + m_nOffset + + (m_eFloatingMode == FloatingMode::FloatingAnchoredBefore ? 1 : 0)}; + pDoc->GetNodes().MergeFloatingTableFrame(nEndOfOldFlyIndex); + } + else + { + rPtPos.Assign(m_nTableNode + m_nOffset); + assert(rPtPos.GetNode().IsTextNode()); // inserted text node + assert(rPtPos.GetNode().GetContentNode()->Len() == 0); // empty para inserted + // avoid asserts from ~SwContentIndexReg SwNodeIndex const idx(pDoc->GetNodes(), m_nTableNode + m_nOffset); { @@ -2870,6 +2884,7 @@ void SwUndoSplitTable::UndoImpl(::sw::UndoRedoContext & rContext) rPtPos.Assign( m_nTableNode + m_nOffset ); SwTableNode* pTableNd = rPtPos.GetNode().GetTableNode(); + assert(pTableNd); SwTable& rTable = pTableNd->GetTable(); rTable.SwitchFormulasToInternalRepresentation(); diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx index 2e3f82bf179f..0e49e2c889ea 100644 --- a/sw/source/uibase/inc/wrtsh.hxx +++ b/sw/source/uibase/inc/wrtsh.hxx @@ -383,7 +383,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)(); enum class FieldDialogPressedButton { NONE, Previous, Next }; - void Do(DoType eDoType, sal_uInt16 nCnt = 1, sal_uInt16 nOffset = 0); + SW_DLLPUBLIC void Do(DoType eDoType, sal_uInt16 nCnt = 1, sal_uInt16 nOffset = 0); OUString GetDoString( DoType eDoType ) const; OUString GetRepeatString() const; void GetDoStrings( DoType eDoType, SfxStringListItem& rStrLstItem ) const;