sw/qa/extras/ooxmlexport/ooxmlexport8.cxx | 12 ++++- sw/source/core/unocore/unotext.cxx | 36 ++++++++++++++- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 5 +- writerfilter/source/dmapper/DomainMapper_Impl.hxx | 5 ++ writerfilter/source/dmapper/PropertyMap.cxx | 52 +++++++++++++++++++--- 5 files changed, 101 insertions(+), 9 deletions(-)
New commits: commit eeb0630b81866edc166f5ee83392b3f885fddc70 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Mon Dec 16 12:58:46 2019 +0100 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Tue Dec 17 12:01:32 2019 +0100 tdf#112202 writerfilter,sw: fix loss of headers There are several problems here: * CloseSectionGroup() is not only called for actual sections in the document but also at the end of every special text like comment, footnote, etc; only actual sections can set page styles. Writer comments use editengine so cannot even contain sections. * With continous section breaks, headers and footers are inherited from the previous section unless defined by the current section; SwXText::copyText() did not copy the content of the header on page 4 to page 5 correctly because it used an SwXTextCursor to create the selection, which cannot select the table at the start of the header. * For continuous section breaks, WW8 import filter has a heuristic to find the first page break in the section and set the PageDescName property on that node to apply the page style with the headers of the new section; do something similar in writerfilter SectionPropertyMap::CloseSectionGroup() Change-Id: I3ebe3d299f83197cbf8f10de46c34de98677626c Reviewed-on: https://gerrit.libreoffice.org/85213 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit 08f13ab85b5c65b5dc8adfa15918fb3e426fcc3c) Reviewed-on: https://gerrit.libreoffice.org/85268 diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx index e5b4ffc9cfdd..88f8610cc0e5 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx @@ -548,7 +548,17 @@ DECLARE_OOXMLEXPORT_TEST(testN780843, "n780843.docx") { uno::Reference< text::XTextRange > xPara = getParagraph(1); OUString aStyleName = getProperty<OUString>(xPara, "PageStyleName"); - CPPUNIT_ASSERT_EQUAL(OUString("First Page"), aStyleName); + // what happens on export here is that the "Default Style" isn't actually + // used on page 2, because of the hard page break with style "Converted2" + // and therefore SwPageDesc::IsFollowNextPageOfNode() returns false and + // "w:titlepg" element is not written + // (the export result is wrong with or without w:titlepg, because the footer + // on the 2nd page should be the text "shown footer") + if (mbExported) + CPPUNIT_ASSERT_EQUAL(OUString("Standard"), aStyleName); + else + CPPUNIT_ASSERT_EQUAL(OUString("First Page"), aStyleName); + //tdf64372 this document should only have one page break (2 pages, not 3) uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx index c9bd3aca8310..316bafa63c6b 100644 --- a/sw/source/core/unocore/unotext.cxx +++ b/sw/source/core/unocore/unotext.cxx @@ -2213,6 +2213,12 @@ SwXText::copyText( { SolarMutexGuard aGuard; + uno::Reference<lang::XUnoTunnel> const xSourceTunnel(xSource, + uno::UNO_QUERY); + SwXText const*const pSource( xSourceTunnel.is() + ? ::sw::UnoTunnelGetImplementation<SwXText>(xSourceTunnel) + : nullptr); + uno::Reference< text::XText > const xText(xSource, uno::UNO_QUERY_THROW); uno::Reference< text::XTextCursor > const xCursor = xText->createTextCursor(); @@ -2230,7 +2236,35 @@ SwXText::copyText( SwNodeIndex rNdIndex( *GetStartNode( ), 1 ); SwPosition rPos( rNdIndex ); - m_pImpl->m_pDoc->getIDocumentContentOperations().CopyRange( *pCursor->GetPaM(), rPos, /*bCopyAll=*/false, /*bCheckPos=*/true ); + // tdf#112202 need SwXText because cursor cannot select table at the start + if (pSource) + { + SwTextNode * pFirstNode; + { + SwPaM temp(*pSource->GetStartNode(), *pSource->GetStartNode()->EndOfSectionNode(), +1, -1); + pFirstNode = temp.GetMark()->nNode.GetNode().GetTextNode(); + if (pFirstNode) + { + pFirstNode->MakeStartIndex(&temp.GetMark()->nContent); + } + if (SwTextNode *const pNode = temp.GetPoint()->nNode.GetNode().GetTextNode()) + { + pNode->MakeEndIndex(&temp.GetPoint()->nContent); + } + m_pImpl->m_pDoc->getIDocumentContentOperations().CopyRange(temp, rPos, /*bCopyAll=*/false, /*bCheckPos=*/true); + } + if (!pFirstNode) + { // the node at rPos was split; get rid of the first empty one so + // that the pasted table is first + auto pDelCursor(m_pImpl->m_pDoc->CreateUnoCursor(SwPosition(SwNodeIndex(*GetStartNode(), 1)))); + m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*pDelCursor); + } + } + else + { + m_pImpl->m_pDoc->getIDocumentContentOperations().CopyRange(*pCursor->GetPaM(), rPos, /*bCopyAll=*/false, /*bCheckPos=*/true); + } + } SwXBodyText::SwXBodyText(SwDoc *const pDoc) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index d88776c63f46..dd4a7a2e599b 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -670,7 +670,10 @@ void DomainMapper_Impl::PopProperties(ContextType eId) if ( eId == CONTEXT_SECTION ) { - m_pLastSectionContext = m_aPropertyStacks[eId].top( ); + if (m_aPropertyStacks[eId].size() == 1) // tdf#112202 only top level !!! + { + m_pLastSectionContext = m_aPropertyStacks[eId].top(); + } } else if (eId == CONTEXT_CHARACTER) { diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 9c0d2cfce854..8352aaa2ae0f 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -936,6 +936,11 @@ public: void SetIsOutsideAParagraph(bool bval) { m_bIsOutsideAParagraph = bval;} void ApplySettingsTable(); + + css::uno::Reference<css::text::XTextAppend> GetCurrentXText() { + return m_aTextAppendStack.empty() ? nullptr : m_aTextAppendStack.top().xTextAppend; + } + SectionPropertyMap * GetSectionContext(); /// If the current paragraph has a numbering style associated, this method returns its character style (part of the numbering rules) css::uno::Reference<css::beans::XPropertySet> GetCurrentNumberingCharStyle(); diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index 3059d7fd9158..66a1eedf9ade 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -1360,12 +1360,13 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) } catch ( const uno::Exception& ) { - OSL_FAIL( "Exception in SectionPropertyMap::CloseSectionGroup" ); + DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup"); } } } - if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous) ) + if (m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous) + && !rDM_Impl.IsInComments()) { //todo: insert a section or access the already inserted section uno::Reference< beans::XPropertySet > xSection = @@ -1385,7 +1386,43 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) OUString aName = m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName; uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) ); if ( m_bIsFirstSection && !aName.isEmpty() && xRangeProperties.is() ) + { xRangeProperties->setPropertyValue( getPropertyName( PROP_PAGE_DESC_NAME ), uno::makeAny( aName ) ); + } + else if ((!m_bFirstPageHeaderLinkToPrevious || + !m_bFirstPageFooterLinkToPrevious || + !m_bDefaultHeaderLinkToPrevious || + !m_bDefaultFooterLinkToPrevious || + !m_bEvenPageHeaderLinkToPrevious || + !m_bEvenPageFooterLinkToPrevious) + && rDM_Impl.GetCurrentXText()) + { // find a node in the section that has a page break and change + // it to apply the page style; see "nightmare scenario" in + // wwSectionManager::InsertSegments() + auto xTextAppend = rDM_Impl.GetCurrentXText(); + uno::Reference<container::XEnumerationAccess> const xCursor( + xTextAppend->createTextCursorByRange( + uno::Reference<text::XTextContent>(xSection, uno::UNO_QUERY_THROW)->getAnchor()), + uno::UNO_QUERY_THROW); + uno::Reference<container::XEnumeration> const xEnum( + xCursor->createEnumeration()); + while (xEnum->hasMoreElements()) + { + uno::Reference<beans::XPropertySet> xElem; + xEnum->nextElement() >>= xElem; + if (xElem->getPropertySetInfo()->hasPropertyByName("BreakType")) + { + style::BreakType bt; + if ((xElem->getPropertyValue("BreakType") >>= bt) + && bt == style::BreakType_PAGE_BEFORE) + { + xElem->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME), + uno::makeAny(aName)); + break; + } + } + } + } } catch ( const uno::Exception& ) { @@ -1395,7 +1432,8 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) // If the section is of type "New column" (0x01), then simply insert a column break. // But only if there actually are columns on the page, otherwise a column break // seems to be handled like a page break by MSO. - else if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_nextColumn) && m_nColumnCount > 0 ) + else if (m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_nextColumn) + && 0 < m_nColumnCount && !rDM_Impl.IsInComments()) { try { @@ -1414,7 +1452,7 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) } catch ( const uno::Exception& ) {} } - else + else if (!rDM_Impl.IsInComments()) { uno::Reference< beans::XPropertySet > xSection; ApplyProtectionProperties( xSection, rDM_Impl ); @@ -1525,7 +1563,7 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) } catch ( const uno::Exception& ) { - OSL_ENSURE( false, "Exception in SectionPropertyMap::CloseSectionGroup" ); + DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup"); } Insert( PROP_GRID_BASE_HEIGHT, uno::makeAny( nGridLinePitch ) ); @@ -1600,11 +1638,13 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) { // Avoid setting page style in case of autotext: so inserting the autotext at the // end of the document does not introduce an unwanted page break. - if (!rDM_Impl.IsReadGlossaries()) + if (!rDM_Impl.IsReadGlossaries() && !rDM_Impl.IsInFootOrEndnote()) + { xRangeProperties->setPropertyValue( getPropertyName( PROP_PAGE_DESC_NAME ), uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName ) ); + } if (0 <= m_nPageNumber) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits