diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2023-04-21 08:22:21 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2023-04-21 09:02:33 +0200 |
commit | f703ad86984bcc5e2271484cf45d36e1057b21ad (patch) | |
tree | 7a6ad5a5526d69b7b295afbcfdbbcd57d1f747cb | |
parent | 76e80a567fe41f885224d01c7dd22de7ee90606d (diff) |
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 <vmiklos@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | include/svtools/rtfkeywd.hxx | 19 | ||||
-rw-r--r-- | sw/qa/extras/rtfexport/rtfexport3.cxx | 60 | ||||
-rw-r--r-- | sw/source/filter/ww8/rtfattributeoutput.cxx | 129 | ||||
-rw-r--r-- | sw/source/filter/ww8/rtfattributeoutput.hxx | 1 | ||||
-rw-r--r-- | sw/source/filter/ww8/rtfexport.cxx | 4 |
5 files changed, 209 insertions, 4 deletions
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()) { |