Kaydet (Commit) b32881b6 authored tarafından Luboš Luňák's avatar Luboš Luňák

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
üst eacc9e6b
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <com/sun/star/xml/dom/XDocument.hpp> #include <com/sun/star/xml/dom/XDocument.hpp>
#include <com/sun/star/text/XDocumentIndex.hpp> #include <com/sun/star/text/XDocumentIndex.hpp>
#include <com/sun/star/style/CaseMap.hpp> #include <com/sun/star/style/CaseMap.hpp>
#include <com/sun/star/style/PageStyleLayout.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/style/ParagraphAdjust.hpp>
#include <vcl/svapp.hxx> #include <vcl/svapp.hxx>
#include <unotools/fltrcfg.hxx> #include <unotools/fltrcfg.hxx>
...@@ -2333,6 +2334,36 @@ DECLARE_OOXMLIMPORT_TEST(testHidemark, "hidemark.docx") ...@@ -2333,6 +2334,36 @@ DECLARE_OOXMLIMPORT_TEST(testHidemark, "hidemark.docx")
CPPUNIT_ASSERT_EQUAL(text::SizeType::FIX, getProperty<sal_Int16>(xTableRows->getByIndex(1), "SizeType")); 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 #endif
CPPUNIT_PLUGIN_IMPLEMENT(); CPPUNIT_PLUGIN_IMPLEMENT();
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <ConversionHelper.hxx> #include <ConversionHelper.hxx>
#include <i18nutil/paper.hxx> #include <i18nutil/paper.hxx>
#include <rtl/ustring.hxx> #include <rtl/ustring.hxx>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp> #include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp>
...@@ -31,6 +32,7 @@ ...@@ -31,6 +32,7 @@
#include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/style/BreakType.hpp> #include <com/sun/star/style/BreakType.hpp>
#include <com/sun/star/style/PageStyleLayout.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/table/ShadowFormat.hpp>
#include <com/sun/star/text/RelOrientation.hpp> #include <com/sun/star/text/RelOrientation.hpp>
#include <com/sun/star/text/WritingMode.hpp> #include <com/sun/star/text/WritingMode.hpp>
...@@ -813,21 +815,9 @@ bool SectionPropertyMap::HasFooter(bool bFirstPage) const ...@@ -813,21 +815,9 @@ bool SectionPropertyMap::HasFooter(bool bFirstPage) const
#define MIN_HEAD_FOOT_HEIGHT 100 //minimum header/footer height #define MIN_HEAD_FOOT_HEIGHT 100 //minimum header/footer height
void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl ) void SectionPropertyMap::CopyHeaderFooter( uno::Reference< beans::XPropertySet > xPrevStyle,
uno::Reference< beans::XPropertySet > xStyle )
{ {
SAL_INFO("writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()");
SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext( );
if ( pLastContext )
{
uno::Reference< beans::XPropertySet > xPrevStyle = pLastContext->GetPageStyle(
rDM_Impl.GetPageStyles(),
rDM_Impl.GetTextFactory(),
bFirstPage );
uno::Reference< beans::XPropertySet > xStyle = GetPageStyle(
rDM_Impl.GetPageStyles(),
rDM_Impl.GetTextFactory(),
bFirstPage );
PropertyNameSupplier& rPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier(); PropertyNameSupplier& rPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
try { try {
...@@ -889,8 +879,25 @@ void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Imp ...@@ -889,8 +879,25 @@ void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Imp
} }
catch ( const uno::Exception& e ) catch ( const uno::Exception& e )
{ {
SAL_INFO("writerfilter", "An exception occurred in SectionPropertyMap::CopyLastHeaderFooter( ) - " << e.Message); 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()");
SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext( );
if ( pLastContext )
{
uno::Reference< beans::XPropertySet > xPrevStyle = pLastContext->GetPageStyle(
rDM_Impl.GetPageStyles(),
rDM_Impl.GetTextFactory(),
bFirstPage );
uno::Reference< beans::XPropertySet > xStyle = GetPageStyle(
rDM_Impl.GetPageStyles(),
rDM_Impl.GetTextFactory(),
bFirstPage );
CopyHeaderFooter( xPrevStyle, xStyle );
} }
SAL_INFO("writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()"); SAL_INFO("writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()");
} }
...@@ -1059,7 +1066,8 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) ...@@ -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 // If the section type is missing, but we have columns, then this should be
// handled as a continuous section break. // handled as a continuous section break.
if(m_nBreakType == 0 || (m_nBreakType == -1 && m_nColumnCount > 0)) if(m_nBreakType == 0 || (m_nBreakType == -1 && m_nColumnCount > 0))
...@@ -1236,22 +1244,44 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) ...@@ -1236,22 +1244,44 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
{ {
//now apply this break at the first paragraph of this section //now apply this break at the first paragraph of this section
uno::Reference<beans::XPropertySet> xRangeProperties(lcl_GetRangeProperties(m_bIsFirstSection, rDM_Impl, m_xStartingRange)); 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()) if (xRangeProperties.is() && rDM_Impl.IsNewDoc())
xRangeProperties->setPropertyValue( xRangeProperties->setPropertyValue(
rPropNameSupplier.GetName( PROP_PAGE_DESC_NAME ), rPropNameSupplier.GetName( PROP_PAGE_DESC_NAME ),
uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName
: m_sFollowPageStyleName )); : 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) if(m_bPageNoRestart || m_nPageNumber >= 0)
{ {
sal_Int16 nPageNumber = m_nPageNumber >= 0 ? static_cast< sal_Int16 >(m_nPageNumber) : 1; sal_Int16 nPageNumber = m_nPageNumber >= 0 ? static_cast< sal_Int16 >(m_nPageNumber) : 1;
......
...@@ -225,6 +225,8 @@ class SectionPropertyMap : public PropertyMap ...@@ -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::text::XTextColumns > ApplyColumnProperties(
::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > const& xFollowPageStyle, DomainMapper_Impl& rDM_Impl ); ::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 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 ); void PrepareHeaderFooterProperties( bool bFirstPage );
bool HasHeader( bool bFirstPage ) const; bool HasHeader( bool bFirstPage ) const;
bool HasFooter( bool bFirstPage ) const; bool HasFooter( bool bFirstPage ) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment