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;

Reply via email to