summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-02-22 08:11:00 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-02-22 09:36:50 +0000
commite7be3b821cd42fdc9d8e51772b8202030d76497e (patch)
tree8cb11757570c267f431ec79f7ea945d302da526e
parenta60fcb15046a60fa35fc4ea07d1411bf3563fe2e (diff)
sw floatable: teach the DOCX filter about SwFormatFlySplit
- stop creating a grab-bag for floating tables in the DOCX import if split flys are allowed, which gives the exporter an opportunity to actually read the doc model - extract that code that writes a <w:tblpPr> from a ww8::Frame to a new CollectFloatingTableAttributes() - in case a fly frame has a table and the fly has SwFormatFlySplit=true, then call CollectFloatingTableAttributes() even without grab-bags - in the unlikely case that we would have both a split fly and a grab-bag, ignore the grab-bag With this, we get a working DOCX export for multi-page floating tables. The import is still disabled by default. Change-Id: I601833c49f49f94e1ff3cdc994e3027ee0542b94 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147429 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/qa/filter/ww8/ww8.cxx39
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx171
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableHandler.cxx28
3 files changed, 162 insertions, 76 deletions
diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
index 611d63259ae8..8eac94ae36d0 100644
--- a/sw/qa/filter/ww8/ww8.cxx
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -15,6 +15,10 @@
#include <docsh.hxx>
#include <formatcontentcontrol.hxx>
#include <wrtsh.hxx>
+#include <itabenum.hxx>
+#include <frmmgr.hxx>
+#include <frameformats.hxx>
+#include <formatflysplit.hxx>
namespace
{
@@ -189,6 +193,41 @@ CPPUNIT_TEST_FIXTURE(Test, testDocxSymbolFontExport)
assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "font", "Wingdings");
assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "char", "f0e0");
}
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxFloatingTableExport)
+{
+ // Given a document with a floating table:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ // Insert a table:
+ SwInsertTableOptions aTableOptions(SwInsertTableFlags::DefaultBorder, 0);
+ pWrtShell->InsertTable(aTableOptions, 1, 1);
+ pWrtShell->MoveTable(GotoPrevTable, fnTableStart);
+ // Select it:
+ pWrtShell->SelAll();
+ // Wrap in a fly:
+ SwFlyFrameAttrMgr aMgr(true, pWrtShell, Frmmgr_Type::TEXT, nullptr);
+ pWrtShell->StartAllAction();
+ aMgr.InsertFlyFrame(RndStdIds::FLY_AT_PARA, aMgr.GetPos(), aMgr.GetSize());
+ // Mark it as a floating table:
+ SwFrameFormats& rFlys = *pDoc->GetSpzFrameFormats();
+ SwFrameFormat* pFly = rFlys[0];
+ SwAttrSet aSet(pFly->GetAttrSet());
+ aSet.Put(SwFormatFlySplit(true));
+ pDoc->SetAttr(aSet, *pFly);
+ pWrtShell->EndAllAction();
+
+ // When saving to docx:
+ save("Office Open XML Text");
+
+ // Then make sure we write a floating table, not a textframe containing a table:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - XPath '//w:tbl/w:tblPr/w:tblpPr' number of nodes is incorrect
+ // i.e. no floating table was exported.
+ assertXPath(pXmlDoc, "//w:tbl/w:tblPr/w:tblpPr", 1);
+}
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 6d1c94868917..ff69fb0b8e2c 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -136,6 +136,7 @@
#include <txtatr.hxx>
#include <frameformats.hxx>
#include <textcontentcontrol.hxx>
+#include <formatflysplit.hxx>
#include <o3tl/string_view.hxx>
#include <o3tl/unit_conversion.hxx>
@@ -408,7 +409,14 @@ static void checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutpu
std::map<OUString, css::uno::Any> aTableGrabBag = pTableGrabBag->GetGrabBag();
// no grabbag?
if (aTableGrabBag.find("TablePosition") == aTableGrabBag.end())
+ {
+ if (pFrameFormat->GetFlySplit().GetValue())
+ {
+ ww8::Frame aFrame(*pFrameFormat, *rAnchor.GetContentAnchor());
+ rDocxAttributeOutput.WriteFloatingTable(&aFrame);
+ }
continue;
+ }
// write table to docx
ww8::Frame aFrame(*pFrameFormat, *rAnchor.GetContentAnchor());
@@ -4559,6 +4567,84 @@ sal_Int32 lcl_getWordCompatibilityMode(const DocxExport& rDocExport)
return nWordCompatibilityMode;
}
+void CollectFloatingTableAttributes(DocxExport& rExport, const ww8::Frame& rFrame,
+ ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner,
+ rtl::Reference<FastAttributeList>& pAttributes)
+{
+ // we export the values of the surrounding Frame
+ OString sOrientation;
+ sal_Int32 nValue;
+
+ // If tblpXSpec or tblpYSpec are present, we do not write tblpX or tblpY!
+ OString sTblpXSpec
+ = convertToOOXMLHoriOrient(rFrame.GetFrameFormat().GetHoriOrient().GetHoriOrient(),
+ rFrame.GetFrameFormat().GetHoriOrient().IsPosToggle());
+ OString sTblpYSpec
+ = convertToOOXMLVertOrient(rFrame.GetFrameFormat().GetVertOrient().GetVertOrient());
+
+ sOrientation
+ = convertToOOXMLVertOrientRel(rFrame.GetFrameFormat().GetVertOrient().GetRelationOrient());
+ pAttributes->add(FSNS(XML_w, XML_vertAnchor), sOrientation);
+
+ if (!sTblpYSpec.isEmpty())
+ pAttributes->add(FSNS(XML_w, XML_tblpYSpec), sTblpYSpec);
+
+ sOrientation
+ = convertToOOXMLHoriOrientRel(rFrame.GetFrameFormat().GetHoriOrient().GetRelationOrient());
+ pAttributes->add(FSNS(XML_w, XML_horzAnchor), sOrientation);
+
+ if (!sTblpXSpec.isEmpty())
+ pAttributes->add(FSNS(XML_w, XML_tblpXSpec), sTblpXSpec);
+
+ nValue = rFrame.GetFrameFormat().GetULSpace().GetLower();
+ if (nValue != 0)
+ pAttributes->add(FSNS(XML_w, XML_bottomFromText), OString::number(nValue));
+
+ nValue = rFrame.GetFrameFormat().GetLRSpace().GetLeft();
+ if (nValue != 0)
+ pAttributes->add(FSNS(XML_w, XML_leftFromText), OString::number(nValue));
+
+ nValue = rFrame.GetFrameFormat().GetLRSpace().GetRight();
+ if (nValue != 0)
+ pAttributes->add(FSNS(XML_w, XML_rightFromText), OString::number(nValue));
+
+ nValue = rFrame.GetFrameFormat().GetULSpace().GetUpper();
+ if (nValue != 0)
+ pAttributes->add(FSNS(XML_w, XML_topFromText), OString::number(nValue));
+
+ if (sTblpXSpec.isEmpty()) // do not write tblpX if tblpXSpec is present
+ {
+ nValue = rFrame.GetFrameFormat().GetHoriOrient().GetPos();
+ // we need to revert the additional shift introduced by
+ // lcl_DecrementHoriOrientPosition() in writerfilter
+ // 1st: left distance of the table
+ const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
+ const SwFrameFormat* pFrameFormat = pTabBox->GetFrameFormat();
+ const SvxBoxItem& rBox = pFrameFormat->GetBox();
+ sal_Int32 nMode = lcl_getWordCompatibilityMode(rExport);
+ if (nMode < 15)
+ {
+ sal_uInt16 nLeftDistance = rBox.GetDistance(SvxBoxItemLine::LEFT);
+ nValue += nLeftDistance;
+ }
+
+ // 2nd: if a left border is given, revert the shift by half the width
+ // from lcl_DecrementHoriOrientPosition() in writerfilter
+ if (const editeng::SvxBorderLine* pLeftBorder = rBox.GetLeft())
+ {
+ tools::Long nWidth = pLeftBorder->GetWidth();
+ nValue += (nWidth / 2);
+ }
+
+ pAttributes->add(FSNS(XML_w, XML_tblpX), OString::number(nValue));
+ }
+
+ if (sTblpYSpec.isEmpty()) // do not write tblpY if tblpYSpec is present
+ {
+ nValue = rFrame.GetFrameFormat().GetVertOrient().GetPos();
+ pAttributes->add(FSNS(XML_w, XML_tblpY), OString::number(nValue));
+ }
+}
}
void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
@@ -4665,6 +4751,16 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t
std::map<SvxBoxItemLine, css::table::BorderLine2>& rTableStyleConf = m_aTableStyleConfs.back();
rTableStyleConf.clear();
+ bool bFloatingTableWritten = false;
+ if (pFloatingTableFrame && pFloatingTableFrame->GetFrameFormat().GetFlySplit().GetValue())
+ {
+ rtl::Reference<FastAttributeList> pAttributes = FastSerializerHelper::createAttrList();
+ CollectFloatingTableAttributes(m_rExport, *pFloatingTableFrame, pTableTextNodeInfoInner,
+ pAttributes);
+ m_pSerializer->singleElementNS(XML_w, XML_tblpPr, pAttributes);
+ bFloatingTableWritten = true;
+ }
+
// Extract properties from grab bag
for( const auto & rGrabBagElement : aGrabBag )
{
@@ -4724,74 +4820,8 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t
const ww8::Frame* pFrame = m_rExport.GetFloatingTableFrame();
if( pFrame )
{
- // we export the values of the surrounding Frame
- OString sOrientation;
- sal_Int32 nValue;
-
- // If tblpXSpec or tblpYSpec are present, we do not write tblpX or tblpY!
- OString sTblpXSpec = convertToOOXMLHoriOrient( pFrame->GetFrameFormat().GetHoriOrient().GetHoriOrient(), pFrame->GetFrameFormat().GetHoriOrient().IsPosToggle() );
- OString sTblpYSpec = convertToOOXMLVertOrient( pFrame->GetFrameFormat().GetVertOrient().GetVertOrient() );
-
- sOrientation = convertToOOXMLVertOrientRel( pFrame->GetFrameFormat().GetVertOrient().GetRelationOrient() );
- attrListTablePos->add(FSNS(XML_w, XML_vertAnchor), sOrientation);
-
- if( !sTblpYSpec.isEmpty() )
- attrListTablePos->add(FSNS(XML_w, XML_tblpYSpec), sTblpYSpec);
-
- sOrientation = convertToOOXMLHoriOrientRel( pFrame->GetFrameFormat().GetHoriOrient().GetRelationOrient() );
- attrListTablePos->add(FSNS(XML_w, XML_horzAnchor), sOrientation);
-
- if( !sTblpXSpec.isEmpty() )
- attrListTablePos->add(FSNS(XML_w, XML_tblpXSpec), sTblpXSpec);
-
- nValue = pFrame->GetFrameFormat().GetULSpace().GetLower();
- if( nValue != 0 )
- attrListTablePos->add( FSNS( XML_w, XML_bottomFromText ), OString::number( nValue ) );
-
- nValue = pFrame->GetFrameFormat().GetLRSpace().GetLeft();
- if( nValue != 0 )
- attrListTablePos->add( FSNS( XML_w, XML_leftFromText ), OString::number( nValue ) );
-
- nValue = pFrame->GetFrameFormat().GetLRSpace().GetRight();
- if( nValue != 0 )
- attrListTablePos->add( FSNS( XML_w, XML_rightFromText ), OString::number( nValue ) );
-
- nValue = pFrame->GetFrameFormat().GetULSpace().GetUpper();
- if( nValue != 0 )
- attrListTablePos->add( FSNS( XML_w, XML_topFromText ), OString::number( nValue ) );
-
- if( sTblpXSpec.isEmpty() ) // do not write tblpX if tblpXSpec is present
- {
- nValue = pFrame->GetFrameFormat().GetHoriOrient().GetPos();
- // we need to revert the additional shift introduced by
- // lcl_DecrementHoriOrientPosition() in writerfilter
- // 1st: left distance of the table
- const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
- const SwFrameFormat * pFrameFormat = pTabBox->GetFrameFormat();
- const SvxBoxItem& rBox = pFrameFormat->GetBox( );
- sal_Int32 nMode = lcl_getWordCompatibilityMode(m_rExport);
- if (nMode < 15)
- {
- sal_uInt16 nLeftDistance = rBox.GetDistance(SvxBoxItemLine::LEFT);
- nValue += nLeftDistance;
- }
-
- // 2nd: if a left border is given, revert the shift by half the width
- // from lcl_DecrementHoriOrientPosition() in writerfilter
- if (const editeng::SvxBorderLine* pLeftBorder = rBox.GetLeft())
- {
- tools::Long nWidth = pLeftBorder->GetWidth();
- nValue += (nWidth / 2);
- }
-
- attrListTablePos->add( FSNS( XML_w, XML_tblpX ), OString::number( nValue ) );
- }
-
- if( sTblpYSpec.isEmpty() ) // do not write tblpY if tblpYSpec is present
- {
- nValue = pFrame->GetFrameFormat().GetVertOrient().GetPos();
- attrListTablePos->add( FSNS( XML_w, XML_tblpY ), OString::number( nValue ) );
- }
+ CollectFloatingTableAttributes(m_rExport, *pFrame, pTableTextNodeInfoInner,
+ attrListTablePos);
}
else // ( pFrame = 0 )
{
@@ -4851,7 +4881,10 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t
}
}
- m_pSerializer->singleElementNS( XML_w, XML_tblpPr, attrListTablePos);
+ if (!bFloatingTableWritten)
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_tblpPr, attrListTablePos);
+ }
attrListTablePos = nullptr;
}
else
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
index 9ecf646af705..fc19793991f8 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -59,6 +59,22 @@
#include <utility>
#endif
+namespace
+{
+bool IsFlySplitAllowed()
+{
+ bool bRet
+ = officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::get();
+
+ if (!bRet)
+ {
+ bRet = getenv("SW_FORCE_FLY_SPLIT") != nullptr;
+ }
+
+ return bRet;
+}
+}
+
namespace writerfilter::dmapper {
using namespace ::com::sun::star;
@@ -375,7 +391,10 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo
comphelper::makePropertyValue("vertAnchor", pTablePositions->getVertAnchor())
};
- aGrabBag["TablePosition"] <<= aGrabBagTS;
+ if (!IsFlySplitAllowed())
+ {
+ aGrabBag["TablePosition"] <<= aGrabBagTS;
+ }
}
else if (bConvertToFloatingInFootnote)
{
@@ -1565,12 +1584,7 @@ void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTab
comphelper::makePropertyValue("IsFollowingTextFlow", true));
}
- bool bSplitAllowed = officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::get();
- if (!bSplitAllowed)
- {
- bSplitAllowed = getenv("SW_FORCE_FLY_SPLIT") != nullptr;
- }
- if (bSplitAllowed)
+ if (IsFlySplitAllowed())
{
aFrameProperties.push_back(comphelper::makePropertyValue("IsSplitAllowed", true));
}