[Libreoffice-commits] core.git: sw/qa sw/source writerfilter/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Tue Dec 17 09:17:42 UTC 2019


 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 08f13ab85b5c65b5dc8adfa15918fb3e426fcc3c
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Dec 16 12:58:46 2019 +0100
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Tue Dec 17 10:16:36 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.stahl at cib.de>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
index 537e6d5a148b..11893cd4d6b4 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 c689ec89e9a9..cc38066a118b 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -2211,6 +2211,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();
@@ -2228,7 +2234,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 b938343bb7ef..3efd32d45ad5 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -677,7 +677,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 8780bc1d51fd..97f7cddb7f16 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -932,6 +932,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 00678668845f..1aefd554c402 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)
                 {


More information about the Libreoffice-commits mailing list