oox: Do not overwrite table style properties

Some table properties can be defined by the table style but cells can
overwrite them in their cell properties section. Our exporter was
writing all the cell properties in all cases, regardless of them
being defined by the theme or not, and we shouldn't do that if we
want the document to work properly in Word.

To fix the issue I store the style-defined cell properties (the
format of all four borders) in the table grab bag. The exporter
recovers them and compares with the cell properties before writing
them; if the cell property matches the stlye-defined one, we don't
write it to the document.

An existing unit test was slightly modified to check that the actual
cell properties are not being skipped.

Change-Id: I3aa12d76fb8f73d3fd300f254d19e1683fb6146c
This commit is contained in:
Jacobo Aragunde Pérez 2014-04-03 16:27:37 +02:00
parent f9636d50e6
commit ae61569eea
5 changed files with 99 additions and 17 deletions

View File

@ -1956,6 +1956,11 @@ DECLARE_OOXMLEXPORT_TEST(testTableThemePreservation, "table-theme-preservation.d
// check table style has been preserved // check table style has been preserved
assertXPath(pXmlDocument, "/w:document/w:body/w:tbl/w:tblPr/w:tblStyle", "val", "Sombreadoclaro-nfasis1"); assertXPath(pXmlDocument, "/w:document/w:body/w:tbl/w:tblPr/w:tblStyle", "val", "Sombreadoclaro-nfasis1");
// check table style is not overwritten by other properties
assertXPath(pXmlDocument, "/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/*", 0);
assertXPath(pXmlDocument, "/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/*", 0);
// check that one cell attribute present in the original document has been preserved
assertXPath(pXmlDocument, "/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:tcBorders/*", 1);
} }

View File

@ -2075,7 +2075,8 @@ void DocxAttributeOutput::ParagraphStyle( sal_uInt16 nStyle )
m_pSerializer->singleElementNS( XML_w, XML_pStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND ); m_pSerializer->singleElementNS( XML_w, XML_pStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND );
} }
static void impl_borderLine( FSHelperPtr pSerializer, sal_Int32 elementToken, const SvxBorderLine* pBorderLine, sal_uInt16 nDist, bool bWriteShadow = false ) static void impl_borderLine( FSHelperPtr pSerializer, sal_Int32 elementToken, const SvxBorderLine* pBorderLine, sal_uInt16 nDist,
bool bWriteShadow = false, const table::BorderLine2* rStyleProps = NULL )
{ {
FastAttributeList* pAttr = pSerializer->createAttrList(); FastAttributeList* pAttr = pSerializer->createAttrList();
@ -2141,6 +2142,19 @@ static void impl_borderLine( FSHelperPtr pSerializer, sal_Int32 elementToken, co
break; break;
} }
} }
else if( rStyleProps == NULL )
// no line, and no line set by the style either:
// there is no need to write the property
return;
// compare the properties with the theme properties before writing them:
// if they are equal, it means that they were style-defined and there is
// no need to write them.
if( rStyleProps != NULL && pBorderLine && !pBorderLine->isEmpty() &&
pBorderLine->GetBorderLineStyle() == rStyleProps->LineStyle &&
pBorderLine->GetColor() == rStyleProps->Color &&
pBorderLine->GetWidth() == MM100_TO_TWIP_UNSIGNED( rStyleProps->LineWidth ) )
return;
pAttr->add( FSNS( XML_w, XML_val ), OString( pVal ) ); pAttr->add( FSNS( XML_w, XML_val ), OString( pVal ) );
@ -2235,7 +2249,8 @@ static bool boxHasLineLargerThan31(const SvxBoxItem& rBox)
); );
} }
static void impl_borders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, const OutputBorderOptions& rOptions, PageMargins* pageMargins) static void impl_borders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, const OutputBorderOptions& rOptions, PageMargins* pageMargins,
std::map<sal_uInt16, css::table::BorderLine2> &rTableStyleConf )
{ {
static const sal_uInt16 aBorders[] = static const sal_uInt16 aBorders[] =
{ {
@ -2267,6 +2282,9 @@ static void impl_borders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, const
for( int i = 0; i < 4; ++i, ++pBrd ) for( int i = 0; i < 4; ++i, ++pBrd )
{ {
const SvxBorderLine* pLn = rBox.GetLine( *pBrd ); const SvxBorderLine* pLn = rBox.GetLine( *pBrd );
const table::BorderLine2 *aStyleProps = NULL;
if( rTableStyleConf.find( *pBrd ) != rTableStyleConf.end() )
aStyleProps = &rTableStyleConf[ *pBrd ];
if (!tagWritten && rOptions.bWriteTag) if (!tagWritten && rOptions.bWriteTag)
{ {
@ -2326,7 +2344,7 @@ static void impl_borders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, const
} }
} }
impl_borderLine( pSerializer, aXmlElements[i], pLn, nDist, bWriteShadow ); impl_borderLine( pSerializer, aXmlElements[i], pLn, nDist, bWriteShadow, aStyleProps );
// When exporting default borders, we need to export these 2 attr // When exporting default borders, we need to export these 2 attr
if ( rOptions.bWriteInsideHV) { if ( rOptions.bWriteInsideHV) {
@ -2337,9 +2355,19 @@ static void impl_borders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, const
} }
} }
if (bWriteInsideH) if (bWriteInsideH)
impl_borderLine( pSerializer, XML_insideH, rBox.GetLine(BOX_LINE_BOTTOM), 0 ); {
const table::BorderLine2 *aStyleProps = NULL;
if( rTableStyleConf.find( BOX_LINE_BOTTOM ) != rTableStyleConf.end() )
aStyleProps = &rTableStyleConf[ BOX_LINE_BOTTOM ];
impl_borderLine( pSerializer, XML_insideH, rBox.GetLine(BOX_LINE_BOTTOM), 0, false, aStyleProps );
}
if (bWriteInsideV) if (bWriteInsideV)
impl_borderLine( pSerializer, XML_insideV, rBox.GetLine(BOX_LINE_RIGHT), 0 ); {
const table::BorderLine2 *aStyleProps = NULL;
if( rTableStyleConf.find( BOX_LINE_RIGHT ) != rTableStyleConf.end() )
aStyleProps = &rTableStyleConf[ BOX_LINE_RIGHT ];
impl_borderLine( pSerializer, XML_insideV, rBox.GetLine(BOX_LINE_RIGHT), 0, false, aStyleProps );
}
if (tagWritten && rOptions.bWriteTag) { if (tagWritten && rOptions.bWriteTag) {
pSerializer->endElementNS( XML_w, rOptions.tag ); pSerializer->endElementNS( XML_w, rOptions.tag );
} }
@ -2450,7 +2478,7 @@ void DocxAttributeOutput::TableCellProperties( ww8::WW8TableNodeInfoInner::Point
const SvxBoxItem& rDefaultBox = (*tableFirstCells.rbegin())->getTableBox( )->GetFrmFmt( )->GetBox( ); const SvxBoxItem& rDefaultBox = (*tableFirstCells.rbegin())->getTableBox( )->GetFrmFmt( )->GetBox( );
{ {
// The cell borders // The cell borders
impl_borders( m_pSerializer, rBox, lcl_getTableCellBorderOptions(bEcma), NULL ); impl_borders( m_pSerializer, rBox, lcl_getTableCellBorderOptions(bEcma), NULL, m_aTableStyleConf );
} }
TableBackgrounds( pTableTextNodeInfoInner ); TableBackgrounds( pTableTextNodeInfoInner );
@ -2549,6 +2577,8 @@ void DocxAttributeOutput::EndTable()
// Cleans the table helper // Cleans the table helper
delete m_pTableWrt, m_pTableWrt = NULL; delete m_pTableWrt, m_pTableWrt = NULL;
m_aTableStyleConf.clear();
} }
void DocxAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) void DocxAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
@ -2678,14 +2708,25 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t
if ( SFX_ITEM_ON == pTblFmt->GetAttrSet().GetItemState( RES_FRMATR_GRABBAG, false, &pI ) ) if ( SFX_ITEM_ON == pTblFmt->GetAttrSet().GetItemState( RES_FRMATR_GRABBAG, false, &pI ) )
aGrabBag = dynamic_cast<const SfxGrabBagItem *>(pI)->GetGrabBag(); aGrabBag = dynamic_cast<const SfxGrabBagItem *>(pI)->GetGrabBag();
// Write table style property if it exists // Extract properties from grab bag
std::map<OUString, com::sun::star::uno::Any>::iterator aGrabBagElement = aGrabBag.find("TableStyleName"); std::map<OUString, com::sun::star::uno::Any>::iterator aGrabBagElement;
if( aGrabBagElement != aGrabBag.end() ) for( aGrabBagElement = aGrabBag.begin(); aGrabBagElement != aGrabBag.end(); ++aGrabBagElement )
{ {
OString sStyleName = OUStringToOString( aGrabBagElement->second.get<OUString>(), RTL_TEXTENCODING_UTF8 ); if( aGrabBagElement->first == "TableStyleName")
m_pSerializer->singleElementNS( XML_w, XML_tblStyle, {
FSNS( XML_w, XML_val ), sStyleName.getStr(), OString sStyleName = OUStringToOString( aGrabBagElement->second.get<OUString>(), RTL_TEXTENCODING_UTF8 );
FSEND ); m_pSerializer->singleElementNS( XML_w, XML_tblStyle,
FSNS( XML_w, XML_val ), sStyleName.getStr(),
FSEND );
}
else if( aGrabBagElement->first == "TableStyleTopBorder" )
m_aTableStyleConf[ BOX_LINE_TOP ] = aGrabBagElement->second.get<table::BorderLine2>();
else if( aGrabBagElement->first == "TableStyleBottomBorder" )
m_aTableStyleConf[ BOX_LINE_BOTTOM ] = aGrabBagElement->second.get<table::BorderLine2>();
else if( aGrabBagElement->first == "TableStyleLeftBorder" )
m_aTableStyleConf[ BOX_LINE_LEFT ] = aGrabBagElement->second.get<table::BorderLine2>();
else if( aGrabBagElement->first == "TableStyleRightBorder" )
m_aTableStyleConf[ BOX_LINE_RIGHT ] = aGrabBagElement->second.get<table::BorderLine2>();
} }
// Output the table alignement // Output the table alignement
@ -2771,7 +2812,7 @@ void DocxAttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Point
bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT; bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
// the defaults of the table are taken from the top-left cell // the defaults of the table are taken from the top-left cell
impl_borders( m_pSerializer, pFrmFmt->GetBox( ), lcl_getTableDefaultBorderOptions(bEcma), NULL ); impl_borders( m_pSerializer, pFrmFmt->GetBox( ), lcl_getTableDefaultBorderOptions(bEcma), NULL, m_aTableStyleConf );
} }
void DocxAttributeOutput::TableDefaultCellMargins( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) void DocxAttributeOutput::TableDefaultCellMargins( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
@ -4623,7 +4664,9 @@ void DocxAttributeOutput::SectionPageBorders( const SwFrmFmt* pFmt, const SwFrmF
aOutputBorderOptions.aShadowLocation = pShadowItem->GetLocation(); aOutputBorderOptions.aShadowLocation = pShadowItem->GetLocation();
} }
impl_borders( m_pSerializer, rBox, aOutputBorderOptions, &m_pageMargins ); std::map<sal_uInt16, css::table::BorderLine2> aEmptyMap; // empty styles map
impl_borders( m_pSerializer, rBox, aOutputBorderOptions, &m_pageMargins,
aEmptyMap );
m_pSerializer->endElementNS( XML_w, XML_pgBorders ); m_pSerializer->endElementNS( XML_w, XML_pgBorders );
} }
@ -6804,7 +6847,9 @@ void DocxAttributeOutput::FormatBox( const SvxBoxItem& rBox )
// Open the paragraph's borders tag // Open the paragraph's borders tag
m_pSerializer->startElementNS( XML_w, XML_pBdr, FSEND ); m_pSerializer->startElementNS( XML_w, XML_pBdr, FSEND );
impl_borders( m_pSerializer, rBox, aOutputBorderOptions, &m_pageMargins ); std::map<sal_uInt16, css::table::BorderLine2> aEmptyMap; // empty styles map
impl_borders( m_pSerializer, rBox, aOutputBorderOptions, &m_pageMargins,
aEmptyMap );
// Close the paragraph's borders tag // Close the paragraph's borders tag
m_pSerializer->endElementNS( XML_w, XML_pBdr ); m_pSerializer->endElementNS( XML_w, XML_pBdr );

View File

@ -39,6 +39,8 @@
#include <oox/export/drawingml.hxx> #include <oox/export/drawingml.hxx>
#include <docxtablestyleexport.hxx> #include <docxtablestyleexport.hxx>
#include <com/sun/star/table/BorderLine2.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
class SwGrfNode; class SwGrfNode;
@ -868,6 +870,8 @@ private:
::sax_fastparser::FastAttributeList *m_pRunSdtPrTokenChildren; ::sax_fastparser::FastAttributeList *m_pRunSdtPrTokenChildren;
::sax_fastparser::FastAttributeList *m_pRunSdtPrDataBindingAttrs; ::sax_fastparser::FastAttributeList *m_pRunSdtPrDataBindingAttrs;
std::map<sal_uInt16, css::table::BorderLine2> m_aTableStyleConf;
public: public:
DocxAttributeOutput( DocxExport &rExport, ::sax_fastparser::FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML ); DocxAttributeOutput( DocxExport &rExport, ::sax_fastparser::FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML );

View File

@ -340,7 +340,7 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo
PropertyMap::iterator aTableStyleIter = PropertyMap::iterator aTableStyleIter =
m_aTableProperties->find(META_PROP_TABLE_STYLE_NAME); m_aTableProperties->find(META_PROP_TABLE_STYLE_NAME);
uno::Sequence< beans::PropertyValue > aGrabBag( 1 ); uno::Sequence< beans::PropertyValue > aGrabBag( 5 );
sal_Int32 nGrabBagSize = 0; sal_Int32 nGrabBagSize = 0;
if(aTableStyleIter != m_aTableProperties->end()) if(aTableStyleIter != m_aTableProperties->end())
{ {
@ -366,6 +366,33 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo
PropertyMapPtr pMergedProperties = lcl_SearchParentStyleSheetAndMergeProperties(pStyleSheet, pStyleSheetTable); PropertyMapPtr pMergedProperties = lcl_SearchParentStyleSheetAndMergeProperties(pStyleSheet, pStyleSheetTable);
table::BorderLine2 aBorderLine;
TableInfo rStyleInfo;
if (lcl_extractTableBorderProperty(pMergedProperties, PROP_TOP_BORDER, rStyleInfo, aBorderLine))
{
aGrabBag[1].Name = "TableStyleTopBorder";
aGrabBag[1].Value = uno::makeAny( aBorderLine );
nGrabBagSize++;
}
if (lcl_extractTableBorderProperty(pMergedProperties, PROP_BOTTOM_BORDER, rStyleInfo, aBorderLine))
{
aGrabBag[2].Name = "TableStyleBottomBorder";
aGrabBag[2].Value = uno::makeAny( aBorderLine );
nGrabBagSize++;
}
if (lcl_extractTableBorderProperty(pMergedProperties, PROP_LEFT_BORDER, rStyleInfo, aBorderLine))
{
aGrabBag[3].Name = "TableStyleLeftBorder";
aGrabBag[3].Value = uno::makeAny( aBorderLine );
nGrabBagSize++;
}
if (lcl_extractTableBorderProperty(pMergedProperties, PROP_RIGHT_BORDER, rStyleInfo, aBorderLine))
{
aGrabBag[4].Name = "TableStyleRightBorder";
aGrabBag[4].Value = uno::makeAny( aBorderLine );
nGrabBagSize++;
}
#ifdef DEBUG_DMAPPER_TABLE_HANDLER #ifdef DEBUG_DMAPPER_TABLE_HANDLER
dmapper_logger->startElement("mergedProps"); dmapper_logger->startElement("mergedProps");
pMergedProperties->dumpXml( dmapper_logger ); pMergedProperties->dumpXml( dmapper_logger );
@ -402,6 +429,7 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo
if( nGrabBagSize > 0 ) if( nGrabBagSize > 0 )
{ {
aGrabBag.realloc( nGrabBagSize );
m_aTableProperties->Insert( PROP_TABLE_INTEROP_GRAB_BAG, uno::makeAny( aGrabBag ) ); m_aTableProperties->Insert( PROP_TABLE_INTEROP_GRAB_BAG, uno::makeAny( aGrabBag ) );
} }