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

László Németh (via logerrit) logerrit at kemper.freedesktop.org
Thu Feb 25 07:42:56 UTC 2021


 sw/inc/IDocumentMarkAccess.hxx            |    3 ++
 sw/qa/extras/odfexport/data/tdf115815.odt |binary
 sw/qa/extras/odfexport/odfexport.cxx      |   39 ++++++++++++++++++++++++++++++
 sw/source/core/doc/docbm.cxx              |   28 +++++++++++++++++++++
 sw/source/core/doc/docredln.cxx           |   29 ++++++++++++++++++++++
 sw/source/core/inc/MarkManager.hxx        |    2 +
 sw/source/filter/xml/swxml.cxx            |    4 +++
 sw/source/filter/xml/wrtxml.cxx           |    4 +++
 8 files changed, 109 insertions(+)

New commits:
commit d325cd0c69b7c0cc4f47105749a98995de81cc9d
Author:     László Németh <nemeth at numbertext.org>
AuthorDate: Wed Feb 24 15:05:38 2021 +0100
Commit:     László Németh <nemeth at numbertext.org>
CommitDate: Thu Feb 25 08:42:13 2021 +0100

    tdf#115815 sw: fix lost annotation ranges of redlines
    
    Annotations of tracked deletions lost their ranges
    during ODF export, according to the limitation of
    ODF or its recent implementation. As a workaround,
    save and restore the start of the annotation ranges
    using temporary bookmarks (which can be part of
    text:deletion).
    
    Note: maybe it's possible to split redline ranges
    regarding to the start of the annotation ranges,
    mixing tracked deletions with normal text or
    tracked insertions, but this would be a not backward
    compatible solution, because the ODF import of this
    file inserts extra (not tracked) spaces around the
    annotation, losing the original text content.
    
    Change-Id: I786993a05ee1683076e213374a92969d1856cf8c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111489
    Tested-by: László Németh <nemeth at numbertext.org>
    Reviewed-by: László Németh <nemeth at numbertext.org>

diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx
index 1ad39701d02b..801ce98ba503 100644
--- a/sw/inc/IDocumentMarkAccess.hxx
+++ b/sw/inc/IDocumentMarkAccess.hxx
@@ -341,6 +341,9 @@ class IDocumentMarkAccess
         virtual sal_Int32 getAnnotationMarksCount() const = 0;
         virtual const_iterator_t findAnnotationMark( const OUString& rName ) const = 0;
         virtual sw::mark::IMark* getAnnotationMarkFor(const SwPosition& rPosition) const = 0;
+        // restore text ranges of annotations of tracked deletions
+        // based on the helper bookmarks (which can survive I/O and hiding redlines)
+        virtual void restoreAnnotationMarks() = 0;
         /** Finds the first mark that is starting after.
 
             @returns
diff --git a/sw/qa/extras/odfexport/data/tdf115815.odt b/sw/qa/extras/odfexport/data/tdf115815.odt
new file mode 100644
index 000000000000..7c2aad0da638
Binary files /dev/null and b/sw/qa/extras/odfexport/data/tdf115815.odt differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index 98712ae76fdc..4e86f035fa92 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -767,6 +767,45 @@ DECLARE_ODFEXPORT_TEST(testFdo60769, "fdo60769.odt")
     }
 }
 
+DECLARE_ODFEXPORT_TEST(testTdf115815, "tdf115815.odt")
+{
+    CPPUNIT_ASSERT_EQUAL(1, getPages());
+    // Test comment range feature on tracked deletion.
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+    uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParaEnum->nextElement(), uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+    bool bAnnotationStart = false;
+    bool bBeforeAnnotation = true;
+    OUString sTextBeforeAnnotation;
+    while (xRunEnum->hasMoreElements())
+    {
+        uno::Reference<beans::XPropertySet> xPropertySet(xRunEnum->nextElement(), uno::UNO_QUERY);
+        OUString aType = getProperty<OUString>(xPropertySet, "TextPortionType");
+        // there is no AnnotationEnd with preceding AnnotationStart,
+        // i.e. annotation with lost range
+        CPPUNIT_ASSERT(aType != "AnnotationEnd" || !bAnnotationStart);
+
+        bAnnotationStart = (aType == "Annotation");
+
+        // collect paragraph text before the first annotation
+        if (bBeforeAnnotation)
+        {
+            if (bAnnotationStart)
+                bBeforeAnnotation = false;
+            else if (aType == "Text")
+            {
+                uno::Reference<text::XTextRange> xRun(xPropertySet, uno::UNO_QUERY);
+                sTextBeforeAnnotation += xRun->getString();
+            }
+        }
+    }
+
+    // This was "Lorem ipsum" (collapsed annotation range)
+    CPPUNIT_ASSERT_EQUAL(OUString("Lorem "), sTextBeforeAnnotation);
+}
+
 DECLARE_ODFEXPORT_TEST(testFdo58949, "fdo58949.docx")
 {
     /*
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index 7adb634b281b..9061e7b853d1 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -1641,6 +1641,34 @@ namespace sw::mark
             CompareIMarkStartsAfter());
     }
 
+    // restore text ranges of annotations of tracked deletions
+    // based on the helper bookmarks (which can survive I/O and hiding redlines)
+    void MarkManager::restoreAnnotationMarks()
+    {
+        for (auto iter = getBookmarksBegin();
+              iter != getBookmarksEnd(); )
+        {
+            const OUString & rBookmarkName = (**iter).GetName();
+            sal_Int32 nPos;
+            if ( rBookmarkName.startsWith("__Annotation__") &&
+                  (nPos = rBookmarkName.indexOf("____")) > -1 )
+            {
+                ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
+                IDocumentMarkAccess::const_iterator_t pMark = findAnnotationMark(rBookmarkName.copy(0, nPos));
+                if ( pMark != getAnnotationMarksEnd() )
+                {
+                    const SwPaM aPam((**iter).GetMarkStart(), (**pMark).GetMarkEnd());
+                    repositionMark(*pMark, aPam);
+                }
+                deleteMark(&**iter);
+                // this invalidates iter, have to start over...
+                iter = getBookmarksBegin();
+            }
+            else
+                ++iter;
+        }
+    }
+
     OUString MarkManager::getUniqueMarkName(const OUString& rName) const
     {
         OSL_ENSURE(rName.getLength(),
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 207ed07dd95c..292600a171d6 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1442,6 +1442,35 @@ void SwRangeRedline::CopyToSection()
         SwNodeIndex aNdIdx( *pSttNd, 1 );
         SwTextNode* pTextNd = aNdIdx.GetNode().GetTextNode();
         SwPosition aPos( aNdIdx, SwIndex( pTextNd ));
+
+        // tdf#115815 keep original start position of collapsed annotation ranges
+        // as temporary bookmarks (removed after file saving and file loading)
+        auto & rDMA(*rDoc.getIDocumentMarkAccess());
+        for (auto iter = rDMA.getAnnotationMarksBegin();
+              iter != rDMA.getAnnotationMarksEnd(); )
+        {
+            SwPosition const& rStartPos((**iter).GetMarkStart());
+            if ( *pStt <= rStartPos && rStartPos < *pEnd )
+            {
+                // at start of redlines use a 1-character length bookmark range
+                // instead of a 0-character length bookmark position to avoid its losing
+                sal_Int32 nLen = (*pStt == rStartPos) ? 1 : 0;
+                SwPaM aPam( rStartPos.nNode, rStartPos.nContent.GetIndex(),
+                                rStartPos.nNode, rStartPos.nContent.GetIndex() + nLen);
+                ::sw::mark::IMark* pMark = rDMA.makeMark(
+                    aPam,
+                    (**iter).GetName() + "____",
+                    IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
+                ::sw::mark::IBookmark* pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pMark);
+                if (pBookmark)
+                {
+                    pBookmark->SetKeyCode(vcl::KeyCode());
+                    pBookmark->SetShortName(OUString());
+                }
+            }
+            ++iter;
+        }
+
         rDoc.getIDocumentContentOperations().CopyRange(*this, aPos, SwCopyFlags::CheckPosInFly);
 
         // Take over the style from the EndNode if needed
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index 11db9719d439..4bc216ff3c7d 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -117,6 +117,8 @@ namespace sw::mark {
 
             typedef std::vector<sw::mark::MarkBase*> container_t;
 
+            virtual void restoreAnnotationMarks() override;
+
         private:
 
             MarkManager(MarkManager const&) = delete;
diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx
index c3d9c50556da..7893321829c6 100644
--- a/sw/source/filter/xml/swxml.cxx
+++ b/sw/source/filter/xml/swxml.cxx
@@ -56,6 +56,7 @@
 #include <docfunc.hxx>
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <DocumentRedlineManager.hxx>
 #include <docary.hxx>
@@ -954,6 +955,9 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con
         }
     }
 
+    // tdf#115815 restore annotation ranges stored in temporary bookmarks
+    rDoc.getIDocumentMarkAccess()->restoreAnnotationMarks();
+
     if (xStatusIndicator.is())
     {
         xStatusIndicator->end();
diff --git a/sw/source/filter/xml/wrtxml.cxx b/sw/source/filter/xml/wrtxml.cxx
index 71445d932f4e..4ae5964a7d2e 100644
--- a/sw/source/filter/xml/wrtxml.cxx
+++ b/sw/source/filter/xml/wrtxml.cxx
@@ -45,6 +45,7 @@
 #include <doc.hxx>
 #include <docfunc.hxx>
 #include <IDocumentRedlineAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
 #include <IDocumentStatistics.hxx>
 #include <IDocumentLayoutAccess.hxx>
 #include <rootfrm.hxx>
@@ -409,6 +410,9 @@ ErrCode SwXMLWriter::Write_( const uno::Reference < task::XStatusIndicator >& xS
     nRedlineFlags |= nOrigRedlineFlags & RedlineFlags::ShowMask;
     m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags( nRedlineFlags );
 
+    // tdf#115815 restore annotation ranges collapsed by hide redlines
+    m_pDoc->getIDocumentMarkAccess()->restoreAnnotationMarks();
+
     if (xStatusIndicator.is())
     {
         xStatusIndicator->end();


More information about the Libreoffice-commits mailing list