[Libreoffice-commits] core.git: Branch 'libreoffice-4-3' - sw/CppunitTest_sw_ooxmlimport.mk sw/qa sw/source writerfilter/source

Luboš Luňák l.lunak at collabora.com
Thu Oct 9 01:03:42 PDT 2014


 sw/CppunitTest_sw_ooxmlimport.mk                  |    1 
 sw/qa/extras/ooxmlimport/data/bnc821804.docx      |binary
 sw/qa/extras/ooxmlimport/ooxmlimport.cxx          |  111 ++++++++++++++++++++++
 sw/source/core/uibase/misc/redlndlg.cxx           |    2 
 sw/source/core/uibase/shells/textfld.cxx          |    1 
 sw/source/core/unocore/unoredline.cxx             |    1 
 writerfilter/source/dmapper/DomainMapper.cxx      |   37 +++----
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |  110 +++++++++++----------
 writerfilter/source/dmapper/DomainMapper_Impl.hxx |   25 +---
 writerfilter/source/dmapper/PropertyMap.hxx       |   18 +++
 writerfilter/source/ooxml/model.xml               |   10 -
 11 files changed, 223 insertions(+), 93 deletions(-)

New commits:
commit c3f4ece4ca8fff2c67504e76bddf89252d75daee
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Wed Oct 1 13:09:36 2014 +0200

    fix docx redline import (bnc#821804)
    
    This is a squash of commits b6969634..fd26de3b.
    
    Change-Id: I8984001d7f85c00eb9b9943b25b8abb6e2ee28d3
    Reviewed-on: https://gerrit.libreoffice.org/11789
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/sw/CppunitTest_sw_ooxmlimport.mk b/sw/CppunitTest_sw_ooxmlimport.mk
index 2c4682b..a77787e 100644
--- a/sw/CppunitTest_sw_ooxmlimport.mk
+++ b/sw/CppunitTest_sw_ooxmlimport.mk
@@ -24,6 +24,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_ooxmlimport, \
     unotest \
     utl \
     sw \
+    tl \
     vcl \
 	$(gb_UWINAPI) \
 ))
diff --git a/sw/qa/extras/ooxmlimport/data/bnc821804.docx b/sw/qa/extras/ooxmlimport/data/bnc821804.docx
new file mode 100644
index 0000000..9ec2e07
Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/bnc821804.docx differ
diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
index 07761dd..900a25e 100644
--- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
+++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
@@ -54,11 +54,13 @@
 #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/util/DateTime.hpp>
 #include <vcl/svapp.hxx>
 #include <unotools/fltrcfg.hxx>
 #include <comphelper/sequenceashashmap.hxx>
 #include <com/sun/star/text/GraphicCrop.hpp>
 #include <swtypes.hxx>
+#include <tools/datetimeutils.hxx>
 
 #include <bordertest.hxx>
 
@@ -2284,6 +2286,115 @@ DECLARE_OOXMLIMPORT_TEST(testBnc891663, "bnc891663.docx")
     CPPUNIT_ASSERT( textNextRowTop >= imageTop + imageHeight );
 }
 
+static OString dateTimeToString( const util::DateTime& dt )
+{
+    return DateTimeToOString( DateTime( Date( dt.Day, dt.Month, dt.Year ), Time( dt.Hours, dt.Minutes, dt.Seconds )));
+}
+
+DECLARE_OOXMLIMPORT_TEST(testBnc821804, "bnc821804.docx")
+{
+    CPPUNIT_ASSERT_EQUAL( OUString( "TITLE" ), getRun( getParagraph( 1 ), 1 )->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(1), 1), "RedlineType"));
+    // Redline information (SwXRedlinePortion) are separate "runs" apparently.
+    CPPUNIT_ASSERT(hasProperty(getRun(getParagraph(1), 2), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(1), 2), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(1), 2), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown1"),getProperty<OUString>(getRun(getParagraph(1), 2), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OString("2006-08-29T09:46:00Z"),dateTimeToString(getProperty<util::DateTime>(getRun(getParagraph(1), 2), "RedlineDateTime")));
+    // So only the 3rd run is actual text (and the two runs have been merged into one, not sure why, but that shouldn't be a problem).
+    CPPUNIT_ASSERT_EQUAL(OUString(" (1st run of an insert) (2nd run of an insert)"), getRun(getParagraph(1),3)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(1), 3), "RedlineType"));
+    // And the end SwXRedlinePortion of the redline.
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(1), 4), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown1"),getProperty<OUString>(getRun(getParagraph(1), 4), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OString("2006-08-29T09:46:00Z"),dateTimeToString(getProperty<util::DateTime>(getRun(getParagraph(1), 4), "RedlineDateTime")));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(1), 4), "IsStart"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Normal text"), getRun(getParagraph(2),1)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(2), 1), "RedlineType"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Delete"),getProperty<OUString>(getRun(getParagraph(3), 1), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown2"),getProperty<OUString>(getRun(getParagraph(3), 1), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OString("2006-08-29T09:47:00Z"),dateTimeToString(getProperty<util::DateTime>(getRun(getParagraph(3), 1), "RedlineDateTime")));
+    CPPUNIT_ASSERT_EQUAL(OUString("Deleted"), getRun(getParagraph(3),2)->getString());
+
+    // This is both inserted and formatted, so there are two SwXRedlinePortion "runs". Given that the redlines overlap and Writer core
+    // doesn't officially expect that (even though it copes, the redline info will be split depending on how Writer deal with it).
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(4), 1), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(4), 1), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("ParagraphFormat"),getProperty<OUString>(getRun(getParagraph(4), 2), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(4), 2), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Inserted and formatted"), getRun(getParagraph(4),3)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(4), 4), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(4), 4), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString(" and this is only formatted"), getRun(getParagraph(4),5)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("ParagraphFormat"),getProperty<OUString>(getRun(getParagraph(4), 6), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(4), 6), "IsStart"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Normal text"), getRun(getParagraph(5),1)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(5), 1), "RedlineType"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Format"),getProperty<OUString>(getRun(getParagraph(6), 1), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(6), 1), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown5"),getProperty<OUString>(getRun(getParagraph(6), 1), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OString("2006-08-29T10:02:00Z"),dateTimeToString(getProperty<util::DateTime>(getRun(getParagraph(6), 1), "RedlineDateTime")));
+    CPPUNIT_ASSERT_EQUAL(OUString("Formatted run"), getRun(getParagraph(6),2)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("Format"),getProperty<OUString>(getRun(getParagraph(6), 3), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(6), 3), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString(" and normal text here "), getRun(getParagraph(6),4)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(6), 4), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(6), 5), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(6), 5), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown6"),getProperty<OUString>(getRun(getParagraph(6), 5), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OString("2006-08-29T09:48:00Z"),dateTimeToString(getProperty<util::DateTime>(getRun(getParagraph(6), 5), "RedlineDateTime")));
+    CPPUNIT_ASSERT_EQUAL(OUString("and inserted again"), getRun(getParagraph(6),6)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(6), 7), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(6), 7), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString(" and normal text again "), getRun(getParagraph(6),8)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(6), 8), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Format"),getProperty<OUString>(getRun(getParagraph(6), 9), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(6), 9), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown7"),getProperty<OUString>(getRun(getParagraph(6), 9), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OUString("and formatted"), getRun(getParagraph(6),10)->getString());
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(6), 11), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString(" and normal."), getRun(getParagraph(6),12)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(6), 12), "RedlineType"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(7), 1), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(7), 1), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown8"),getProperty<OUString>(getRun(getParagraph(7), 1), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OUString("One insert."), getRun(getParagraph(7),2)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(7), 3), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(7), 3), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(7), 4), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(7), 4), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("unknown9"),getProperty<OUString>(getRun(getParagraph(7), 4), "RedlineAuthor"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Second insert."), getRun(getParagraph(7),5)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(7), 6), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(7), 6), "IsStart"));
+
+    // Overlapping again.
+    CPPUNIT_ASSERT_EQUAL(OUString("Delete"),getProperty<OUString>(getRun(getParagraph(8), 1), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(8), 1), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("ParagraphFormat"),getProperty<OUString>(getRun(getParagraph(8), 2), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(8), 2), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Deleted and formatted"), getRun(getParagraph(8),3)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("Delete"),getProperty<OUString>(getRun(getParagraph(8), 4), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(8), 4), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString(" and this is only formatted"), getRun(getParagraph(8),5)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("ParagraphFormat"),getProperty<OUString>(getRun(getParagraph(8), 6), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(8), 6), "IsStart"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Normal text"), getRun(getParagraph(9),1)->getString());
+    CPPUNIT_ASSERT(!hasProperty(getRun(getParagraph(9), 1), "RedlineType"));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("ParagraphFormat"),getProperty<OUString>(getRun(getParagraph(10), 1), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(10), 1), "IsStart"));
+    CPPUNIT_ASSERT_EQUAL(OUString("This is only formatted."), getRun(getParagraph(10),2)->getString());
+    CPPUNIT_ASSERT_EQUAL(OUString("ParagraphFormat"),getProperty<OUString>(getRun(getParagraph(10), 3), "RedlineType"));
+    CPPUNIT_ASSERT_EQUAL(false,getProperty<bool>(getRun(getParagraph(10), 3), "IsStart"));
+}
+
 #endif
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/uibase/misc/redlndlg.cxx b/sw/source/core/uibase/misc/redlndlg.cxx
index d3dc31f..3a062a4 100644
--- a/sw/source/core/uibase/misc/redlndlg.cxx
+++ b/sw/source/core/uibase/misc/redlndlg.cxx
@@ -338,6 +338,7 @@ OUString SwRedlineAcceptDlg::GetActionText(const SwRangeRedline& rRedln, sal_uIn
         case nsRedlineType_t::REDLINE_INSERT:   return sInserted;
         case nsRedlineType_t::REDLINE_DELETE:   return sDeleted;
         case nsRedlineType_t::REDLINE_FORMAT:   return sFormated;
+        case nsRedlineType_t::REDLINE_PARAGRAPH_FORMAT:   return sFormated;
         case nsRedlineType_t::REDLINE_TABLE:    return sTableChgd;
         case nsRedlineType_t::REDLINE_FMTCOLL:  return sFmtCollSet;
         default:;//prevent warning
@@ -1092,6 +1093,7 @@ IMPL_LINK_NOARG(SwRedlineAcceptDlg, CommandHdl)
                             nResId = STR_REDLINE_DELETED;
                             break;
                         case nsRedlineType_t::REDLINE_FORMAT:
+                        case nsRedlineType_t::REDLINE_PARAGRAPH_FORMAT:
                             nResId = STR_REDLINE_FORMATED;
                             break;
                         case nsRedlineType_t::REDLINE_TABLE:
diff --git a/sw/source/core/uibase/shells/textfld.cxx b/sw/source/core/uibase/shells/textfld.cxx
index ce20366..cace5c5 100644
--- a/sw/source/core/uibase/shells/textfld.cxx
+++ b/sw/source/core/uibase/shells/textfld.cxx
@@ -82,6 +82,7 @@ static OUString& lcl_AppendRedlineStr( OUString& rStr, sal_uInt16 nRedlId )
     case nsRedlineType_t::REDLINE_INSERT:   nResId = STR_REDLINE_INSERTED;      break;
     case nsRedlineType_t::REDLINE_DELETE:   nResId = STR_REDLINE_DELETED;       break;
     case nsRedlineType_t::REDLINE_FORMAT:   nResId = STR_REDLINE_FORMATED;      break;
+    case nsRedlineType_t::REDLINE_PARAGRAPH_FORMAT:   nResId = STR_REDLINE_FORMATED;      break;
     case nsRedlineType_t::REDLINE_TABLE:        nResId = STR_REDLINE_TABLECHG;      break;
     case nsRedlineType_t::REDLINE_FMTCOLL:  nResId = STR_REDLINE_FMTCOLLSET;    break;
     }
diff --git a/sw/source/core/unocore/unoredline.cxx b/sw/source/core/unocore/unoredline.cxx
index 314178d..855d11b 100644
--- a/sw/source/core/unocore/unoredline.cxx
+++ b/sw/source/core/unocore/unoredline.cxx
@@ -209,6 +209,7 @@ static OUString lcl_RedlineTypeToOUString(RedlineType_t eType)
         case nsRedlineType_t::REDLINE_INSERT: sRet = "Insert"; break;
         case nsRedlineType_t::REDLINE_DELETE: sRet = "Delete"; break;
         case nsRedlineType_t::REDLINE_FORMAT: sRet = "Format"; break;
+        case nsRedlineType_t::REDLINE_PARAGRAPH_FORMAT: sRet = "ParagraphFormat"; break;
         case nsRedlineType_t::REDLINE_TABLE:  sRet = "TextTable"; break;
         case nsRedlineType_t::REDLINE_FMTCOLL:sRet = "Style"; break;
     }
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index d97f471..90ae6e9 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2169,9 +2169,10 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, PropertyMapPtr rContext )
     }
     break;
     case NS_ooxml::LN_endtrackchange:
-        m_pImpl->RemoveCurrentRedline( );
+        m_pImpl->RemoveTopRedline();
     break;
     case NS_ooxml::LN_CT_RPrChange_rPr:
+    {
         // Push all the current 'Character' properties to the stack, so that we don't store them
         // as 'tracked changes' by mistake
         m_pImpl->PushProperties(CONTEXT_CHARACTER);
@@ -2179,19 +2180,19 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, PropertyMapPtr rContext )
         // Resolve all the properties that are under the 'rPrChange'->'rPr' XML node
         resolveSprmProps(*this, rSprm );
 
-        if (m_pImpl->GetTopContext())
-        {
-            // Get all the properties that were processed in the 'rPrChange'->'rPr' XML node
-            uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
-
-            // Store these properties in the current redline object
-            m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
-        }
+        // Get all the properties that were processed in the 'rPrChange'->'rPr' XML node
+        uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
 
         // Pop back out the character properties that were on the run
         m_pImpl->PopProperties(CONTEXT_CHARACTER);
+
+        // Store these properties in the current redline object (do it after the PopProperties() above, since
+        // otherwise it'd be stored in the content dropped there).
+        m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
+    }
     break;
     case NS_ooxml::LN_CT_PPrChange_pPr:
+    {
         // Push all the current 'Paragraph' properties to the stack, so that we don't store them
         // as 'tracked changes' by mistake
         m_pImpl->PushProperties(CONTEXT_PARAGRAPH);
@@ -2199,17 +2200,16 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, PropertyMapPtr rContext )
         // Resolve all the properties that are under the 'pPrChange'->'pPr' XML node
         resolveSprmProps(*this, rSprm );
 
-        if (m_pImpl->GetTopContext())
-        {
-            // Get all the properties that were processed in the 'pPrChange'->'pPr' XML node
-            uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
-
-            // Store these properties in the current redline object
-            m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
-        }
+        // Get all the properties that were processed in the 'pPrChange'->'pPr' XML node
+        uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
 
         // Pop back out the character properties that were on the run
         m_pImpl->PopProperties(CONTEXT_PARAGRAPH);
+
+        // Store these properties in the current redline object (do it after the PopProperties() above, since
+        // otherwise it'd be stored in the content dropped there).
+        m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
+    }
     break;
     case NS_ooxml::LN_object:
     {
@@ -3288,7 +3288,7 @@ void DomainMapper::HandleRedline( Sprm& rSprm )
 {
     sal_uInt32 nSprmId = rSprm.getId();
 
-    m_pImpl->AddNewRedline( );
+    m_pImpl->AddNewRedline( nSprmId );
 
     if (nSprmId == NS_ooxml::LN_CT_PPr_pPrChange)
     {
@@ -3328,6 +3328,7 @@ void DomainMapper::HandleRedline( Sprm& rSprm )
         default: OSL_FAIL( "redline token other than mod, ins, del or table row" ); break;
     }
     m_pImpl->EndParaMarkerChange( );
+    m_pImpl->SetCurrentRedlineIsRead();
 }
 
 } //namespace dmapper
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 23b976b..ffa4bae 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -1625,7 +1625,7 @@ void DomainMapper_Impl::PushFootOrEndnote( bool bIsFootnote )
     }
 }
 
-void DomainMapper_Impl::CreateRedline( uno::Reference< text::XTextRange > xRange, RedlineParamsPtr& pRedline )
+void DomainMapper_Impl::CreateRedline( uno::Reference< text::XTextRange > xRange, RedlineParamsPtr pRedline )
 {
     if ( pRedline.get( ) )
     {
@@ -1679,21 +1679,25 @@ void DomainMapper_Impl::CheckParaMarkerRedline( uno::Reference< text::XTextRange
 
 void DomainMapper_Impl::CheckRedline( uno::Reference< text::XTextRange > xRange )
 {
-    vector<RedlineParamsPtr>::iterator pIt = m_aRedlines.top().begin( );
-    vector< RedlineParamsPtr > aCleaned;
+    // Writer core "officially" does not like overlapping redlines, and its UNO interface is stupid enough
+    // to not prevent that. However, in practice in fact everything appears to work fine (except for the debug warnings
+    // about redline table corruption, which may possibly be harmless in reality). So leave this as it is, since this
+    // is a better representation of how the changes happened. If this will ever become a problem, overlapping redlines
+    // will need to be merged into one, just like doing the changes in the UI does, which will lose some information
+    // (and so if that happens, it may be better to fix Writer).
+    // Create the redlines here from lowest (formats) to highest (inserts/removals) priority, since the last one is
+    // what Writer presents graphically, so this will show deletes as deleted text and not as just formatted text being there.
+    if( GetTopContextOfType(CONTEXT_PARAGRAPH) != NULL )
+        for( std::vector<RedlineParamsPtr>::const_iterator it = GetTopContextOfType(CONTEXT_PARAGRAPH)->Redlines().begin();
+             it != GetTopContextOfType(CONTEXT_PARAGRAPH)->Redlines().end(); ++it )
+            CreateRedline( xRange, *it );
+    if( GetTopContextOfType(CONTEXT_CHARACTER) != NULL )
+        for( std::vector<RedlineParamsPtr>::const_iterator it = GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().begin();
+             it != GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().end(); ++it )
+            CreateRedline( xRange, *it );
+    std::vector<RedlineParamsPtr>::iterator pIt = m_aRedlines.top().begin( );
     for (; pIt != m_aRedlines.top().end( ); ++pIt )
-    {
         CreateRedline( xRange, *pIt );
-
-        // Adding the non-mod redlines to the temporary vector
-        if ( pIt->get( ) )
-        {
-            if (((*pIt)->m_nToken & 0xffff) != OOXML_mod && ((*pIt)->m_nToken & 0xffff) != OOXML_ParagraphFormat)
-                aCleaned.push_back(*pIt);
-        }
-    }
-
-    m_aRedlines.top().swap( aCleaned );
 }
 
 void DomainMapper_Impl::StartParaMarkerChange( )
@@ -1704,6 +1708,7 @@ void DomainMapper_Impl::StartParaMarkerChange( )
 void DomainMapper_Impl::EndParaMarkerChange( )
 {
     m_bIsParaMarkerChange = false;
+    m_currentRedline.reset();
 }
 
 
@@ -4495,36 +4500,43 @@ bool DomainMapper_Impl::ExecuteFrameConversion()
     return bRet;
 }
 
-void DomainMapper_Impl::AddNewRedline(  )
+void DomainMapper_Impl::AddNewRedline( sal_uInt32 sprmId )
 {
     RedlineParamsPtr pNew( new RedlineParams );
     pNew->m_nToken = OOXML_mod;
     if ( !m_bIsParaMarkerChange )
     {
-        m_aRedlines.top().push_back( pNew );
+        // <w:rPrChange> applies to the whole <w:r>, <w:pPrChange> applies to the whole <w:p>,
+        // so keep those two in CONTEXT_CHARACTERS and CONTEXT_PARAGRAPH, which will take
+        // care of their scope (i.e. when they should be used and discarded).
+        // Let's keep the rest the same way they used to be handled (explictly dropped
+        // from a global stack by endtrackchange), but quite possibly they should not be handled
+        // that way either (I don't know).
+        if( sprmId == NS_ooxml::LN_EG_RPrContent_rPrChange )
+            GetTopContextOfType( CONTEXT_CHARACTER )->Redlines().push_back( pNew );
+        else if( sprmId == NS_ooxml::LN_CT_PPr_pPrChange )
+            GetTopContextOfType( CONTEXT_PARAGRAPH )->Redlines().push_back( pNew );
+        else
+            m_aRedlines.top().push_back( pNew );
     }
     else
     {
-        m_pParaMarkerRedline.swap( pNew );
+        m_pParaMarkerRedline = pNew;
     }
+    // Newly read data will go into this redline.
+    m_currentRedline = pNew;
 }
 
-RedlineParamsPtr DomainMapper_Impl::GetTopRedline(  )
+void DomainMapper_Impl::SetCurrentRedlineIsRead()
 {
-    RedlineParamsPtr pResult;
-    if ( !m_bIsParaMarkerChange && m_aRedlines.top().size(  ) > 0 )
-        pResult = m_aRedlines.top().back(  );
-    else if ( m_bIsParaMarkerChange )
-        pResult = m_pParaMarkerRedline;
-    return pResult;
+    m_currentRedline.reset();
 }
 
 sal_Int32 DomainMapper_Impl::GetCurrentRedlineToken(  )
 {
     sal_Int32 nToken = 0;
-    RedlineParamsPtr pCurrent( GetTopRedline(  ) );
-    if ( pCurrent.get(  ) )
-        nToken = pCurrent->m_nToken;
+    assert( m_currentRedline.get());
+    nToken = m_currentRedline->m_nToken;
     return nToken;
 }
 
@@ -4532,9 +4544,8 @@ void DomainMapper_Impl::SetCurrentRedlineAuthor( const OUString& sAuthor )
 {
     if (!m_xAnnotationField.is())
     {
-        RedlineParamsPtr pCurrent( GetTopRedline(  ) );
-        if ( pCurrent.get(  ) )
-            pCurrent->m_sAuthor = sAuthor;
+        assert( m_currentRedline.get());
+        m_currentRedline->m_sAuthor = sAuthor;
     }
     else
         m_xAnnotationField->setPropertyValue("Author", uno::makeAny(sAuthor));
@@ -4550,9 +4561,8 @@ void DomainMapper_Impl::SetCurrentRedlineDate( const OUString& sDate )
 {
     if (!m_xAnnotationField.is())
     {
-        RedlineParamsPtr pCurrent( GetTopRedline(  ) );
-        if ( pCurrent.get(  ) )
-            pCurrent->m_sDate = sDate;
+        assert( m_currentRedline.get());
+        m_currentRedline->m_sDate = sDate;
     }
     else
         m_xAnnotationField->setPropertyValue("DateTimeValue", uno::makeAny(ConversionHelper::ConvertDateStringToDateTime(sDate)));
@@ -4566,46 +4576,46 @@ void DomainMapper_Impl::SetCurrentRedlineId( sal_Int32 sId )
     }
     else
     {
-        RedlineParamsPtr pCurrent( GetTopRedline(  ) );
-        if ( pCurrent.get(  ) )
-            pCurrent->m_nId = sId;
+        // This should be an assert, but somebody had the smart idea to reuse this function also for comments and whatnot,
+        // and in some cases the id is actually not handled, which may be in fact a bug.
+        SAL_WARN( "writerfilter", !m_currentRedline.get());
+        if( m_currentRedline.get())
+            m_currentRedline->m_nId = sId;
     }
 }
 
 void DomainMapper_Impl::SetCurrentRedlineToken( sal_Int32 nToken )
 {
-    RedlineParamsPtr pCurrent( GetTopRedline(  ) );
-    if ( pCurrent.get(  ) )
-        pCurrent->m_nToken = nToken;
+    assert( m_currentRedline.get());
+    m_currentRedline->m_nToken = nToken;
 }
 
 void DomainMapper_Impl::SetCurrentRedlineRevertProperties( const uno::Sequence<beans::PropertyValue>& aProperties )
 {
-    RedlineParamsPtr pCurrent( GetTopRedline(  ) );
-    if ( pCurrent.get(  ) )
-        pCurrent->m_aRevertProperties = aProperties;
+    assert( m_currentRedline.get());
+    m_currentRedline->m_aRevertProperties = aProperties;
 }
 
 
-void DomainMapper_Impl::RemoveCurrentRedline( )
+// This removes only the last redline stored here, those stored in contexts are automatically removed when
+// the context is destroyed.
+void DomainMapper_Impl::RemoveTopRedline( )
 {
-    if ( m_aRedlines.top().size( ) > 0 )
-    {
-        m_aRedlines.top().pop_back( );
-    }
+    assert( m_aRedlines.top().size( ) > 0 );
+    m_aRedlines.top().pop_back( );
+    m_currentRedline.reset();
 }
 
 void DomainMapper_Impl::ResetParaMarkerRedline( )
 {
     if ( m_pParaMarkerRedline.get( ) )
     {
-        RedlineParamsPtr pEmpty;
-        m_pParaMarkerRedline.swap( pEmpty );
+        m_pParaMarkerRedline.reset();
+        m_currentRedline.reset();
     }
 }
 
 
-
 void DomainMapper_Impl::ApplySettingsTable()
 {
     if (m_pSettingsTable && m_xTextFactory.is())
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 3f62129..e60eab4 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -243,20 +243,6 @@ struct AnnotationPosition
 };
 typedef boost::unordered_map< sal_Int32, AnnotationPosition > AnnotationPositions_t;
 
-struct RedlineParams
-{
-    OUString m_sAuthor;
-    OUString m_sDate;
-    sal_Int32       m_nId;
-    sal_Int32       m_nToken;
-
-    /// This can hold properties of runs that had formatted 'track changes' properties
-    css::uno::Sequence<css::beans::PropertyValue> m_aRevertProperties;
-};
-typedef boost::shared_ptr< RedlineParams > RedlineParamsPtr;
-
-
-
 struct LineNumberSettings
 {
     bool        bIsOn;
@@ -377,6 +363,8 @@ private:
 
     // Redline stack
     std::stack< std::vector< RedlineParamsPtr > > m_aRedlines;
+    // The redline currently read, may be also stored by a context instead of m_aRedlines.
+    RedlineParamsPtr                m_currentRedline;
     RedlineParamsPtr                m_pParaMarkerRedline;
     bool                            m_bIsParaMarkerChange;
 
@@ -449,7 +437,7 @@ public:
     }
     void SetDocumentSettingsProperty( const OUString& rPropName, const css::uno::Any& rValue );
 
-    void CreateRedline( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > xRange, RedlineParamsPtr& pRedline  );
+    void CreateRedline( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > xRange, RedlineParamsPtr pRedline  );
 
     void CheckParaMarkerRedline( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > xRange );
 
@@ -704,9 +692,7 @@ public:
         );
     bool ExecuteFrameConversion();
 
-    void AddNewRedline( );
-
-    RedlineParamsPtr GetTopRedline( );
+    void AddNewRedline( sal_uInt32 sprmId );
 
     sal_Int32 GetCurrentRedlineToken( );
     void SetCurrentRedlineAuthor( const OUString& sAuthor );
@@ -714,7 +700,8 @@ public:
     void SetCurrentRedlineId( sal_Int32 nId );
     void SetCurrentRedlineToken( sal_Int32 nToken );
     void SetCurrentRedlineRevertProperties( const css::uno::Sequence<css::beans::PropertyValue>& aProperties );
-    void RemoveCurrentRedline( );
+    void SetCurrentRedlineIsRead();
+    void RemoveTopRedline( );
     void ResetParaMarkerRedline( );
     void SetCurrentRedlineInitials( const OUString& sInitials );
     bool IsFirstRun() { return m_bIsFirstRun;}
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
index 5c12df2..58487d6 100644
--- a/writerfilter/source/dmapper/PropertyMap.hxx
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -71,6 +71,18 @@ enum GrabBagType
     CHAR_GRAB_BAG
 };
 
+struct RedlineParams
+{
+    OUString m_sAuthor;
+    OUString m_sDate;
+    sal_Int32       m_nId;
+    sal_Int32       m_nToken;
+
+    /// This can hold properties of runs that had formatted 'track changes' properties
+    css::uno::Sequence<css::beans::PropertyValue> m_aRevertProperties;
+};
+typedef boost::shared_ptr< RedlineParams > RedlineParamsPtr;
+
 class PropValue
 {
     css::uno::Any m_aValue;
@@ -101,6 +113,9 @@ class PropertyMap : public _PropertyMap
     OUString                                                             m_sFootnoteFontName;
     ::com::sun::star::uno::Reference< ::com::sun::star::text::XFootnote >       m_xFootnote;
 
+
+    std::vector< RedlineParamsPtr > m_aRedlines;
+
 protected:
     void Invalidate()
     {
@@ -133,6 +148,9 @@ public:
 
     virtual void insertTableProperties( const PropertyMap* );
 
+    const std::vector< RedlineParamsPtr >& Redlines() const { return m_aRedlines; }
+    std::vector< RedlineParamsPtr >& Redlines() { return m_aRedlines; }
+
 #if OSL_DEBUG_LEVEL > 1
     virtual void dumpXml( const TagLogger::Pointer_t pLogger ) const;
 #endif
diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml
index 36a37f6..b3f25af 100644
--- a/writerfilter/source/ooxml/model.xml
+++ b/writerfilter/source/ooxml/model.xml
@@ -24263,19 +24263,16 @@
     </resource>
     <resource name="CT_RPrChange" resource="Properties" tag="character">
       <element name="rPr" tokenid="ooxml:CT_RPrChange_rPr"/>
-      <action name="end" action="tokenproperty"/>
-      <action name="end" action="propagateCharacterPropertiesAsSet" sendtokenid="ooxml:endtrackchange"/>
-      <action name="end" action="clearProps"/>
     </resource>
     <resource name="CT_ParaRPrChange" resource="Properties" tag="character">
       <element name="rPr" tokenid="ooxml:CT_ParaRPrChange_rPr"/>
     </resource>
     <resource name="CT_RunTrackChange" resource="Stream" tag="redlines">
       <action name="start" action="tokenproperty"/>
-      <action name="start" action="propagateCharacterPropertiesAsSet" sendtokenid="ooxml:trackchange"/>
+      <action name="start" action="sendPropertiesWithId" sendtokenid="ooxml:trackchange"/>
       <action name="start" action="clearProps"/>
       <action name="end" action="tokenproperty"/>
-      <action name="end" action="propagateCharacterPropertiesAsSet" sendtokenid="ooxml:endtrackchange"/>
+      <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:endtrackchange"/>
       <action name="end" action="clearProps"/>
     </resource>
     <resource name="EG_RangeMarkupElements" resource="Properties" tag="redlines">
@@ -24479,6 +24476,7 @@
       <element name="checkBox" tokenid="ooxml:CT_FFData_checkBox"/>
       <element name="ddList" tokenid="ooxml:CT_FFData_ddList"/>
       <element name="textInput" tokenid="ooxml:CT_FFData_textInput"/>
+      <!-- TODO: This is possibly wrong and should be sendPropertiesWithId -->
       <action name="end" action="propagateCharacterPropertiesAsSet" sendtokenid="ooxml:ffdata"/>
       <action name="end" action="clearProps"/>
     </resource>
@@ -24934,7 +24932,7 @@
     </resource>
     <resource name="CT_ParaTrackChange" resource="Properties" tag="redline">
       <action name="start" action="tokenproperty"/>
-      <action name="start" action="propagateCharacterPropertiesAsSet" sendtokenid="ooxml:paratrackchange"/>
+      <action name="start" action="sendPropertiesWithId" sendtokenid="ooxml:paratrackchange"/>
       <action name="start" action="clearProps"/>
     </resource>
     <resource name="ST_RubyAlign" resource="List" generated="yes">


More information about the Libreoffice-commits mailing list