sc/qa/unit/data/ods/tdf121716_EvenHeaderFooter.ods |binary sc/qa/unit/subsequent_export-test.cxx | 52 ++++++++++++++++++--- sc/source/filter/excel/xepage.cxx | 49 +++++++++++++++++-- sc/source/filter/excel/xipage.cxx | 8 ++- sc/source/filter/excel/xlpage.cxx | 3 + sc/source/filter/inc/xlpage.hxx | 9 +++ 6 files changed, 106 insertions(+), 15 deletions(-)
New commits: commit 74ff90587db28aa199fdbcae0abb7f37f83fb617 Author: Attila Szűcs <szucs.atti...@nisz.hu> AuthorDate: Thu Jul 23 14:51:01 2020 +0200 Commit: Gabor Kelemen <kelemen.gab...@nisz.hu> CommitDate: Thu Feb 18 10:36:27 2021 +0100 tdf#121716 XLSX export: fix loss of left header (footer) when footer (header) is shared (even). Co-authored-by: Tibor Nagy (NISZ) Change-Id: I6e656f2df1f9b6522af933bd1c71b8d60bbfe19f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99315 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> (cherry picked from commit a858284092e976fa284d5ed118e366d9860ec9bb) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111048 Tested-by: Gabor Kelemen <kelemen.gab...@nisz.hu> Reviewed-by: Gabor Kelemen <kelemen.gab...@nisz.hu> diff --git a/sc/qa/unit/data/ods/tdf121716_EvenHeaderFooter.ods b/sc/qa/unit/data/ods/tdf121716_EvenHeaderFooter.ods new file mode 100644 index 000000000000..2666a9d4291e Binary files /dev/null and b/sc/qa/unit/data/ods/tdf121716_EvenHeaderFooter.ods differ diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx index 56f38a3697a9..e84a464ab886 100644 --- a/sc/qa/unit/subsequent_export-test.cxx +++ b/sc/qa/unit/subsequent_export-test.cxx @@ -257,8 +257,9 @@ public: void testTdf131372(); void testTdf122331(); void testTdf83779(); - void testTdf134817_HeaderFooterTextWith2SectionXLSX(); + void testTdf121716_ExportEvenHeaderFooterXLSX(); void testTdf134459_HeaderFooterColorXLSX(); + void testTdf134817_HeaderFooterTextWith2SectionXLSX(); void testHeaderFontStyleXLSX(); void testTdf135828_Shape_Rect(); void testTdf123353(); @@ -414,6 +415,7 @@ public: CPPUNIT_TEST(testTdf131372); CPPUNIT_TEST(testTdf122331); CPPUNIT_TEST(testTdf83779); + CPPUNIT_TEST(testTdf121716_ExportEvenHeaderFooterXLSX); CPPUNIT_TEST(testTdf134817_HeaderFooterTextWith2SectionXLSX); CPPUNIT_TEST(testTdf134459_HeaderFooterColorXLSX); CPPUNIT_TEST(testHeaderFontStyleXLSX); @@ -5195,20 +5197,36 @@ void ScExportTest::testTdf83779() xShell->DoClose(); } -void ScExportTest::testTdf134817_HeaderFooterTextWith2SectionXLSX() +void ScExportTest::testTdf121716_ExportEvenHeaderFooterXLSX() { - // Header/footer text with multiple selection should be exported, and imported properly - ScDocShellRef xShell = loadDoc("tdf134817_HeaderFooterTextWith2Section.", FORMAT_XLSX); + // Header and footer on even pages should be exported properly + // If there are separate odd/even header, but only 1 footer for all pages (this is possible only in LibreOffice) + // then the footer will be duplicated to have the same footer separately for even/odd pages + + ScDocShellRef xShell = loadDoc("tdf121716_EvenHeaderFooter.", FORMAT_ODS); CPPUNIT_ASSERT(xShell.is()); ScDocShellRef xDocSh = saveAndReload(&(*xShell), FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); - xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); + std::shared_ptr<utl::TempFile> pXPathFile = ScBootstrapFixture::exportTo(&(*xDocSh), FORMAT_XLSX); + xmlDocUniquePtr pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pDoc); - assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddHeader", "&L&\"Abadi,Regular\"&11aaa&\"Bembo,Regular\"&20bbb"); - assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddFooter", "&R&\"Cambria,Regular\"&14camb&\"Dante,Regular\"&18dant"); + assertXPath(pDoc, "/x:worksheet/x:headerFooter", "differentOddEven", "true"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddHeader", "&Lodd/right&Cpage&Rheader"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddFooter", "&Lboth&C&12page&Rfooter"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:evenHeader", "&Lpage&Cheader&Reven/left"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:evenFooter", "&Lboth&C&12page&Rfooter"); + + pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet2.xml"); + CPPUNIT_ASSERT(pDoc); + + assertXPath(pDoc, "/x:worksheet/x:headerFooter", "differentOddEven", "true"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddHeader", "&Coddh"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddFooter", "&Coddf"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:evenHeader", "&Cevenh"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:evenFooter", "&Levenf"); xDocSh->DoClose(); } @@ -5227,6 +5245,26 @@ void ScExportTest::testTdf134459_HeaderFooterColorXLSX() assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddHeader", "&L&Kc06040l&C&K4c3789c&Rr"); assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddFooter", "&Ll&C&K64cf5fc&R&Kcd15aar"); + + xDocSh->DoClose(); +} + +void ScExportTest::testTdf134817_HeaderFooterTextWith2SectionXLSX() +{ + // Header/footer text with multiple selection should be exported, and imported properly + ScDocShellRef xShell = loadDoc("tdf134817_HeaderFooterTextWith2Section.", FORMAT_XLSX); + CPPUNIT_ASSERT(xShell.is()); + + ScDocShellRef xDocSh = saveAndReload(&(*xShell), FORMAT_XLSX); + CPPUNIT_ASSERT(xDocSh.is()); + + xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); + CPPUNIT_ASSERT(pDoc); + + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddHeader", "&L&\"Abadi,Regular\"&11aaa&\"Bembo,Regular\"&20bbb"); + assertXPathContent(pDoc, "/x:worksheet/x:headerFooter/x:oddFooter", "&R&\"Cambria,Regular\"&14camb&\"Dante,Regular\"&18dant"); + + xDocSh->DoClose(); } void ScExportTest::testHeaderFontStyleXLSX() diff --git a/sc/source/filter/excel/xepage.cxx b/sc/source/filter/excel/xepage.cxx index aea06c72157b..3941bd191f92 100644 --- a/sc/source/filter/excel/xepage.cxx +++ b/sc/source/filter/excel/xepage.cxx @@ -58,7 +58,14 @@ XclExpHeaderFooter::XclExpHeaderFooter( sal_uInt16 nRecId, const OUString& rHdrS void XclExpHeaderFooter::SaveXml( XclExpXmlStream& rStrm ) { sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream(); - sal_Int32 nElement = GetRecId() == EXC_ID_HEADER ? XML_oddHeader : XML_oddFooter; + sal_Int32 nElement; + switch(GetRecId()) { + case EXC_ID_HEADER_EVEN: nElement = XML_evenHeader; break; + case EXC_ID_FOOTER_EVEN: nElement = XML_evenFooter; break; + case EXC_ID_HEADER: nElement = XML_oddHeader; break; + case EXC_ID_FOOTER: + default: nElement = XML_oddFooter; + } rWorksheet->startElement(nElement); rWorksheet->writeEscaped( maHdrString ); rWorksheet->endElement( nElement ); @@ -252,7 +259,6 @@ XclExpPageSettings::XclExpPageSettings( const XclExpRoot& rRoot ) : maData.mnFitToWidth = rScaleToItem.GetWidth(); maData.mnFitToHeight = rScaleToItem.GetHeight(); maData.mbFitToPages = true; - } else if( ScfTools::CheckItem( rItemSet, ATTR_PAGE_SCALETOPAGES, false ) && nPages ) { @@ -267,6 +273,7 @@ XclExpPageSettings::XclExpPageSettings( const XclExpRoot& rRoot ) : } maData.mxBrushItem.reset( new SvxBrushItem( rItemSet.Get( ATTR_BACKGROUND ) ) ); + maData.mbUseEvenHF = false; // *** header and footer *** @@ -279,6 +286,18 @@ XclExpPageSettings::XclExpPageSettings( const XclExpRoot& rRoot ) : const ScPageHFItem& rHFItem = rItemSet.Get( ATTR_PAGE_HEADERRIGHT ); aHFConv.GenerateString( rHFItem.GetLeftArea(), rHFItem.GetCenterArea(), rHFItem.GetRightArea() ); maData.maHeader = aHFConv.GetHFString(); + if ( rHdrItemSet.HasItem(ATTR_PAGE_SHARED) && !rHdrItemSet.Get(ATTR_PAGE_SHARED).GetValue()) + { + const ScPageHFItem& rHFItemLeft = rItemSet.Get( ATTR_PAGE_HEADERLEFT ); + aHFConv.GenerateString( rHFItemLeft.GetLeftArea(), rHFItemLeft.GetCenterArea(), rHFItemLeft.GetRightArea() ); + maData.maHeaderEven = aHFConv.GetHFString(); + maData.mbUseEvenHF = true; + } + else + { + // If maData.mbUseEvenHF become true, then we will need a copy of maHeader in maHeaderEven. + maData.maHeaderEven = maData.maHeader; + } // header height (Excel excludes header from top margin) sal_Int32 nHdrHeight = rHdrItemSet.Get( ATTR_PAGE_DYNAMIC ).GetValue() ? // dynamic height: calculate header height, add header <-> sheet area distance @@ -296,6 +315,17 @@ XclExpPageSettings::XclExpPageSettings( const XclExpRoot& rRoot ) : const ScPageHFItem& rHFItem = rItemSet.Get( ATTR_PAGE_FOOTERRIGHT ); aHFConv.GenerateString( rHFItem.GetLeftArea(), rHFItem.GetCenterArea(), rHFItem.GetRightArea() ); maData.maFooter = aHFConv.GetHFString(); + if (rFtrItemSet.HasItem(ATTR_PAGE_SHARED) && !rFtrItemSet.Get(ATTR_PAGE_SHARED).GetValue()) + { + const ScPageHFItem& rHFItemLeft = rItemSet.Get( ATTR_PAGE_FOOTERLEFT ); + aHFConv.GenerateString( rHFItemLeft.GetLeftArea(), rHFItemLeft.GetCenterArea(), rHFItemLeft.GetRightArea() ); + maData.maFooterEven = aHFConv.GetHFString(); + maData.mbUseEvenHF = true; + } + else + { + maData.maFooterEven = maData.maFooter; + } // footer height (Excel excludes footer from bottom margin) sal_Int32 nFtrHeight = rFtrItemSet.Get( ATTR_PAGE_DYNAMIC ).GetValue() ? // dynamic height: calculate footer height, add sheet area <-> footer distance @@ -340,10 +370,12 @@ namespace { class XclExpXmlStartHeaderFooterElementRecord : public XclExpXmlElementRecord { public: - explicit XclExpXmlStartHeaderFooterElementRecord(sal_Int32 const nElement) - : XclExpXmlElementRecord(nElement) {} + explicit XclExpXmlStartHeaderFooterElementRecord(sal_Int32 const nElement, bool const bDifferentOddEven = false) + : XclExpXmlElementRecord(nElement), mbDifferentOddEven(bDifferentOddEven) {} virtual void SaveXml( XclExpXmlStream& rStrm ) override; +private: + bool mbDifferentOddEven; }; } @@ -356,7 +388,7 @@ void XclExpXmlStartHeaderFooterElementRecord::SaveXml(XclExpXmlStream& rStrm) rStream->startElement( mnElement, // OOXTODO: XML_alignWithMargins, XML_differentFirst, "false", // OOXTODO - XML_differentOddEven, "false" // OOXTODO + XML_differentOddEven, mbDifferentOddEven ? "true" : "false" // OOXTODO: XML_scaleWithDoc ); } @@ -404,9 +436,14 @@ void XclExpPageSettings::SaveXml( XclExpXmlStream& rStrm ) XclExpSetup( maData ).SaveXml( rStrm ); - XclExpXmlStartHeaderFooterElementRecord(XML_headerFooter).SaveXml(rStrm); + XclExpXmlStartHeaderFooterElementRecord(XML_headerFooter, maData.mbUseEvenHF).SaveXml(rStrm); XclExpHeaderFooter( EXC_ID_HEADER, maData.maHeader ).SaveXml( rStrm ); XclExpHeaderFooter( EXC_ID_FOOTER, maData.maFooter ).SaveXml( rStrm ); + if (maData.mbUseEvenHF) + { + XclExpHeaderFooter( EXC_ID_HEADER_EVEN, maData.maHeaderEven ).SaveXml( rStrm ); + XclExpHeaderFooter( EXC_ID_FOOTER_EVEN, maData.maFooterEven ).SaveXml( rStrm ); + } XclExpXmlEndElementRecord( XML_headerFooter ).SaveXml( rStrm ); XclExpPageBreaks( EXC_ID_HORPAGEBREAKS, maData.maHorPageBreaks, diff --git a/sc/source/filter/excel/xipage.cxx b/sc/source/filter/excel/xipage.cxx index 7436c3eaed2c..c0207a033b00 100644 --- a/sc/source/filter/excel/xipage.cxx +++ b/sc/source/filter/excel/xipage.cxx @@ -118,13 +118,17 @@ void XclImpPageSettings::ReadHeaderFooter( XclImpStream& rStrm ) switch( rStrm.GetRecId() ) { - case EXC_ID_HEADER: maData.maHeader = aString; break; - case EXC_ID_FOOTER: maData.maFooter = aString; break; + case EXC_ID_HEADER: maData.maHeader = aString; break; + case EXC_ID_FOOTER: maData.maFooter = aString; break; + case EXC_ID_HEADER_EVEN: maData.maHeaderEven = aString; break; + case EXC_ID_FOOTER_EVEN: maData.maFooterEven = aString; break; default: OSL_FAIL( "XclImpPageSettings::ReadHeaderFooter - unknown record" ); } if (maData.maHeader.getLength() > 10 && utl::ConfigManager::IsFuzzing()) maData.maHeader = maData.maHeader.copy(0, 10); + if (maData.maHeaderEven.getLength() > 10 && utl::ConfigManager::IsFuzzing()) + maData.maHeaderEven = maData.maHeaderEven.copy(0, 10); } void XclImpPageSettings::ReadPageBreaks( XclImpStream& rStrm ) diff --git a/sc/source/filter/excel/xlpage.cxx b/sc/source/filter/excel/xlpage.cxx index fb08932872f1..3f13befddcfa 100644 --- a/sc/source/filter/excel/xlpage.cxx +++ b/sc/source/filter/excel/xlpage.cxx @@ -180,6 +180,8 @@ void XclPageData::SetDefaults() mxBrushItem.reset(); maHeader.clear(); maFooter.clear(); + maHeaderEven.clear(); + maFooterEven.clear(); mfLeftMargin = mfRightMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_LR ); mfTopMargin = mfBottomMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_TB ); mfHeaderMargin = mfFooterMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_HF ); @@ -193,6 +195,7 @@ void XclPageData::SetDefaults() mnScaling = 100; mnFitToWidth = mnFitToHeight = 1; mnHorPrintRes = mnVerPrintRes = 300; + mbUseEvenHF = /*mbUseFirstHF =*/ false; mbValid = false; mbPortrait = true; mbPrintInRows = mbBlackWhite = mbDraftQuality = mbPrintNotes = mbManualStart = mbFitToPages = false; diff --git a/sc/source/filter/inc/xlpage.hxx b/sc/source/filter/inc/xlpage.hxx index 8ae20f85d1ba..36190b2e8693 100644 --- a/sc/source/filter/inc/xlpage.hxx +++ b/sc/source/filter/inc/xlpage.hxx @@ -31,6 +31,11 @@ const sal_uInt16 EXC_ID_HEADER = 0x0014; const sal_uInt16 EXC_ID_FOOTER = 0x0015; +// (0x0016, 0x0017) EVEN HEADER, EVEN FOOTER ---------------------------------- + +const sal_uInt16 EXC_ID_HEADER_EVEN = 0x0016; +const sal_uInt16 EXC_ID_FOOTER_EVEN = 0x0017; + // (0x001A, 0x001B) VERTICAL-, HORIZONTALPAGEBREAKS --------------------------- const sal_uInt16 EXC_ID_VERPAGEBREAKS = 0x001A; @@ -102,6 +107,8 @@ struct XclPageData SvxBrushItemPtr mxBrushItem; /// Background bitmap. OUString maHeader; /// Excel header string (empty = off). OUString maFooter; /// Excel footer string (empty = off). + OUString maHeaderEven; /// Excel header string for even pages (empty = off). + OUString maFooterEven; /// Excel footer string for even pages (empty = off). double mfLeftMargin; /// Left margin in inches. double mfRightMargin; /// Right margin in inches. double mfTopMargin; /// Top margin in inches. @@ -123,6 +130,8 @@ struct XclPageData sal_uInt16 mnFitToHeight; /// Fit to number of pages in height. sal_uInt16 mnHorPrintRes; /// Horizontal printing resolution. sal_uInt16 mnVerPrintRes; /// Vertical printing resolution. + bool mbUseEvenHF; /// True = use maHeaderEven/maFooterEven. +// bool mbUseFirstHF; /// True = use maHeaderFirst/maFooterFirst. TODO: not implemented yet. bool mbValid; /// false = some of the values are not valid. bool mbPortrait; /// true = portrait; false = landscape. bool mbPrintInRows; /// true = in rows; false = in columns. _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits