sw/qa/core/layout/flycnt.cxx     |   45 +++++++++++++++++++++++++++++++++++++--
 sw/source/core/layout/fly.cxx    |    9 +++++++
 sw/source/core/layout/flycnt.cxx |    5 ++--
 sw/source/core/layout/tabfrm.cxx |   18 +++++++++++++--
 4 files changed, 71 insertions(+), 6 deletions(-)

New commits:
commit 9dda7a9e6551c204e8e709a0873d2b1865de3bf6
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri May 5 08:09:35 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon May 15 10:11:33 2023 +0200

    sw floattable: fix UI for turning fly split off
    
    Given a multi-page floating table of 2 pages, turning the "allow frame
    to split across pages" checkbox off in the frame properties dialog
    resulted in a 1 page document, but with 2 fly frames instead of just 1.
    
    There were 3 problems here:
    
    1) SwTabFrame::MakeAll() should join the follow table frames, similar to
    what happens then the split bit on the table itself is turned off.  Note
    that this is only safe if the frame is not chained, either.
    
    2) SwTabFrame::Cut() should mark the follow fly for deletion. The check
    here was broken, since we didn't do anything in case the split bit is
    off for the fly frame. This looks OK, but we still need to handle the
    case when it was on, but it's now off.
    
    3) Finally SwFlyFrame::Format() always increases the height of flys to
    at least MINFLY, so drop the HasArea() condition that prevented
    deletion. Checking if the fly has content is probably enough.
    
    With this, disabling the "split" checkbox on the frame dialog results in
    a single fly frame, as expected.
    
    For the testcase, improve Create1x2SplitFly() a bit, so it's closer to
    what floattable.docx import would create (to help debugging) and also
    improve SwFlyFrame::UpdateAttr_(), because previously that only worked
    by accident, due to some rounding error on the UI. (So the fly size
    changed even when that was not the intent.)
    
    Change-Id: I7b33e6557282032c5d8ed2c3aea21b78a33bd6d3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151408
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit f7e1cdf951f7f9cbb5822c49b86ba8a77a2fa878)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151758
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index bf1068635a72..5f042b1958e6 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -52,9 +52,9 @@ void Test::Create1x2SplitFly()
     SwDoc* pDoc = getSwDoc();
     SwPageDesc aStandard(pDoc->GetPageDesc(0));
     SwFormatFrameSize aPageSize(aStandard.GetMaster().GetFrameSize());
-    // 5cm for the page height, 2cm are the top and bottom margins, so 1cm 
remains for the body
+    // 10 cm for the page height, 2cm are the top and bottom margins, so 6cm 
remains for the body
     // frame:
-    aPageSize.SetHeight(2834);
+    aPageSize.SetHeight(5669);
     aStandard.GetMaster().SetFormatAttr(aPageSize);
     pDoc->ChgPageDesc(0, aStandard);
     // Insert a table:
@@ -64,8 +64,13 @@ void Test::Create1x2SplitFly()
     pWrtShell->MoveTable(GotoPrevTable, fnTableStart);
     pWrtShell->GoPrevCell();
     pWrtShell->Insert("A1");
+    SwFormatFrameSize aRowSize(SwFrameSize::Minimum);
+    // 4 cm, so 2 rows don't fit 1 page.
+    aRowSize.SetHeight(2267);
+    pWrtShell->SetRowHeight(aRowSize);
     pWrtShell->GoNextCell();
     pWrtShell->Insert("A2");
+    pWrtShell->SetRowHeight(aRowSize);
     // Select cell:
     pWrtShell->SelAll();
     // Select table:
@@ -294,6 +299,42 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyEnable)
     CPPUNIT_ASSERT(pPage2);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyDisable)
+{
+    // Given a document with a floating talbe, table split on 2 pages:
+    Create1x2SplitFly();
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
+    CPPUNIT_ASSERT(pPage1);
+    CPPUNIT_ASSERT(pPage1->GetNext());
+    const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs.size());
+    auto pPage1Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage1Objs[0]);
+    CPPUNIT_ASSERT(pPage1Fly);
+    CPPUNIT_ASSERT(pPage1Fly->GetFollow());
+
+    // When turning the "split fly" checkbox off:
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    pWrtShell->StartAllAction();
+    auto& rFlys = *pDoc->GetSpzFrameFormats();
+    auto pFly = rFlys[0];
+    SwAttrSet aSet(pFly->GetAttrSet());
+    // Note how the UI puts a SwFormatFrameSize into this item set with a 
slightly different size
+    // (e.g. 3823 twips width -> 3821). This means that by accident the UI 
works even without the
+    // explicit RES_FLY_SPLIT handling in SwFlyFrame::UpdateAttr_(), but this 
test will fail when
+    // that is missing.
+    aSet.Put(SwFormatFlySplit(false));
+    pDoc->SetAttr(aSet, *pFly);
+    pWrtShell->EndAllAction();
+
+    // Then make sure the extra page and follow fly frame is joined:
+    CPPUNIT_ASSERT(!pPage1->GetNext());
+    // Without the accompanying fix in place, this test would have failed, the 
follow fly frame was
+    // moved to page 1, but it wasn't deleted.
+    CPPUNIT_ASSERT(!pPage1Fly->GetFollow());
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testSplitFlyFooter)
 {
     // Given a document with a floattable, table split on 2 pages with 
headers/footers:
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 5de34f544894..c5ee8815a71b 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -954,6 +954,15 @@ void SwFlyFrame::UpdateAttr_( const SfxPoolItem *pOld, 
const SfxPoolItem *pNew,
                 pNewFormatFrameSize = 
const_cast<SwFormatFrameSize*>(static_cast<const SwFormatFrameSize*>(pNew));
             else if (nWhich == RES_FMT_CHG)
                 pOldFormatChg = const_cast<SwFormatChg*>(static_cast<const 
SwFormatChg*>(pOld));
+            else if (nWhich == RES_FLY_SPLIT)
+            {
+                // If the fly frame has a table lower, invalidate that, so it 
joins its follow tab
+                // frames and re-splits according to the new fly split rule.
+                if (Lower() && Lower()->IsTabFrame())
+                {
+                    Lower()->InvalidateAll_();
+                }
+            }
 
             if (aURL.GetMap() && (pNewFormatFrameSize || pOldFormatChg))
             {
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 3821ac66b1df..de26ee63a18a 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -1651,8 +1651,9 @@ void SwRootFrame::DeleteEmptyFlys_()
     {
         SwFlyFrame* pFly = *mpFlyDestroy->begin();
         mpFlyDestroy->erase( mpFlyDestroy->begin() );
-        if (!pFly->getFrameArea().HasArea() && !pFly->ContainsContent()
-            && !pFly->IsDeleteForbidden())
+        // Allow deletion of non-empty flys: a fly with no content is still 
formatted to have a
+        // height of MINLAY.
+        if (!pFly->ContainsContent() && !pFly->IsDeleteForbidden())
         {
             SwFrame::DestroyFrame(pFly);
         }
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 50e02cec3a7a..647bee556368 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -1971,7 +1971,7 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
     const SwBorderAttrs *pAttrs = oAccess->Get();
 
     // All rows should keep together
-    const bool bDontSplit = !IsFollow() &&
+    bool bDontSplit = !IsFollow() &&
                             ( !GetFormat()->GetLayoutSplit().GetValue() );
 
     // The number of repeated headlines
@@ -1991,6 +1991,12 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
             // Ignore the above text node -> row inheritance for floating 
tables.
             bTableRowKeep = false;
         }
+        else if (!pFly->GetNextLink())
+        {
+            // If the fly is not allowed to split and is not chained, then it 
makes no sense to
+            // split the table.
+            bDontSplit = true;
+        }
     }
 
     // The Magic Move: Used for the table row keep feature.
@@ -3848,7 +3854,15 @@ void SwTabFrame::Cut()
                 !(pFly = pUp->FindFlyFrame())->ContainsContent() &&
                 !pFly->ContainsAny())
         {
-            if (pUp == pFly && pFly->IsFlySplitAllowed())
+            bool bSplitFly = pFly->IsFlySplitAllowed();
+            if (!bSplitFly && pFly->IsFlyAtContentFrame())
+            {
+                // If the fly is not allowed to split, it's still possible 
that it was allowed to
+                // split. That is definitely the case when the fly is a follow.
+                auto pFlyAtContent = static_cast<SwFlyAtContentFrame*>(pFly);
+                bSplitFly = pFlyAtContent->IsFollow();
+            }
+            if (pUp == pFly && bSplitFly)
             {
                 auto pFlyAtContent = static_cast<SwFlyAtContentFrame*>(pFly);
                 pFlyAtContent->DelEmpty();

Reply via email to