tdf#81100 docx export: write tblHeader=false for first row
A whether a table repeats a header row is often defined by a firstRow table style. If our table was (grabbagged) as using that firstRow style, but has been explicitly been set to override that and not repeat the first row, then that needs to be explicitly written out to avoid inheriting the style's setting on the round-trip. make CppunitTest_sw_ooxmlexport26 CPPUNIT_TEST_NAME=testTdf81100 Change-Id: Id581fb316ef9aa88cb53e87c50eb40fc0a3ecbc0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202254 Tested-by: Jenkins Reviewed-by: Justin Luth <jluth@mail.com>
This commit is contained in:
@@ -382,23 +382,22 @@ DECLARE_OOXMLEXPORT_TEST(testTdf58944RepeatingTableHeader, "tdf58944-repeating-t
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testTdf81100)
|
||||
{
|
||||
auto verify = [this](bool bIsExport = false) {
|
||||
auto verify = [this]() {
|
||||
xmlDocUniquePtr pDump = parseLayoutDump();
|
||||
CPPUNIT_ASSERT_EQUAL(3, getPages());
|
||||
|
||||
// table starts on page 1 and finished on page 2
|
||||
// and it has got only a single repeating header line
|
||||
// with no repeating header line (explicit tblHeader="0")
|
||||
assertXPath(pDump, "/root/page[2]/body/tab[1]", 1);
|
||||
assertXPath(pDump, "/root/page[2]/body/tab[1]/row", 2);
|
||||
assertXPath(pDump, "/root/page[3]/body/tab", 1);
|
||||
if (!bIsExport) // TODO export tblHeader=false
|
||||
assertXPath(pDump, "/root/page[3]/body/tab/row", 1);
|
||||
assertXPath(pDump, "/root/page[3]/body/tab/row", 1);
|
||||
};
|
||||
createSwDoc("tdf81100.docx");
|
||||
verify();
|
||||
|
||||
saveAndReload(TestFilter::DOCX);
|
||||
verify(/*bIsExport*/ true);
|
||||
verify();
|
||||
|
||||
xmlDocUniquePtr pXmlDoc = parseExport(u"word/styles.xml"_ustr);
|
||||
CPPUNIT_ASSERT(pXmlDoc);
|
||||
|
||||
@@ -457,6 +457,36 @@ bool lcl_hasParaSdtEndBefore(const SwNode& rNode)
|
||||
return rMap.contains(u"ParaSdtEndBefore"_ustr);
|
||||
}
|
||||
|
||||
bool lcl_HasTblHeaderFromStyle(const SwFrameFormat* pTableFormat,
|
||||
const DocxTableStyleExport& rTableStyleExport)
|
||||
{
|
||||
// does the table actually apply a table style, and does it use the firstRow style?
|
||||
const std::map<OUString, css::uno::Any>& rGrabBag
|
||||
= pTableFormat->GetAttrSet().GetItem<SfxGrabBagItem>(RES_FRMATR_GRABBAG)->GetGrabBag();
|
||||
bool bIsUsingFirstRow = false;
|
||||
OUString sStyleId;
|
||||
for (const auto& rElement : rGrabBag)
|
||||
{
|
||||
if (rElement.first == "TableStyleName")
|
||||
sStyleId = rElement.second.get<OUString>();
|
||||
else if (rElement.first == "TableStyleLook")
|
||||
{
|
||||
for (const auto& rTblLook : rElement.second.get<uno::Sequence<beans::PropertyValue>>())
|
||||
{
|
||||
if (rTblLook.Name == "val")
|
||||
{
|
||||
bIsUsingFirstRow = rTblLook.Value.get<sal_Int32>() & 0x020;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bIsUsingFirstRow || sStyleId.isEmpty())
|
||||
return false;
|
||||
|
||||
return rTableStyleExport.FirstRowHasTblHeader(sStyleId);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void DocxAttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 /*nScript*/ )
|
||||
@@ -5061,7 +5091,17 @@ void DocxAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t c
|
||||
// Header row: tblHeader
|
||||
const SwTable *pTable = pTableTextNodeInfoInner->getTable( );
|
||||
if ( pTable->GetRowsToRepeat( ) > pTableTextNodeInfoInner->getRow( ) )
|
||||
m_pSerializer->singleElementNS(XML_w, XML_tblHeader, FSNS(XML_w, XML_val), "true"); // TODO to overwrite table style may need explicit false
|
||||
m_pSerializer->singleElementNS(XML_w, XML_tblHeader, FSNS(XML_w, XML_val), "true");
|
||||
else if (!pTableTextNodeInfoInner->getRow()) // first row
|
||||
{
|
||||
// Perhaps there is a table style attached to this table,
|
||||
// and perhaps that table style has a firstRow tblStylePr defined
|
||||
// and perhaps our tblLook uses that firstRow style
|
||||
// and perhaps the firstRow style defines a tblHeader
|
||||
// then in that case we need to write an explicit false to dis-inherit.
|
||||
if (lcl_HasTblHeaderFromStyle(pTable->GetFrameFormat(), *m_pTableStyleExport))
|
||||
m_pSerializer->singleElementNS(XML_w, XML_tblHeader, FSNS(XML_w, XML_val), "false");
|
||||
}
|
||||
|
||||
TableRowRedline( pTableTextNodeInfoInner );
|
||||
TableHeight( pTableTextNodeInfoInner );
|
||||
|
||||
@@ -31,6 +31,7 @@ struct DocxTableStyleExport::Impl
|
||||
private:
|
||||
SwDoc& m_rDoc;
|
||||
sax_fastparser::FSHelperPtr m_pSerializer;
|
||||
OUString m_sCurrentStyle;
|
||||
|
||||
public:
|
||||
Impl(SwDoc& rDoc)
|
||||
@@ -38,6 +39,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<OUString> m_vStylesWithTblHeaderInFirstRow;
|
||||
|
||||
void TableStyle(const uno::Sequence<beans::PropertyValue>& rStyle);
|
||||
|
||||
void setSerializer(sax_fastparser::FSHelperPtr pSerializer)
|
||||
@@ -559,7 +562,11 @@ void DocxTableStyleExport::Impl::tableStyleTrPr(const uno::Sequence<beans::Prope
|
||||
for (const auto& rProp : rTrPr)
|
||||
{
|
||||
if (rProp.Name == "tblHeader")
|
||||
{
|
||||
m_pSerializer->singleElementNS(XML_w, XML_tblHeader);
|
||||
if (!m_sCurrentStyle.isEmpty())
|
||||
m_vStylesWithTblHeaderInFirstRow.push_back(m_sCurrentStyle);
|
||||
}
|
||||
}
|
||||
|
||||
m_pSerializer->endElementNS(XML_w, XML_trPr);
|
||||
@@ -648,7 +655,6 @@ void DocxTableStyleExport::Impl::TableStyle(const uno::Sequence<beans::PropertyV
|
||||
bool bQFormat = false;
|
||||
bool bSemiHidden = false;
|
||||
bool bUnhideWhenUsed = false;
|
||||
OUString aStyleId;
|
||||
OUString aName;
|
||||
OUString aBasedOn;
|
||||
OUString aRsid;
|
||||
@@ -658,6 +664,7 @@ void DocxTableStyleExport::Impl::TableStyle(const uno::Sequence<beans::PropertyV
|
||||
uno::Sequence<beans::PropertyValue> aTablePr;
|
||||
uno::Sequence<beans::PropertyValue> aTcPr;
|
||||
std::vector<uno::Sequence<beans::PropertyValue>> aTableStylePrs;
|
||||
m_sCurrentStyle.clear();
|
||||
for (const auto& rProp : rStyle)
|
||||
{
|
||||
if (rProp.Name == "default")
|
||||
@@ -665,7 +672,7 @@ void DocxTableStyleExport::Impl::TableStyle(const uno::Sequence<beans::PropertyV
|
||||
else if (rProp.Name == "customStyle")
|
||||
bCustomStyle = rProp.Value.get<bool>();
|
||||
else if (rProp.Name == "styleId")
|
||||
aStyleId = rProp.Value.get<OUString>();
|
||||
m_sCurrentStyle = rProp.Value.get<OUString>();
|
||||
else if (rProp.Name == "name")
|
||||
aName = rProp.Value.get<OUString>();
|
||||
else if (rProp.Name == "basedOn")
|
||||
@@ -699,8 +706,8 @@ void DocxTableStyleExport::Impl::TableStyle(const uno::Sequence<beans::PropertyV
|
||||
pAttributeList->add(FSNS(XML_w, XML_default), "1");
|
||||
if (bCustomStyle)
|
||||
pAttributeList->add(FSNS(XML_w, XML_customStyle), "1");
|
||||
if (!aStyleId.isEmpty())
|
||||
pAttributeList->add(FSNS(XML_w, XML_styleId), aStyleId);
|
||||
if (!m_sCurrentStyle.isEmpty())
|
||||
pAttributeList->add(FSNS(XML_w, XML_styleId), m_sCurrentStyle);
|
||||
m_pSerializer->startElementNS(XML_w, XML_style, pAttributeList);
|
||||
|
||||
m_pSerializer->singleElementNS(XML_w, XML_name, FSNS(XML_w, XML_val), aName);
|
||||
@@ -727,6 +734,14 @@ void DocxTableStyleExport::Impl::TableStyle(const uno::Sequence<beans::PropertyV
|
||||
m_pSerializer->endElementNS(XML_w, XML_style);
|
||||
}
|
||||
|
||||
bool DocxTableStyleExport::FirstRowHasTblHeader(const OUString& rStyleId) const
|
||||
{
|
||||
auto pIter = std::find_if(std::cbegin(m_pImpl->m_vStylesWithTblHeaderInFirstRow),
|
||||
std::cend(m_pImpl->m_vStylesWithTblHeaderInFirstRow),
|
||||
[rStyleId](const OUString& rName) { return rName == rStyleId; });
|
||||
return (pIter != std::cend(m_pImpl->m_vStylesWithTblHeaderInFirstRow));
|
||||
}
|
||||
|
||||
void DocxTableStyleExport::SetSerializer(const sax_fastparser::FSHelperPtr& pSerializer)
|
||||
{
|
||||
m_pImpl->setSerializer(pSerializer);
|
||||
|
||||
@@ -35,6 +35,9 @@ public:
|
||||
void SetSerializer(const sax_fastparser::FSHelperPtr& pSerializer);
|
||||
DocxTableStyleExport(SwDoc& rDoc, const sax_fastparser::FSHelperPtr& pSerializer);
|
||||
~DocxTableStyleExport();
|
||||
|
||||
// This function only returns useful/cached results after EndStyles - i.e. in WriteMainText
|
||||
bool FirstRowHasTblHeader(const OUString& rStyleId) const;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_SW_SOURCE_FILTER_WW8_DOCXTABLESTYLEEXPORT_HXX
|
||||
|
||||
Reference in New Issue
Block a user