include/svtools/rtfkeywd.hxx                |   19 ++++
 sw/qa/extras/rtfexport/rtfexport3.cxx       |   60 +++++++++++++
 sw/source/filter/ww8/rtfattributeoutput.cxx |  129 +++++++++++++++++++++++++++-
 sw/source/filter/ww8/rtfattributeoutput.hxx |    1 
 sw/source/filter/ww8/rtfexport.cxx          |    4 
 5 files changed, 209 insertions(+), 4 deletions(-)

New commits:
commit f703ad86984bcc5e2271484cf45d36e1057b21ad
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Apr 21 08:22:21 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Apr 21 09:02:33 2023 +0200

    sw floatable: teach the RTF export about SwFormatFlySplit
    
    Write \nobrkwrptbl unconditionally till we have a layout mode where
    floating/wrapped tables don't split/break.
    
    Change-Id: I0a19d034651a276dde8df391a5f1ca8ae39ddfed
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150739
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/include/svtools/rtfkeywd.hxx b/include/svtools/rtfkeywd.hxx
index d1a4a59073b2..b4bac2af34cf 100644
--- a/include/svtools/rtfkeywd.hxx
+++ b/include/svtools/rtfkeywd.hxx
@@ -1221,5 +1221,24 @@
 #define LO_STRING_SVTOOLS_RTF_GUTTERPRL "\\gutterprl"
 #define LO_STRING_SVTOOLS_RTF_RTLGUTTER "\\rtlgutter"
 #define LO_STRING_SVTOOLS_RTF_LBR "\\lbr"
+#define LO_STRING_SVTOOLS_RTF_TPVMRG "\\tpvmrg"
+#define LO_STRING_SVTOOLS_RTF_TPVPG "\\tpvpg"
+#define LO_STRING_SVTOOLS_RTF_TPVPARA "\\tpvpara"
+#define LO_STRING_SVTOOLS_RTF_NOBRKWRPTBL "\\nobrkwrptbl"
+#define LO_STRING_SVTOOLS_RTF_TPHCOL "\\tphcol"
+#define LO_STRING_SVTOOLS_RTF_TPHMRG "\\tphmrg"
+#define LO_STRING_SVTOOLS_RTF_TPHPG "\\tphpg"
+#define LO_STRING_SVTOOLS_RTF_TPOSXL "\\tposxl"
+#define LO_STRING_SVTOOLS_RTF_TPOSXC "\\tposxc"
+#define LO_STRING_SVTOOLS_RTF_TPOSXR "\\tposxr"
+#define LO_STRING_SVTOOLS_RTF_TPOSX "\\tposx"
+#define LO_STRING_SVTOOLS_RTF_TPOSYT "\\tposyt"
+#define LO_STRING_SVTOOLS_RTF_TPOSYC "\\tposyc"
+#define LO_STRING_SVTOOLS_RTF_TPOSYB "\\tposyb"
+#define LO_STRING_SVTOOLS_RTF_TPOSY "\\tposy"
+#define LO_STRING_SVTOOLS_RTF_TDFRMTXTLEFT "\\tdfrmtxtLeft"
+#define LO_STRING_SVTOOLS_RTF_TDFRMTXTRIGHT "\\tdfrmtxtRight"
+#define LO_STRING_SVTOOLS_RTF_TDFRMTXTTOP "\\tdfrmtxtTop"
+#define LO_STRING_SVTOOLS_RTF_TDFRMTXTBOTTOM "\\tdfrmtxtBottom"
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/rtfexport/rtfexport3.cxx 
b/sw/qa/extras/rtfexport/rtfexport3.cxx
index 83d1743e05d2..2b45ca61f33e 100644
--- a/sw/qa/extras/rtfexport/rtfexport3.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport3.cxx
@@ -21,6 +21,7 @@
 
 #include <comphelper/sequenceashashmap.hxx>
 #include <tools/UnitConversion.hxx>
+#include <comphelper/propertyvalue.hxx>
 
 #include <unotxdoc.hxx>
 #include <docsh.hxx>
@@ -559,6 +560,65 @@ DECLARE_RTFEXPORT_TEST(testTdf152784_1, "tdf152784_1.rtf")
     CPPUNIT_ASSERT(getProperty<OUString>(xPara, 
"NumberingStyleName").isEmpty());
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testFloatingTableExport)
+{
+    // Given a document with a floating table:
+    mxComponent = loadFromDesktop("private:factory/swriter");
+    // Insert a table:
+    uno::Sequence<beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("Rows", static_cast<sal_Int32>(1)),
+        comphelper::makePropertyValue("Columns", static_cast<sal_Int32>(1)),
+    };
+    dispatchCommand(mxComponent, ".uno:InsertTable", aArgs);
+    // Select it:
+    dispatchCommand(mxComponent, ".uno:SelectAll", {});
+    // Wrap in a fly:
+    aArgs = {
+        comphelper::makePropertyValue("AnchorType", 
static_cast<sal_uInt16>(0)),
+    };
+    dispatchCommand(mxComponent, ".uno:InsertFrame", aArgs);
+    // Mark it as a floating table:
+    uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xFrame(
+        xTextFramesSupplier->getTextFrames()->getByName("Frame1"), 
uno::UNO_QUERY);
+    xFrame->setPropertyValue("IsSplitAllowed", uno::Any(true));
+    // Originally 10, 30 & 40 twips.
+    xFrame->setPropertyValue("VertOrientPosition", 
uno::Any(static_cast<sal_Int32>(18)));
+    xFrame->setPropertyValue("LeftMargin", 
uno::Any(static_cast<sal_Int32>(53)));
+    xFrame->setPropertyValue("RightMargin", 
uno::Any(static_cast<sal_Int32>(71)));
+
+    // When saving to RTF:
+    reload(mpFilter, "floating-table.rtf");
+
+    // Then make sure the floating table is there & has the expected 
properties:
+    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<drawing::XDrawPage> xDrawPage = 
xDrawPageSupplier->getDrawPage();
+    xFrame.set(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+    bool bIsSplitAllowed{};
+    xFrame->getPropertyValue("IsSplitAllowed") >>= bIsSplitAllowed;
+    // Without the accompanying fix in place, this test would have failed, the 
table was not
+    // multi-page.
+    CPPUNIT_ASSERT(bIsSplitAllowed);
+    sal_Int16 nVertOrientRelation{};
+    xFrame->getPropertyValue("VertOrientRelation") >>= nVertOrientRelation;
+    CPPUNIT_ASSERT_EQUAL(text::RelOrientation::FRAME, nVertOrientRelation);
+    sal_Int16 nHoriOrientRelation{};
+    xFrame->getPropertyValue("HoriOrientRelation") >>= nHoriOrientRelation;
+    CPPUNIT_ASSERT_EQUAL(text::RelOrientation::FRAME, nHoriOrientRelation);
+    sal_Int32 nVertOrientPosition{};
+    xFrame->getPropertyValue("VertOrientPosition") >>= nVertOrientPosition;
+    sal_Int32 nExpected = 18;
+    CPPUNIT_ASSERT_EQUAL(nExpected, nVertOrientPosition);
+    sal_Int32 nLeftMargin{};
+    xFrame->getPropertyValue("LeftMargin") >>= nLeftMargin;
+    nExpected = 53;
+    CPPUNIT_ASSERT_EQUAL(nExpected, nLeftMargin);
+    sal_Int32 nRightMargin{};
+    xFrame->getPropertyValue("RightMargin") >>= nRightMargin;
+    nExpected = 71;
+    CPPUNIT_ASSERT_EQUAL(nExpected, nRightMargin);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 4e5a583264dd..0d59c8dfae4e 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -91,6 +91,7 @@
 #include <svl/grabbagitem.hxx>
 #include <frmatr.hxx>
 #include <swtable.hxx>
+#include <formatflysplit.hxx>
 #include "rtfexport.hxx"
 
 using namespace ::com::sun::star;
@@ -676,6 +677,108 @@ void 
RtfAttributeOutput::TableInfoRow(ww8::WW8TableNodeInfoInner::Pointer_t /*pT
     /* noop */
 }
 
+void RtfAttributeOutput::TablePositioning(SwFrameFormat* pFlyFormat)
+{
+    if (!pFlyFormat || !pFlyFormat->GetFlySplit().GetValue())
+    {
+        return;
+    }
+
+    switch (pFlyFormat->GetVertOrient().GetRelationOrient())
+    {
+        case text::RelOrientation::PAGE_PRINT_AREA:
+            // relative to margin
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPVMRG);
+            break;
+        case text::RelOrientation::PAGE_FRAME:
+            // relative to page
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPVPG);
+            break;
+        default:
+            // text::RelOrientation::FRAME
+            // relative to text
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPVPARA);
+            break;
+    }
+
+    switch (pFlyFormat->GetHoriOrient().GetRelationOrient())
+    {
+        case text::RelOrientation::FRAME:
+            // relative to column
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPHCOL);
+            break;
+        case text::RelOrientation::PAGE_PRINT_AREA:
+            // relative to margin
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPHMRG);
+            break;
+        default:
+            // text::RelOrientation::PAGE_FRAME
+            // relative to page
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPHPG);
+            break;
+    }
+
+    // Similar to RtfAttributeOutput::FormatHorizOrientation(), but for tables.
+    switch (pFlyFormat->GetHoriOrient().GetHoriOrient())
+    {
+        case text::HoriOrientation::LEFT:
+            // left
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSXL);
+            break;
+        case text::HoriOrientation::CENTER:
+            // centered
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSXC);
+            break;
+        case text::HoriOrientation::RIGHT:
+            // right
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSXR);
+            break;
+        default:
+            SwTwips nTPosX = pFlyFormat->GetHoriOrient().GetPos();
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSX);
+            m_aRowDefs.append(static_cast<sal_Int32>(nTPosX));
+            break;
+    }
+
+    // Similar to RtfAttributeOutput::FormatVertOrientation(), but for tables.
+    switch (pFlyFormat->GetVertOrient().GetVertOrient())
+    {
+        case text::VertOrientation::TOP:
+            // up
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSYT);
+            break;
+        case text::VertOrientation::CENTER:
+            // centered
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSYC);
+            break;
+        case text::VertOrientation::BOTTOM:
+            // down
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSYB);
+            break;
+        default:
+            SwTwips nTPosY = pFlyFormat->GetVertOrient().GetPos();
+            m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSY);
+            m_aRowDefs.append(static_cast<sal_Int32>(nTPosY));
+            break;
+    }
+
+    // Similar to RtfAttributeOutput::FormatULSpace(), but for tables.
+    sal_uInt16 nTdfrmtxtTop = pFlyFormat->GetULSpace().GetUpper();
+    m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTTOP);
+    m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtTop));
+    sal_uInt16 nTdfrmtxtBottom = pFlyFormat->GetULSpace().GetLower();
+    m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTBOTTOM);
+    m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtBottom));
+
+    // Similar to RtfAttributeOutput::FormatLRSpace(), but for tables.
+    sal_uInt16 nTdfrmtxtLeft = pFlyFormat->GetLRSpace().GetLeft();
+    m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTLEFT);
+    m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtLeft));
+    sal_uInt16 nTdfrmtxtRight = pFlyFormat->GetLRSpace().GetRight();
+    m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTRIGHT);
+    m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtRight));
+}
+
 void RtfAttributeOutput::TableDefinition(
     ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
 {
@@ -690,6 +793,9 @@ void RtfAttributeOutput::TableDefinition(
     TableHeight(pTableTextNodeInfoInner);
     TableCanSplit(pTableTextNodeInfoInner);
 
+    // Write table positioning properties in case this is a floating table.
+    TablePositioning(pTable->GetTableNode()->GetFlyFormat());
+
     // Cell margins
     const SvxBoxItem& rBox = pFormat->GetBox();
     static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, 
SvxBoxItemLine::LEFT,
@@ -1095,7 +1201,9 @@ void RtfAttributeOutput::EndTableRow()
             m_aAfterRuns.append(m_aTables.back());
             m_aTables.pop_back();
         }
-        m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ROW 
OOO_STRING_SVTOOLS_RTF_PARD);
+        // Make sure that the first word of the next paragraph is not merged 
with the last control
+        // word of this table row, happens with floating tables.
+        m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ROW 
OOO_STRING_SVTOOLS_RTF_PARD " ");
     }
     m_bTableRowEnded = true;
 }
@@ -2037,6 +2145,22 @@ public:
 
 void RtfAttributeOutput::OutputFlyFrame_Impl(const ww8::Frame& rFrame, const 
Point& /*rNdTopLeft*/)
 {
+    const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
+    if (rFrameFormat.GetFlySplit().GetValue())
+    {
+        // The frame can split: this was originally from a floating table, 
write it back as
+        // such.
+        SaveRunState aState(*this);
+        const SwNodeIndex* pNodeIndex = 
rFrameFormat.GetContent().GetContentIdx();
+        SwNodeOffset nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 
SwNodeOffset(0);
+        SwNodeOffset nEnd
+            = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 
SwNodeOffset(0);
+        m_rExport.SaveData(nStt, nEnd);
+        GetExport().WriteText();
+        m_rExport.RestoreData();
+        return;
+    }
+
     const SwNode* pNode = rFrame.GetContent();
     const SwGrfNode* pGrfNode = pNode ? pNode->GetGrfNode() : nullptr;
 
@@ -2083,7 +2207,6 @@ void RtfAttributeOutput::OutputFlyFrame_Impl(const 
ww8::Frame& rFrame, const Poi
             m_rExport.SetRTFFlySyntax(false);
             m_pFlyFrameSize = nullptr;
 
-            const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
             lcl_TextFrameShadow(m_aFlyProperties, rFrameFormat);
             lcl_TextFrameRelativeSize(m_aFlyProperties, rFrameFormat);
 
@@ -2145,7 +2268,6 @@ void RtfAttributeOutput::OutputFlyFrame_Impl(const 
ww8::Frame& rFrame, const Poi
         break;
         case ww8::Frame::eFormControl:
         {
-            const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
             const SdrObject* pObject = rFrameFormat.FindRealSdrObject();
 
             m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
@@ -2377,7 +2499,6 @@ void RtfAttributeOutput::OutputFlyFrame_Impl(const 
ww8::Frame& rFrame, const Poi
         break;
         case ww8::Frame::eOle:
         {
-            const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
             const SdrObject* pSdrObj = rFrameFormat.FindRealSdrObject();
             if (pSdrObj)
             {
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx 
b/sw/source/filter/ww8/rtfattributeoutput.hxx
index fdd5ed09d3bc..6e5a3c77cd2c 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -125,6 +125,7 @@ public:
     void TableInfoCell(ww8::WW8TableNodeInfoInner::Pointer_t 
pTableTextNodeInfoInner) override;
     void TableInfoRow(ww8::WW8TableNodeInfoInner::Pointer_t 
pTableTextNodeInfoInner) override;
     void TableDefinition(ww8::WW8TableNodeInfoInner::Pointer_t 
pTableTextNodeInfoInner) override;
+    void TablePositioning(SwFrameFormat* pFlyFormat);
     void
     TableDefaultBorders(ww8::WW8TableNodeInfoInner::Pointer_t 
pTableTextNodeInfoInner) override;
     void TableBackgrounds(ww8::WW8TableNodeInfoInner::Pointer_t 
pTableTextNodeInfoInner) override;
diff --git a/sw/source/filter/ww8/rtfexport.cxx 
b/sw/source/filter/ww8/rtfexport.cxx
index ccde1138c76c..4b78a464c7c5 100644
--- a/sw/source/filter/ww8/rtfexport.cxx
+++ b/sw/source/filter/ww8/rtfexport.cxx
@@ -856,6 +856,10 @@ ErrCode RtfExport::ExportDocument_Impl()
     // enable form field shading
     Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_FORMSHADE);
 
+    // Enable breaking wrapped tables across pages: the "no" in the control 
word's name is
+    // confusing.
+    Strm().WriteOString(LO_STRING_SVTOOLS_RTF_NOBRKWRPTBL);
+
     // size and empty margins of the page
     if (m_rDoc.GetPageDescCnt())
     {

Reply via email to