diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2014-08-17 21:35:48 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2014-08-17 21:39:39 +0200 |
commit | b32881b6723072c8d1a652ea147d12e75766d504 (patch) | |
tree | f705e8fcb5320201beae7c6bc3031fc81926d54a | |
parent | eacc9e6bad22525e99e243b3fbb2405a00503bd3 (diff) |
fix reading even/odd page breaks from .docx (bnc#519228)
We map Word's even/odd page breaks to Writer's left/right page styles. And we cannot
just set any page style to be left/right, because that could set e.g. the default
page style as such, which would make all normal pages that way. So instead we need
to make a copy of the relevant page style, as the original page style as its follow,
copy all the properties and headers/footers, and use this copy to get the page break.
Change-Id: Id0d2568de91ac2de4afb0ba3a6eedd9cec46f878
-rw-r--r-- | sw/qa/extras/ooxmlimport/data/bnc519228_odd-breaks.docx | bin | 0 -> 14777 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 31 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.cxx | 180 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.hxx | 2 |
4 files changed, 138 insertions, 75 deletions
diff --git a/sw/qa/extras/ooxmlimport/data/bnc519228_odd-breaks.docx b/sw/qa/extras/ooxmlimport/data/bnc519228_odd-breaks.docx Binary files differnew file mode 100644 index 000000000000..8711d62df045 --- /dev/null +++ b/sw/qa/extras/ooxmlimport/data/bnc519228_odd-breaks.docx diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 7c8f13b25133..1b8324330d73 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -54,6 +54,7 @@ #include <com/sun/star/xml/dom/XDocument.hpp> #include <com/sun/star/text/XDocumentIndex.hpp> #include <com/sun/star/style/CaseMap.hpp> +#include <com/sun/star/style/PageStyleLayout.hpp> #include <com/sun/star/style/ParagraphAdjust.hpp> #include <vcl/svapp.hxx> #include <unotools/fltrcfg.hxx> @@ -2333,6 +2334,36 @@ DECLARE_OOXMLIMPORT_TEST(testHidemark, "hidemark.docx") CPPUNIT_ASSERT_EQUAL(text::SizeType::FIX, getProperty<sal_Int16>(xTableRows->getByIndex(1), "SizeType")); } +DECLARE_OOXMLIMPORT_TEST(testBnc519228OddBreaks, "bnc519228_odd-breaks.docx") +{ + // Check that all the normal styles are not set as right-only, those should be only those used after odd page breaks. + uno::Reference<beans::XPropertySet> defaultStyle(getStyles("PageStyles")->getByName(DEFAULT_STYLE), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::makeAny(style::PageStyleLayout_ALL), defaultStyle->getPropertyValue("PageStyleLayout")); + uno::Reference<beans::XPropertySet> firstPage( getStyles("PageStyles")->getByName("First Page"), uno::UNO_QUERY ); + CPPUNIT_ASSERT_EQUAL(uno::makeAny(style::PageStyleLayout_ALL), firstPage->getPropertyValue("PageStyleLayout")); + + OUString page1StyleName = getProperty<OUString>( getParagraph( 1, "This is the first page." ), "PageDescName"); + uno::Reference<beans::XPropertySet> page1Style(getStyles("PageStyles")->getByName(page1StyleName), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::makeAny(style::PageStyleLayout_RIGHT), page1Style->getPropertyValue("PageStyleLayout")); + getParagraphOfText( 1, getProperty< uno::Reference<text::XText> >(page1Style, "HeaderText"), "This is the header for odd pages"); + + // Page2 comes from follow of style for page 1 and should be a normal page. Also check the two page style have the same properties, + // since page style for page1 was created from page style for page 2. + OUString page2StyleName = getProperty<OUString>( getParagraph( 3, "This is page 2, which is obviously an even page." ), "PageDescName"); + CPPUNIT_ASSERT_EQUAL(OUString(), page2StyleName); + page2StyleName = getProperty<OUString>( page1Style, "FollowStyle" ); + uno::Reference<beans::XPropertySet> page2Style(getStyles("PageStyles")->getByName(page2StyleName), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::makeAny(style::PageStyleLayout_ALL), page2Style->getPropertyValue("PageStyleLayout")); + getParagraphOfText( 1, getProperty< uno::Reference<text::XText> >(page2Style, "HeaderTextLeft"), "This is the even header"); + getParagraphOfText( 1, getProperty< uno::Reference<text::XText> >(page2Style, "HeaderTextRight"), "This is the header for odd pages"); + CPPUNIT_ASSERT_EQUAL(getProperty<sal_Int32>(page1Style, "TopMargin"), getProperty<sal_Int32>(page2Style, "TopMargin")); + + OUString page5StyleName = getProperty<OUString>( getParagraph( 5, "Then an odd break after an odd page, should lead us to page #5." ), "PageDescName"); + uno::Reference<beans::XPropertySet> page5Style(getStyles("PageStyles")->getByName(page5StyleName), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::makeAny(style::PageStyleLayout_RIGHT), page5Style->getPropertyValue("PageStyleLayout")); + getParagraphOfText( 1, getProperty< uno::Reference<text::XText> >(page5Style, "HeaderText"), "This is the header for odd pages"); +} + #endif CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index 9a4a953c9816..e774010e5764 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -22,6 +22,7 @@ #include <ConversionHelper.hxx> #include <i18nutil/paper.hxx> #include <rtl/ustring.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> #include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/beans/XMultiPropertySet.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -31,6 +32,7 @@ #include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/style/BreakType.hpp> #include <com/sun/star/style/PageStyleLayout.hpp> +#include <com/sun/star/style/XStyle.hpp> #include <com/sun/star/table/ShadowFormat.hpp> #include <com/sun/star/text/RelOrientation.hpp> #include <com/sun/star/text/WritingMode.hpp> @@ -813,6 +815,74 @@ 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 ) +{ + PropertyNameSupplier& rPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier(); + + 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 sHeaderIsOn = rPropNameSupplier.GetName( PROP_HEADER_IS_ON ); + if (xPrevStyle.is()) + xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader; + if (xStyle.is()) + xStyle->getPropertyValue( sHeaderIsOn ) >>= bHasHeader; + bool bCopyHeader = bHasPrevHeader && !bHasHeader; + + if ( bCopyHeader ) + xStyle->setPropertyValue( sHeaderIsOn, uno::makeAny( sal_True ) ); + + bool bHasPrevFooter = false; + bool bHasFooter = false; + + OUString sFooterIsOn = rPropNameSupplier.GetName( PROP_FOOTER_IS_ON ); + if (xPrevStyle.is()) + xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter; + if (xStyle.is()) + xStyle->getPropertyValue( sFooterIsOn ) >>= bHasFooter; + bool bCopyFooter = bHasPrevFooter && !bHasFooter; + + 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 = rPropNameSupplier.GetName( 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 ); + + uno::Reference< text::XTextCopy > xPrevTxt; + if (xPrevStyle.is()) + xPrevTxt.set(xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW ); + + xTxt->copyText( xPrevTxt ); + } + } + } + catch ( const uno::Exception& e ) + { + SAL_INFO("writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooter( ) - " << e.Message); + } +} + void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl ) { SAL_INFO("writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()"); @@ -827,70 +897,7 @@ void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Imp rDM_Impl.GetPageStyles(), rDM_Impl.GetTextFactory(), bFirstPage ); - - PropertyNameSupplier& rPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier(); - - 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 sHeaderIsOn = rPropNameSupplier.GetName( PROP_HEADER_IS_ON ); - if (xPrevStyle.is()) - xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader; - if (xStyle.is()) - xStyle->getPropertyValue( sHeaderIsOn ) >>= bHasHeader; - bool bCopyHeader = bHasPrevHeader && !bHasHeader; - - if ( bCopyHeader ) - xStyle->setPropertyValue( sHeaderIsOn, uno::makeAny( sal_True ) ); - - bool bHasPrevFooter = false; - bool bHasFooter = false; - - OUString sFooterIsOn = rPropNameSupplier.GetName( PROP_FOOTER_IS_ON ); - if (xPrevStyle.is()) - xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter; - if (xStyle.is()) - xStyle->getPropertyValue( sFooterIsOn ) >>= bHasFooter; - bool bCopyFooter = bHasPrevFooter && !bHasFooter; - - 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 = rPropNameSupplier.GetName( 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 ); - - uno::Reference< text::XTextCopy > xPrevTxt; - if (xPrevStyle.is()) - xPrevTxt.set(xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW ); - - xTxt->copyText( xPrevTxt ); - } - } - } - catch ( const uno::Exception& e ) - { - SAL_INFO("writerfilter", "An exception occurred in SectionPropertyMap::CopyLastHeaderFooter( ) - " << e.Message); - } + CopyHeaderFooter( xPrevStyle, xStyle ); } SAL_INFO("writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()"); } @@ -1059,7 +1066,8 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) } } - //depending on the break type no page styles should be created + // break type : 0 - No break 1 - New Column 2 - New page 3 - Even page 4 - odd page + // depending on the break type no page styles should be created // If the section type is missing, but we have columns, then this should be // handled as a continuous section break. if(m_nBreakType == 0 || (m_nBreakType == -1 && m_nColumnCount > 0)) @@ -1236,22 +1244,44 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) { //now apply this break at the first paragraph of this section uno::Reference<beans::XPropertySet> xRangeProperties(lcl_GetRangeProperties(m_bIsFirstSection, rDM_Impl, m_xStartingRange)); - /* break type - 0 - No break 1 - New Column 2 - New page 3 - Even page 4 - odd page */ + + // Handle page breaks with odd/even page numbering. We need to use an extra page style for setting the page style + // to left/right, because if we set it to the normal style, we'd set it to "First Page"/"Default Style", which would + // break them (all default pages would be only left or right). + if (m_nBreakType == 3 || m_nBreakType == 4) + { + OUString* pageStyle = m_bTitlePage ? &m_sFirstPageStyleName : &m_sFollowPageStyleName; + OUString evenOddStyleName = lcl_FindUnusedPageStyleName(rDM_Impl.GetPageStyles()->getElementNames()); + uno::Reference< beans::XPropertySet > evenOddStyle( + rDM_Impl.GetTextFactory()->createInstance("com.sun.star.style.PageStyle"), + uno::UNO_QUERY); + // Unfortunately using setParent() does not work for page styles, so make a deep copy of the page style. + uno::Reference< beans::XPropertySet > pageProperties( m_bTitlePage ? m_aFirstPageStyle : m_aFollowPageStyle ); + uno::Reference< beans::XPropertySetInfo > pagePropertiesInfo( pageProperties->getPropertySetInfo()); + uno::Sequence< beans::Property > propertyList( pagePropertiesInfo->getProperties()); + for( int i = 0; i < propertyList.getLength(); ++i ) + { + if(( propertyList[i].Attributes & beans::PropertyAttribute::READONLY ) == 0 ) + evenOddStyle->setPropertyValue( propertyList[ i ].Name, pageProperties->getPropertyValue( propertyList[ i ].Name )); + } + evenOddStyle->setPropertyValue("FollowStyle", uno::makeAny(*pageStyle)); + rDM_Impl.GetPageStyles()->insertByName( evenOddStyleName, uno::makeAny( evenOddStyle ) ); + evenOddStyle->setPropertyValue("HeaderIsOn", uno::makeAny(sal_False)); + evenOddStyle->setPropertyValue("FooterIsOn", uno::makeAny(sal_False)); + CopyHeaderFooter( pageProperties, evenOddStyle ); + *pageStyle = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one). + if (m_nBreakType == 3) + evenOddStyle->setPropertyValue(rPropNameSupplier.GetName(PROP_PAGE_STYLE_LAYOUT), uno::makeAny(style::PageStyleLayout_LEFT)); + else if (m_nBreakType == 4) + evenOddStyle->setPropertyValue(rPropNameSupplier.GetName(PROP_PAGE_STYLE_LAYOUT), uno::makeAny(style::PageStyleLayout_RIGHT)); + } + if (xRangeProperties.is() && rDM_Impl.IsNewDoc()) xRangeProperties->setPropertyValue( rPropNameSupplier.GetName( PROP_PAGE_DESC_NAME ), uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName )); - // handle page breaks with odd/even page numbering - style::PageStyleLayout nPageStyleLayout(style::PageStyleLayout_ALL); - if (m_nBreakType == 3) - nPageStyleLayout = style::PageStyleLayout_LEFT; - else if (m_nBreakType == 4) - nPageStyleLayout = style::PageStyleLayout_RIGHT; - if (nPageStyleLayout) - xFollowPageStyle->setPropertyValue(rPropNameSupplier.GetName(PROP_PAGE_STYLE_LAYOUT), uno::makeAny(nPageStyleLayout)); if(m_bPageNoRestart || m_nPageNumber >= 0) { sal_Int16 nPageNumber = m_nPageNumber >= 0 ? static_cast< sal_Int16 >(m_nPageNumber) : 1; diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx index 63e7c2c6a017..5f16df628d9d 100644 --- a/writerfilter/source/dmapper/PropertyMap.hxx +++ b/writerfilter/source/dmapper/PropertyMap.hxx @@ -225,6 +225,8 @@ class SectionPropertyMap : public PropertyMap ::com::sun::star::uno::Reference< com::sun::star::text::XTextColumns > ApplyColumnProperties( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > const& xFollowPageStyle, DomainMapper_Impl& rDM_Impl ); void CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl ); + void CopyHeaderFooter( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xPrevStyle, + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xStyle ); void PrepareHeaderFooterProperties( bool bFirstPage ); bool HasHeader( bool bFirstPage ) const; bool HasFooter( bool bFirstPage ) const; |