summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Deller <luke@deller.id.au>2016-01-03 23:12:56 +1100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-05-03 15:57:23 +0000
commit7e9b5d9ba6bccdc75bfee4ddfd2f1582ea10746f (patch)
treef8a0f5a89da6952232b7122cf972bce58e849a9b
parent5e5e155ddf467cdce2312fa16d0392900afc7355 (diff)
tdf#93640 Fix import of linked left page header/footer
In a docx section, any header/footer which is not defined in the section is considered to be linked to the previous section. In the Word UI this is shown as an option named "Link to Previous", and editing the header/footer in either section affects both sections. LO imports this by copying the header/footer contents from the previous section, but it did not handle the case where a section had different headers for left pages vs right pages. Fix this, which involved changing the mechanism used to detect whether a section has defined a certain header/footer (which unlinks it from the previous section): rather than trying to figure it out from the converted LO page styles, explicitly track which headers/footers have been defined using boolean member variables on the SectionPropertyMap instance. Conflicts: sw/qa/extras/ooxmlimport/ooxmlimport.cxx Change-Id: Ic43a867356c2cd5df09d39f2a3ddefa584b6765c Reviewed-on: https://gerrit.libreoffice.org/24608 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r--sw/qa/extras/ooxmlimport/data/headerfooter-link-to-prev.docxbin0 -> 18770 bytes
-rw-r--r--sw/qa/extras/ooxmlimport/ooxmlimport.cxx100
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx4
-rw-r--r--writerfilter/source/dmapper/PropertyMap.cxx173
-rw-r--r--writerfilter/source/dmapper/PropertyMap.hxx21
5 files changed, 244 insertions, 54 deletions
diff --git a/sw/qa/extras/ooxmlimport/data/headerfooter-link-to-prev.docx b/sw/qa/extras/ooxmlimport/data/headerfooter-link-to-prev.docx
new file mode 100644
index 000000000000..cc4ddc89bb9b
--- /dev/null
+++ b/sw/qa/extras/ooxmlimport/data/headerfooter-link-to-prev.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
index b336fcb5de48..1c026e68b869 100644
--- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
+++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
@@ -3108,6 +3108,106 @@ DECLARE_OOXMLIMPORT_TEST(testTdf99140, "tdf99140.docx")
CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::LEFT_AND_WIDTH, getProperty<sal_Int16>(xTableProperties, "HoriOrient"));
}
+// base class to supply a helper method for testHFLinkToPrev
+class testHFBase : public Test
+{
+protected:
+ OUString
+ getHFText(const uno::Reference<style::XStyle>& xPageStyle,
+ const OUString &sPropName)
+ {
+ auto xTextRange = getProperty< uno::Reference<text::XTextRange> >(
+ xPageStyle, sPropName);
+ return xTextRange->getString();
+ }
+};
+
+DECLARE_SW_IMPORT_TEST(testHFLinkToPrev, "headerfooter-link-to-prev.docx",
+ testHFBase)
+{
+ uno::Reference<container::XNameAccess> xPageStyles = getStyles("PageStyles");
+
+ // get a page cursor
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
+ xModel->getCurrentController(), uno::UNO_QUERY);
+ uno::Reference<text::XPageCursor> xCursor(
+ xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY);
+
+ // get LO page style for page 1, corresponding to docx section 1 first page
+ xCursor->jumpToFirstPage();
+ OUString pageStyleName = getProperty<OUString>(xCursor, "PageStyleName");
+ uno::Reference<style::XStyle> xPageStyle(
+ xPageStyles->getByName(pageStyleName), uno::UNO_QUERY);
+ // check page 1 header & footer text
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderText"),
+ OUString("First page header for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterText"),
+ OUString("First page footer for section 1 only"));
+
+ // get LO page style for page 2, corresponding to docx section 1
+ xCursor->jumpToPage(2);
+ pageStyleName = getProperty<OUString>(xCursor, "PageStyleName");
+ xPageStyle.set( xPageStyles->getByName(pageStyleName), uno::UNO_QUERY );
+ // check header & footer text
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderTextLeft"),
+ OUString("Even page header for section 1 only"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterTextLeft"),
+ OUString("Even page footer for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderText"),
+ OUString("Odd page header for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterText"),
+ OUString("Odd page footer for section 1 only"));
+
+ // get LO page style for page 4, corresponding to docx section 2 first page
+ xCursor->jumpToPage(4);
+ pageStyleName = getProperty<OUString>(xCursor, "PageStyleName");
+ xPageStyle.set( xPageStyles->getByName(pageStyleName), uno::UNO_QUERY );
+ // check header & footer text
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderText"),
+ OUString("First page header for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterText"),
+ OUString("First page footer for sections 2 and 3 only"));
+
+ // get LO page style for page 5, corresponding to docx section 2
+ xCursor->jumpToPage(5);
+ pageStyleName = getProperty<OUString>(xCursor, "PageStyleName");
+ xPageStyle.set( xPageStyles->getByName(pageStyleName), uno::UNO_QUERY );
+ // check header & footer text
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderTextLeft"),
+ OUString("Even page header for sections 2 and 3 only"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterTextLeft"),
+ OUString("Even page footer for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderText"),
+ OUString("Odd page header for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterText"),
+ OUString("Odd page footer for sections 2 and 3 only"));
+
+ // get LO page style for page 7, corresponding to docx section 3 first page
+ xCursor->jumpToPage(7);
+ pageStyleName = getProperty<OUString>(xCursor, "PageStyleName");
+ xPageStyle.set( xPageStyles->getByName(pageStyleName), uno::UNO_QUERY );
+ // check header & footer text
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderText"),
+ OUString("First page header for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterText"),
+ OUString("First page footer for sections 2 and 3 only"));
+
+ // get LO page style for page 8, corresponding to docx section 3
+ xCursor->jumpToPage(8);
+ pageStyleName = getProperty<OUString>(xCursor, "PageStyleName");
+ xPageStyle.set( xPageStyles->getByName(pageStyleName), uno::UNO_QUERY );
+ // check header & footer text
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderTextLeft"),
+ OUString("Even page header for sections 2 and 3 only"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterTextLeft"),
+ OUString("Even page footer for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "HeaderText"),
+ OUString("Odd page header for all sections"));
+ CPPUNIT_ASSERT_EQUAL(getHFText(xPageStyle, "FooterText"),
+ OUString("Odd page footer for sections 2 and 3 only"));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 9f8ef2b92fae..ddaa8b78e928 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -1475,6 +1475,10 @@ void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::P
SectionPropertyMap* pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
if(pSectionContext)
{
+ // clear the "Link To Previous" flag so that the header/footer
+ // content is not copied from the previous section
+ pSectionContext->ClearHeaderFooterLinkToPrevious(bHeader, eType);
+
uno::Reference< beans::XPropertySet > xPageStyle =
pSectionContext->GetPageStyle(
GetPageStyles(),
diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx
index e15c259490c6..08c7f56d8f3a 100644
--- a/writerfilter/source/dmapper/PropertyMap.cxx
+++ b/writerfilter/source/dmapper/PropertyMap.cxx
@@ -426,6 +426,12 @@ SectionPropertyMap::SectionPropertyMap(bool bIsFirstSection) :
,m_nLnc( 0 )
,m_ndxaLnn( 0 )
,m_nLnnMin( 0 )
+ ,m_bDefaultHeaderLinkToPrevious(true)
+ ,m_bEvenPageHeaderLinkToPrevious(true)
+ ,m_bFirstPageHeaderLinkToPrevious(true)
+ ,m_bDefaultFooterLinkToPrevious(true)
+ ,m_bEvenPageFooterLinkToPrevious(true)
+ ,m_bFirstPageFooterLinkToPrevious(true)
{
static sal_Int32 nNumber = 0;
nSectionNumber = nNumber++;
@@ -801,72 +807,97 @@ bool SectionPropertyMap::HasFooter(bool bFirstPage) const
#define MIN_HEAD_FOOT_HEIGHT 100 //minimum header/footer height
-void SectionPropertyMap::CopyHeaderFooter( uno::Reference< beans::XPropertySet > xPrevStyle,
- uno::Reference< beans::XPropertySet > xStyle )
+void SectionPropertyMap::CopyHeaderFooterTextProperty (
+ uno::Reference< beans::XPropertySet > xPrevStyle,
+ uno::Reference< beans::XPropertySet > xStyle,
+ PropertyIds ePropId )
{
try {
- // Loop over the Header and Footer properties to copy them
- static const PropertyIds aProperties[] =
- {
- PROP_HEADER_TEXT,
- PROP_FOOTER_TEXT,
- };
-
- bool bHasPrevHeader = false;
- bool bHasHeader = false;
+ OUString sName = getPropertyName( ePropId );
- OUString sHeaderIsOn = getPropertyName( PROP_HEADER_IS_ON );
- if (xPrevStyle.is())
- xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader;
+ SAL_INFO("writerfilter", "Copying " << sName);
+ uno::Reference< text::XTextCopy > xTxt;
if (xStyle.is())
- xStyle->getPropertyValue( sHeaderIsOn ) >>= bHasHeader;
- bool bCopyHeader = bHasPrevHeader && !bHasHeader;
+ xTxt.set(xStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
- if ( bCopyHeader )
- xStyle->setPropertyValue( sHeaderIsOn, uno::makeAny( sal_True ) );
-
- bool bHasPrevFooter = false;
- bool bHasFooter = false;
-
- OUString sFooterIsOn = getPropertyName( PROP_FOOTER_IS_ON );
+ uno::Reference< text::XTextCopy > xPrevTxt;
if (xPrevStyle.is())
- xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter;
- if (xStyle.is())
- xStyle->getPropertyValue( sFooterIsOn ) >>= bHasFooter;
- bool bCopyFooter = bHasPrevFooter && !bHasFooter;
+ xPrevTxt.set(xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
- if ( bCopyFooter && xStyle.is() )
- xStyle->setPropertyValue( sFooterIsOn, uno::makeAny( sal_True ) );
-
- // Copying the text properties
- for ( int i = 0, nNbProps = 2; i < nNbProps; i++ )
- {
- bool bIsHeader = ( i < nNbProps / 2 );
- PropertyIds aPropId = aProperties[i];
- OUString sName = getPropertyName( aPropId );
-
- if ( ( bIsHeader && bCopyHeader ) || ( !bIsHeader && bCopyFooter ) )
- {
- SAL_INFO("writerfilter", "Copying " << sName);
- // TODO has to be copied
- uno::Reference< text::XTextCopy > xTxt;
- if (xStyle.is())
- xTxt.set(xStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
+ xTxt->copyText( xPrevTxt );
+ }
+ catch ( const uno::Exception& e )
+ {
+ SAL_INFO("writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooterTextProperty( ) - " << e.Message);
+ }
+}
- uno::Reference< text::XTextCopy > xPrevTxt;
- if (xPrevStyle.is())
- xPrevTxt.set(xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
+// Copy headers and footers from the previous page style.
+void SectionPropertyMap::CopyHeaderFooter(
+ uno::Reference< beans::XPropertySet > xPrevStyle,
+ uno::Reference< beans::XPropertySet > xStyle,
+ bool bOmitRightHeader, bool bOmitLeftHeader,
+ bool bOmitRightFooter, bool bOmitLeftFooter)
+{
+ bool bHasPrevHeader = false;
+ bool bHeaderIsShared = true;
+ OUString sHeaderIsOn = getPropertyName( PROP_HEADER_IS_ON );
+ OUString sHeaderIsShared = getPropertyName( PROP_HEADER_IS_SHARED );
+ if ( xPrevStyle.is() )
+ {
+ xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader;
+ xPrevStyle->getPropertyValue( sHeaderIsShared ) >>= bHeaderIsShared;
+ }
- xTxt->copyText( xPrevTxt );
- }
+ if ( bHasPrevHeader )
+ {
+ xStyle->setPropertyValue( sHeaderIsOn, uno::makeAny( sal_True ) );
+ xStyle->setPropertyValue( sHeaderIsShared, uno::makeAny(bHeaderIsShared));
+ if ( !bOmitRightHeader )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_HEADER_TEXT );
+ }
+ if ( !bHeaderIsShared && !bOmitLeftHeader )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_HEADER_TEXT_LEFT );
}
}
- catch ( const uno::Exception& e )
+
+ bool bHasPrevFooter = false;
+ bool bFooterIsShared = true;
+ OUString sFooterIsOn = getPropertyName( PROP_FOOTER_IS_ON );
+ OUString sFooterIsShared = getPropertyName( PROP_FOOTER_IS_SHARED );
+ if ( xPrevStyle.is() )
+ {
+ xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter;
+ xPrevStyle->getPropertyValue( sFooterIsShared ) >>= bFooterIsShared;
+ }
+
+ if ( bHasPrevFooter )
{
- SAL_INFO("writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooter( ) - " << e.Message);
+ xStyle->setPropertyValue( sFooterIsOn, uno::makeAny( sal_True ) );
+ xStyle->setPropertyValue( sFooterIsShared, uno::makeAny(bFooterIsShared) );
+ if ( !bOmitRightFooter )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_FOOTER_TEXT );
+ }
+ if ( !bFooterIsShared && !bOmitLeftFooter )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_FOOTER_TEXT_LEFT );
+ }
}
}
+// Copy header and footer content from the previous docx section as needed.
+//
+// Any headers and footers which were not defined in this docx section
+// should be "linked" with the corresponding header or footer from the
+// previous section. LO does not support linking of header/footer content
+// across page styles so we just copy the content from the previous section.
void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
{
SAL_INFO("writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()");
@@ -881,7 +912,21 @@ void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Imp
rDM_Impl.GetPageStyles(),
rDM_Impl.GetTextFactory(),
bFirstPage );
- CopyHeaderFooter( xPrevStyle, xStyle );
+
+ if (bFirstPage)
+ {
+ CopyHeaderFooter( xPrevStyle, xStyle,
+ !m_bFirstPageHeaderLinkToPrevious, true,
+ !m_bFirstPageFooterLinkToPrevious, true);
+ }
+ else
+ {
+ CopyHeaderFooter( xPrevStyle, xStyle,
+ !m_bDefaultHeaderLinkToPrevious,
+ !m_bEvenPageHeaderLinkToPrevious,
+ !m_bDefaultFooterLinkToPrevious,
+ !m_bEvenPageFooterLinkToPrevious);
+ }
}
SAL_INFO("writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()");
}
@@ -1335,6 +1380,30 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
rDM_Impl.SetIsFirstParagraphInSection(true);
}
+// Clear the flag that says we should take the header/footer content from
+// the previous section. This should be called when we encounter a header
+// or footer definition for this section.
+void SectionPropertyMap::ClearHeaderFooterLinkToPrevious(
+ bool bHeader, PageType eType )
+{
+ if( bHeader ) {
+ switch( eType ) {
+ case PAGE_FIRST: m_bFirstPageHeaderLinkToPrevious = false; break;
+ case PAGE_LEFT: m_bEvenPageHeaderLinkToPrevious = false; break;
+ case PAGE_RIGHT: m_bDefaultHeaderLinkToPrevious = false; break;
+ // no default case as all enumeration values have been covered
+ }
+ }
+ else
+ {
+ switch( eType ) {
+ case PAGE_FIRST: m_bFirstPageFooterLinkToPrevious = false; break;
+ case PAGE_LEFT: m_bEvenPageFooterLinkToPrevious = false; break;
+ case PAGE_RIGHT: m_bDefaultFooterLinkToPrevious = false; break;
+ }
+ }
+}
+
class NamedPropertyValue {
OUString m_aName;
public:
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
index 79fc213bc957..90e71f6f70ad 100644
--- a/writerfilter/source/dmapper/PropertyMap.hxx
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -236,12 +236,28 @@ class SectionPropertyMap : public PropertyMap
sal_Int32 m_ndxaLnn;
sal_Int32 m_nLnnMin;
+ // The "Link To Previous" flag indicates whether the header/footer
+ // content should be taken from the previous section
+ bool m_bDefaultHeaderLinkToPrevious;
+ bool m_bEvenPageHeaderLinkToPrevious;
+ bool m_bFirstPageHeaderLinkToPrevious;
+ bool m_bDefaultFooterLinkToPrevious;
+ bool m_bEvenPageFooterLinkToPrevious;
+ bool m_bFirstPageFooterLinkToPrevious;
+
void _ApplyProperties(css::uno::Reference<css::beans::XPropertySet> const& xStyle);
css::uno::Reference<css::text::XTextColumns> ApplyColumnProperties(css::uno::Reference<css::beans::XPropertySet> const& xFollowPageStyle,
DomainMapper_Impl& rDM_Impl);
void CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl );
- static void CopyHeaderFooter(css::uno::Reference<css::beans::XPropertySet> xPrevStyle,
- css::uno::Reference<css::beans::XPropertySet> xStyle);
+ static void CopyHeaderFooter(
+ css::uno::Reference<css::beans::XPropertySet> xPrevStyle,
+ css::uno::Reference<css::beans::XPropertySet> xStyle,
+ bool bOmitRightHeader=false, bool bOmitLeftHeader=false,
+ bool bOmitRightFooter=false, bool bOmitLeftFooter=false);
+ static void CopyHeaderFooterTextProperty(
+ css::uno::Reference<css::beans::XPropertySet> xPrevStyle,
+ css::uno::Reference<css::beans::XPropertySet> xStyle,
+ PropertyIds ePropId );
void PrepareHeaderFooterProperties( bool bFirstPage );
bool HasHeader( bool bFirstPage ) const;
bool HasFooter( bool bFirstPage ) const;
@@ -323,6 +339,7 @@ public:
void CloseSectionGroup( DomainMapper_Impl& rDM_Impl );
/// Handling of margins, header and footer for any kind of sections breaks.
void HandleMarginsHeaderFooter(DomainMapper_Impl& rDM_Impl);
+ void ClearHeaderFooterLinkToPrevious( bool bHeader, PageType eType );
};