sc/qa/uitest/calc_tests7/tdf150044.py                      |  108 +-
 sw/CppunitTest_sw_core_edit.mk                             |   74 +
 sw/CppunitTest_sw_core_text.mk                             |    2 
 sw/Module_sw.mk                                            |    1 
 sw/inc/IDocumentContentOperations.hxx                      |   11 
 sw/inc/crsrsh.hxx                                          |   13 
 sw/inc/editsh.hxx                                          |    4 
 sw/inc/ndarr.hxx                                           |    8 
 sw/inc/ndtxt.hxx                                           |    2 
 sw/inc/unobaseclass.hxx                                    |   19 
 sw/inc/unosett.hxx                                         |    5 
 sw/inc/unotextcursor.hxx                                   |    4 
 sw/inc/unotextrange.hxx                                    |    2 
 sw/qa/core/edit/data/redline-hidden.fodt                   |   32 
 sw/qa/core/edit/edit.cxx                                   |   57 +
 sw/qa/core/text/text.cxx                                   |   51 
 sw/qa/core/uwriter.cxx                                     |    2 
 sw/qa/extras/odfexport/data/tdf137199.docx                 |binary
 sw/qa/extras/odfexport/odfexport.cxx                       |   11 
 sw/qa/extras/uiwriter/data/tdf133982.docx                  |binary
 sw/qa/extras/uiwriter/data/tdf134021.docx                  |binary
 sw/qa/extras/uiwriter/data/tdf139843.odt                   |binary
 sw/qa/extras/uiwriter/data/tdf148868.odt                   |binary
 sw/qa/extras/uiwriter/data2/tdf135061.odt                  |binary
 sw/qa/extras/uiwriter/data2/tdf136452.fodt                 |   80 +
 sw/qa/extras/uiwriter/data2/tdf141175.odt                  |binary
 sw/qa/extras/uiwriter/data2/try2.fodt                      |   66 +
 sw/qa/extras/uiwriter/uiwriter.cxx                         |  262 ++++-
 sw/qa/extras/uiwriter/uiwriter2.cxx                        |  679 +++++++++++++
 sw/qa/extras/unowriter/unowriter.cxx                       |   33 
 sw/qa/extras/ww8export/data/tdf138302_restartNumbering.odt |binary
 sw/qa/extras/ww8export/ww8export3.cxx                      |    6 
 sw/qa/inc/swmodeltestbase.hxx                              |    8 
 sw/qa/uitest/data/tdf39721.fodt                            |   42 
 sw/qa/uitest/writer_tests7/tdf145093.py                    |   34 
 sw/source/core/crsr/crbm.cxx                               |   15 
 sw/source/core/crsr/crsrsh.cxx                             |    9 
 sw/source/core/crsr/crstrvl.cxx                            |   41 
 sw/source/core/doc/DocumentContentOperationsManager.cxx    |  110 +-
 sw/source/core/doc/DocumentRedlineManager.cxx              |    6 
 sw/source/core/doc/docedt.cxx                              |   11 
 sw/source/core/doc/docnew.cxx                              |   27 
 sw/source/core/docnode/ndsect.cxx                          |    2 
 sw/source/core/docnode/ndtbl.cxx                           |    2 
 sw/source/core/docnode/node.cxx                            |    6 
 sw/source/core/docnode/nodes.cxx                           |  182 ++-
 sw/source/core/edit/acorrect.cxx                           |    5 
 sw/source/core/edit/autofmt.cxx                            |   29 
 sw/source/core/edit/edatmisc.cxx                           |    2 
 sw/source/core/edit/eddel.cxx                              |    9 
 sw/source/core/edit/edglbldc.cxx                           |    2 
 sw/source/core/edit/editsh.cxx                             |    4 
 sw/source/core/edit/edlingu.cxx                            |   19 
 sw/source/core/edit/edws.cxx                               |    6 
 sw/source/core/fields/reffld.cxx                           |    4 
 sw/source/core/frmedt/fecopy.cxx                           |    2 
 sw/source/core/inc/DocumentContentOperationsManager.hxx    |    9 
 sw/source/core/inc/UndoDelete.hxx                          |    3 
 sw/source/core/inc/UndoRedline.hxx                         |    8 
 sw/source/core/inc/mvsave.hxx                              |    5 
 sw/source/core/inc/rootfrm.hxx                             |    2 
 sw/source/core/layout/atrfrm.cxx                           |    2 
 sw/source/core/layout/frmtool.cxx                          |   13 
 sw/source/core/layout/tabfrm.cxx                           |    7 
 sw/source/core/text/frmform.cxx                            |   18 
 sw/source/core/text/txtfrm.cxx                             |    1 
 sw/source/core/txtnode/ndtxt.cxx                           |   70 -
 sw/source/core/undo/undel.cxx                              |   27 
 sw/source/core/undo/undobj.cxx                             |   19 
 sw/source/core/undo/unins.cxx                              |    7 
 sw/source/core/undo/unredln.cxx                            |   38 
 sw/source/core/undo/untbl.cxx                              |   14 
 sw/source/core/undo/untblk.cxx                             |    2 
 sw/source/core/unocore/unobkm.cxx                          |    2 
 sw/source/core/unocore/unoobj.cxx                          |   10 
 sw/source/core/unocore/unoobj2.cxx                         |    9 
 sw/source/core/unocore/unosett.cxx                         |   20 
 sw/source/core/unocore/unotext.cxx                         |   22 
 sw/source/filter/ww8/wrtw8num.cxx                          |   11 
 sw/source/filter/ww8/wrtww8.hxx                            |    1 
 sw/source/filter/ww8/ww8atr.cxx                            |    7 
 sw/source/uibase/config/StoredChapterNumbering.cxx         |    2 
 sw/source/uibase/dochdl/swdtflvr.cxx                       |    2 
 sw/source/uibase/docvw/edtwin.cxx                          |   29 
 sw/source/uibase/inc/wrtsh.hxx                             |    3 
 sw/source/uibase/lingu/hhcwrp.cxx                          |    4 
 sw/source/uibase/ribbar/inputwin.cxx                       |    4 
 sw/source/uibase/shells/textfld.cxx                        |    2 
 sw/source/uibase/uitest/uiobject.cxx                       |   25 
 sw/source/uibase/wrtsh/delete.cxx                          |   28 
 sw/source/uibase/wrtsh/select.cxx                          |    4 
 sw/source/uibase/wrtsh/wrtsh1.cxx                          |   20 
 xmloff/source/style/xmlnume.cxx                            |   19 
 93 files changed, 2210 insertions(+), 368 deletions(-)

New commits:
commit 2404401551cb4f07710f9659e975d3573090a27a
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Aug 24 13:26:34 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Aug 24 13:26:34 2022 +0200

    sc: disable 
tdf150044.save_shared_readonly_with_password.test_save_to_shared_ods
    
    Unfortunately can't figure out why it locks up without creating
    xFilePath.
    
    Change-Id: I6b875135e762f4323910664ab98accb68b36c1b6

diff --git a/sc/qa/uitest/calc_tests7/tdf150044.py 
b/sc/qa/uitest/calc_tests7/tdf150044.py
index 6e42358d7b81..e3a400f617da 100644
--- a/sc/qa/uitest/calc_tests7/tdf150044.py
+++ b/sc/qa/uitest/calc_tests7/tdf150044.py
@@ -9,7 +9,6 @@
 from uitest.framework import UITestCase
 from libreoffice.uno.propertyvalue import mkPropertyValues
 from org.libreoffice.unotest import systemPathToFileUrl
-from uitest.uihelper.common import select_by_text
 from tempfile import TemporaryDirectory
 import os.path
 
@@ -17,53 +16,70 @@ class save_shared_readonly_with_password(UITestCase):
 
    def test_save_to_shared_ods(self):
 
+        return # FIXME the test deadlocks after saving the file
         with TemporaryDirectory() as tempdir:
             xFilePath = os.path.join(tempdir, 
"shared_readonly_with_password_tmp.ods")
 
-            with self.ui_test.create_doc_in_start_center("calc"):
-                with 
self.ui_test.execute_dialog_through_command(".uno:ShareDocument", 
close_button="") as xShareDocumentDialog:
-                    xShareCheckButton = xShareDocumentDialog.getChild("share")
-                    xShareCheckButton.executeAction("CLICK", tuple())
-                    xOk = xShareDocumentDialog.getChild("ok")
-                    # Save the document
-                    with self.ui_test.execute_dialog_through_action(xOk, 
"CLICK", close_button="") as xSaveDialog:
-                        xFileName = xSaveDialog.getChild("file_name")
-                        xFileName.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"CTRL+A"}))
-                        xFileName.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"BACKSPACE"}))
-                        xFileName.executeAction("TYPE", 
mkPropertyValues({"TEXT": xFilePath}))
-                        xPasswordCheckButton = xSaveDialog.getChild("password")
-                        xPasswordCheckButton.executeAction("CLICK", tuple())
-                        xOpen = xSaveDialog.getChild("open")
-
-                        with self.ui_test.execute_dialog_through_action(xOpen, 
"CLICK") as xPasswordDialog:
-                            xReadonly = xPasswordDialog.getChild("readonly")
-                            xReadonly.executeAction("CLICK", tuple())
-                            xNewPassword = 
xPasswordDialog.getChild("newpassroEntry")
-                            xNewPassword.executeAction("TYPE", 
mkPropertyValues({"TEXT": "password"}))
-                            xConfirmPassword = 
xPasswordDialog.getChild("confirmropassEntry")
-                            xConfirmPassword.executeAction("TYPE", 
mkPropertyValues({"TEXT": "password"}))
-
-            self.ui_test.wait_until_file_is_available(xFilePath)
-
-            with self.ui_test.execute_dialog_through_command(".uno:Open", 
close_button="") as xOpenDialog:
-                # Open document
-                xFileName = xOpenDialog.getChild("file_name")
-                xFileName.executeAction("TYPE", mkPropertyValues({"TEXT": 
xFilePath}))
-                xOpenBtn = xOpenDialog.getChild("open")
-                xOpenBtn.executeAction("CLICK", tuple())
-
-                xDialog = 
self.ui_test.wait_for_top_focus_window('SharedWarningDialog')
-                xOk = xDialog.getChild("ok")
-                xOk.executeAction("CLICK", tuple())
-
-                document = self.ui_test.get_component()
-                self.assertTrue(document.isReadonly())
-
-                with 
self.ui_test.execute_dialog_through_command(".uno:EditDoc") as xDialog:
-                    # check that we have a password dialog for editing the 
shared document
-                    xPassword = xDialog.getChild("newpassEntry")
-                    xPassword.executeAction("TYPE", mkPropertyValues({"TEXT": 
"password"}))
-
-                self.assertFalse(document.isReadonly())
+            self.ui_test.create_doc_in_start_center("calc")
+
+            self.ui_test.execute_dialog_through_command(".uno:ShareDocument")
+            xShareDocumentDialog = self.xUITest.getTopFocusWindow()
+            xShareCheckButton = xShareDocumentDialog.getChild("share")
+            xShareCheckButton.executeAction("CLICK", tuple())
+            xOk = xShareDocumentDialog.getChild("ok")
+
+            # Save the document
+            self.ui_test.execute_dialog_through_action(xOk, "CLICK")
+            xSaveDialog = self.xUITest.getTopFocusWindow()
+            xFileName = xSaveDialog.getChild("file_name")
+            xFileName.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"CTRL+A"}))
+            xFileName.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"BACKSPACE"}))
+            xFileName.executeAction("TYPE", mkPropertyValues({"TEXT": 
xFilePath}))
+            xPasswordCheckButton = xSaveDialog.getChild("password")
+            xPasswordCheckButton.executeAction("CLICK", tuple())
+            xOpen = xSaveDialog.getChild("open")
+
+            self.ui_test.execute_dialog_through_action(xOpen, "CLICK")
+            xPasswordDialog = self.xUITest.getTopFocusWindow()
+            xReadonly = xPasswordDialog.getChild("readonly")
+            xReadonly.executeAction("CLICK", tuple())
+            xNewPassword = xPasswordDialog.getChild("newpassroEntry")
+            xNewPassword.executeAction("TYPE", mkPropertyValues({"TEXT": 
"password"}))
+            xConfirmPassword = xPasswordDialog.getChild("confirmropassEntry")
+            xConfirmPassword.executeAction("TYPE", mkPropertyValues({"TEXT": 
"password"}))
+
+            xOKButton = xPasswordDialog.getChild("ok")
+            xOKButton.executeAction("CLICK", tuple())
+
+            while True:
+                if not os.path.isfile(xFilePath):
+                    time.sleep(DEFAULT_SLEEP)
+
+            self.ui_test.close_doc()
+
+            self.ui_test.execute_dialog_through_command(".uno:Open")
+            xOpenDialog = self.xUITest.getTopFocusWindow()
+            # Open document
+            xFileName = xOpenDialog.getChild("file_name")
+            xFileName.executeAction("TYPE", mkPropertyValues({"TEXT": 
xFilePath}))
+            xOpenBtn = xOpenDialog.getChild("open")
+            xOpenBtn.executeAction("CLICK", tuple())
+
+            xDialog = 
self.ui_test.wait_for_top_focus_window('SharedWarningDialog')
+            xOk = xDialog.getChild("ok")
+            xOk.executeAction("CLICK", tuple())
+
+            document = self.ui_test.get_component()
+            self.assertTrue(document.isReadonly())
+
+            self.ui_test.execute_dialog_through_command(".uno:EditDoc")
+            xDialog = self.xUITest.getTopFocusWindow()
+            # check that we have a password dialog for editing the shared 
document
+            xPassword = xDialog.getChild("newpassEntry")
+            xPassword.executeAction("TYPE", mkPropertyValues({"TEXT": 
"password"}))
+            xOKButton = xDialog.getChild("ok")
+            xOKButton.executeAction("CLICK", tuple())
+
+            self.assertFalse(document.isReadonly())
 
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
commit 41ec4c4255667089f1f28aa9f29ff2941368e482
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jul 22 19:34:12 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:57:04 2022 +0200

    sw: delete bookmark if paragraph is fully selected
    
    testTdf96479 requires inserting with absorb=true to be treated as
    Replace, and there is of course no string in insertTextContent().
    testDeleteFlyAtCharAtStart requires setString("") to be treated as
    Delete.
    
    Annoyingly this requires API setString() call to be replaced with
    internal call, do this for SwXTextRange and SwXTextCursor which are
    the 2 classes typically used in practice.
    
    Change-Id: I87caa1aa11abe298cdd3d9a9bbb602e547c7b443
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137370
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    Tested-by: Jenkins
    (cherry picked from commit baf8d2c1c16cb3bdc4edad2560f95fea807a034f)

diff --git a/sw/inc/unobaseclass.hxx b/sw/inc/unobaseclass.hxx
index 289d5f0b7ee1..9f7db995de53 100644
--- a/sw/inc/unobaseclass.hxx
+++ b/sw/inc/unobaseclass.hxx
@@ -26,6 +26,9 @@
 
 #include <comphelper/servicehelper.hxx>
 #include <cppuhelper/implbase.hxx>
+
+#include <o3tl/typed_flags_set.hxx>
+
 #include <vcl/svapp.hxx>
 
 class SfxPoolItem;
@@ -54,6 +57,22 @@ enum class CursorType
     Meta,         // meta/meta-field
 };
 
+namespace sw {
+
+enum class DeleteAndInsertMode
+{
+    Default = 0,
+    ForceExpandHints = (1<<0),
+    ForceReplace = (1<<1),
+};
+
+} // namespace sw
+
+namespace o3tl
+{
+    template<> struct typed_flags<::sw::DeleteAndInsertMode> : 
is_typed_flags<::sw::DeleteAndInsertMode, 0x03> {};
+}
+
 /*
     Start/EndAction or Start/EndAllAction
 */
diff --git a/sw/inc/unotextcursor.hxx b/sw/inc/unotextcursor.hxx
index 25cdb7d102d7..4585e79e72ab 100644
--- a/sw/inc/unotextcursor.hxx
+++ b/sw/inc/unotextcursor.hxx
@@ -91,9 +91,7 @@ public:
     SwUnoCursor& GetCursor();
     bool IsAtEndOfMeta() const;
 
-    void DeleteAndInsert(OUString const& rText,
-                const bool bForceExpandHints);
-
+    void DeleteAndInsert(OUString const& rText, ::sw::DeleteAndInsertMode 
eMode);
     // OTextCursorHelper
     virtual const SwPaM*        GetPaM() const override;
     virtual SwPaM*              GetPaM() override;
diff --git a/sw/inc/unotextrange.hxx b/sw/inc/unotextrange.hxx
index 41a69049fc5e..36dc36e643db 100644
--- a/sw/inc/unotextrange.hxx
+++ b/sw/inc/unotextrange.hxx
@@ -101,7 +101,7 @@ private:
     //TODO: new exception type for protected content
     /// @throws css::uno::RuntimeException
     void    DeleteAndInsert(
-                const OUString& rText, const bool bForceExpandHints);
+                const OUString& rText, ::sw::DeleteAndInsertMode eMode);
     void    Invalidate();
 
     virtual ~SwXTextRange() override;
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index cb819d5216c8..bee925546d75 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -1304,6 +1304,7 @@ void SwUndoDelete::RedoImpl(::sw::UndoRedoContext & 
rContext)
         rDoc.getIDocumentContentOperations().DelFullPara( rPam );
     }
     else
+        // FIXME: this ends up calling DeleteBookmarks() on the entire rPam 
which deletes too many!
         rDoc.getIDocumentContentOperations().DeleteAndJoin(rPam, 
m_DeleteFlags);
 }
 
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index d611cb4a496b..098c277d9155 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -1112,7 +1112,12 @@ void SwUndoSaveContent::DelContentIndex( const 
SwPosition& rMark,
                                 && (   type == 
IDocumentMarkAccess::MarkType::TEXT_FIELDMARK
                                     || type == 
IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK
                                     || type == 
IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK
-                                    || type == 
IDocumentMarkAccess::MarkType::DATE_FIELDMARK)))
+                                    || type == 
IDocumentMarkAccess::MarkType::DATE_FIELDMARK))
+                                    || (bMaybe
+                                        && !(nDelContentType & 
DelContentType::Replace)
+                                        && type == 
IDocumentMarkAccess::MarkType::BOOKMARK
+                                        && pStt->nContent == 0 // entire 
paragraph deleted?
+                                        && pEnd->nContent == 
pEnd->nNode.GetNode().GetTextNode()->Len()))
                         {
                             if( bMaybe )
                                 bSavePos = true;
diff --git a/sw/source/core/unocore/unoobj.cxx 
b/sw/source/core/unocore/unoobj.cxx
index 1f8b4d02edfd..e3ac0563be12 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -765,7 +765,7 @@ SwXTextCursor::~SwXTextCursor()
 }
 
 void SwXTextCursor::DeleteAndInsert(const OUString& rText,
-        const bool bForceExpandHints)
+        ::sw::DeleteAndInsertMode const eMode)
 {
     auto pUnoCursor = static_cast<SwCursor*>(m_pImpl->m_pUnoCursor.get());
     if (pUnoCursor)
@@ -780,13 +780,15 @@ void SwXTextCursor::DeleteAndInsert(const OUString& rText,
         {
             if (pCurrent->HasMark())
             {
-                pDoc->getIDocumentContentOperations().DeleteAndJoin(*pCurrent);
+                pDoc->getIDocumentContentOperations().DeleteAndJoin(*pCurrent,
+                    // is it "delete" or "replace"?
+                    (nTextLen != 0 || eMode & 
::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : 
SwDeleteFlags::Default);
             }
             if(nTextLen)
             {
                 const bool bSuccess(
                     SwUnoCursorHelper::DocInsertStringSplitCR(
-                        *pDoc, *pCurrent, rText, bForceExpandHints ) );
+                        *pDoc, *pCurrent, rText, bool(eMode & 
::sw::DeleteAndInsertMode::ForceExpandHints)) );
                 OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." );
 
                 SwUnoCursorHelper::SelectPam(*pUnoCursor, true);
@@ -1754,7 +1756,7 @@ SwXTextCursor::setString(const OUString& aString)
     const bool bForceExpandHints( (CursorType::Meta == m_pImpl->m_eType)
         && dynamic_cast<SwXMeta*>(m_pImpl->m_xParentText.get())
                 ->CheckForOwnMemberMeta(*GetPaM(), true) );
-    DeleteAndInsert(aString, bForceExpandHints);
+    DeleteAndInsert(aString, bForceExpandHints ? 
::sw::DeleteAndInsertMode::ForceExpandHints : 
::sw::DeleteAndInsertMode::Default);
 }
 
 uno::Any SwUnoCursorHelper::GetPropertyValue(
diff --git a/sw/source/core/unocore/unoobj2.cxx 
b/sw/source/core/unocore/unoobj2.cxx
index 502e2e74c2dd..62180c0bc230 100644
--- a/sw/source/core/unocore/unoobj2.cxx
+++ b/sw/source/core/unocore/unoobj2.cxx
@@ -791,7 +791,7 @@ void SwXTextRange::SetPositions(const SwPaM& rPam)
 }
 
 void SwXTextRange::DeleteAndInsert(
-        const OUString& rText, const bool bForceExpandHints)
+        const OUString& rText, ::sw::DeleteAndInsertMode const eMode)
 {
     if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition)
     {
@@ -807,13 +807,14 @@ void SwXTextRange::DeleteAndInsert(
         m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, 
nullptr);
         if (aCursor.HasMark())
         {
-            
m_pImpl->m_rDoc.getIDocumentContentOperations().DeleteAndJoin(aCursor);
+            
m_pImpl->m_rDoc.getIDocumentContentOperations().DeleteAndJoin(aCursor,
+                (!rText.isEmpty() || eMode & 
::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : 
SwDeleteFlags::Default);
         }
 
         if (!rText.isEmpty())
         {
             SwUnoCursorHelper::DocInsertStringSplitCR(
-                    m_pImpl->m_rDoc, aCursor, rText, bForceExpandHints);
+                m_pImpl->m_rDoc, aCursor, rText, bool(eMode & 
::sw::DeleteAndInsertMode::ForceExpandHints));
 
             SwUnoCursorHelper::SelectPam(aCursor, true);
             aCursor.Left(rText.getLength());
@@ -961,7 +962,7 @@ void SAL_CALL SwXTextRange::setString(const OUString& 
rString)
 {
     SolarMutexGuard aGuard;
 
-    DeleteAndInsert(rString, false);
+    DeleteAndInsert(rString, ::sw::DeleteAndInsertMode::Default);
 }
 
 bool SwXTextRange::GetPositions(SwPaM& rToFill) const
diff --git a/sw/source/core/unocore/unotext.cxx 
b/sw/source/core/unocore/unotext.cxx
index a4dfe5422af1..a8f91620622c 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -364,7 +364,8 @@ SwXText::insertString(const uno::Reference< 
text::XTextRange >& xTextRange,
                 dynamic_cast<SwXTextCursor*>(pCursor) );
             if (pTextCursor)
             {
-                pTextCursor->DeleteAndInsert(rString, bForceExpandHints);
+                pTextCursor->DeleteAndInsert(rString, 
::sw::DeleteAndInsertMode::ForceReplace
+                    | (bForceExpandHints ? 
::sw::DeleteAndInsertMode::ForceExpandHints : 
::sw::DeleteAndInsertMode::Default));
             }
             else
             {
@@ -373,7 +374,8 @@ SwXText::insertString(const uno::Reference< 
text::XTextRange >& xTextRange,
         }
         else
         {
-            pRange->DeleteAndInsert(rString, bForceExpandHints);
+            pRange->DeleteAndInsert(rString, 
::sw::DeleteAndInsertMode::ForceReplace
+                | (bForceExpandHints ? 
::sw::DeleteAndInsertMode::ForceExpandHints : 
::sw::DeleteAndInsertMode::Default));
         }
     }
     else
@@ -605,7 +607,21 @@ SwXText::insertTextContent(
 
     if (bAbsorb && !bAttribute)
     {
-        xRange->setString(OUString());
+        uno::Reference<lang::XUnoTunnel> const xRangeTunnel(xRange, 
uno::UNO_QUERY);
+        if (SwXTextRange *const pRange = 
::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel))
+        {
+            pRange->DeleteAndInsert(OUString(), 
::sw::DeleteAndInsertMode::ForceReplace
+                | (bForceExpandHints ? 
::sw::DeleteAndInsertMode::ForceExpandHints : 
::sw::DeleteAndInsertMode::Default));
+        }
+        else if (SwXTextCursor *const pCursor = 
dynamic_cast<SwXTextCursor*>(::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel)))
+        {
+            pCursor->DeleteAndInsert(OUString(), 
::sw::DeleteAndInsertMode::ForceReplace
+                | (bForceExpandHints ? 
::sw::DeleteAndInsertMode::ForceExpandHints : 
::sw::DeleteAndInsertMode::Default));
+        }
+        else
+        {
+            xRange->setString(OUString());
+        }
     }
     uno::Reference< text::XTextRange > xTempRange =
         (bAttribute && bAbsorb) ? xRange : xRange->getStart();
commit c17bcef73f17d022352d410e841e510e75d88cc0
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Mon Aug 8 16:15:36 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:32:35 2022 +0200

    sw: fix infinite recursion in SwEditWin::GetSurroundingTextSelection()
    
    The unexpected problem of calling SwCursorShell::Pop() from there ending
    up calling the function itself again, with gtk3 UI, on loading
    forum-mso-en-4034.docx and clicking somewhere or scrolling:
    
    466 SwEditWin::GetSurroundingTextSelection() const at 
sw/source/uibase/docvw/edtwin.cxx:6656
    467 ImplHandleSurroundingTextRequest(vcl::Window*, rtl::OUString&, 
Selection&) at vcl/source/window/winproc.cxx:2487
    468 ImplHandleSalSurroundingTextRequest(vcl::Window*, 
SalSurroundingTextRequestEvent*) at vcl/source/window/winproc.cxx:2497
    469 ImplWindowFrameProc(vcl::Window*, SalEvent, void const*) at 
vcl/source/window/winproc.cxx:2826
    470 SalFrame::CallCallback(SalEvent, void const*) const at 
vcl/inc/salframe.hxx:306
    471 GtkSalFrame::IMHandler::signalIMRetrieveSurrounding(_GtkIMContext*, 
void*) at vcl/unx/gtk3/gtkframe.cxx:5707
    472 _gtk_marshal_BOOLEAN__VOIDv () at /lib64/libgtk-3.so.0
    473 g_signal_emit_valist () at /lib64/libgobject-2.0.so.0
    474 g_signal_emit_by_name () at /lib64/libgobject-2.0.so.0
    475 gtk_im_multicontext_retrieve_surrounding_cb () at /lib64/libgtk-3.so.0
    476 _gtk_marshal_BOOLEAN__VOIDv () at /lib64/libgtk-3.so.0
    477 g_signal_emit_valist () at /lib64/libgobject-2.0.so.0
    478 g_signal_emit_by_name () at /lib64/libgobject-2.0.so.0
    479 enable () at /lib64/libgtk-3.so.0
    480 GtkSalFrame::IMHandler::createIMContext() at 
vcl/unx/gtk3/gtkframe.cxx:5187
    481 GtkSalFrame::IMHandler::IMHandler(GtkSalFrame*) at 
vcl/unx/gtk3/gtkframe.cxx:5153
    482 GtkSalFrame::SetInputContext(SalInputContext*) at 
vcl/unx/gtk3/gtkframe.cxx:2711
    483 vcl::Window::ImplNewInputContext() () at 
vcl/source/window/window.cxx:1781
    484 vcl::Window::SetInputContext(InputContext const&) at 
vcl/source/window/window.cxx:2083
    485 SwView::CheckReadonlySelection() at sw/source/uibase/uiview/view.cxx:699
    486 SwView::AttrChangedNotify(LinkParamNone*) at 
sw/source/uibase/uiview/view.cxx:510
    487 SwView::LinkStubAttrChangedNotify(void*, LinkParamNone*) at 
sw/source/uibase/uiview/view.cxx:499
    488 Link<LinkParamNone*, void>::Call(LinkParamNone*) const at 
include/tools/link.hxx:111
    489 SwCursorShell::CallChgLnk() at sw/source/core/crsr/crsrsh.cxx:2544
    490 SwCallLink::~SwCallLink() at sw/source/core/crsr/callnk.cxx:149
    491 SwCursorShell::Pop(SwCursorShell::PopMode) at 
sw/source/core/crsr/crsrsh.cxx:2327
    492 SwWrtShell::Pop(SwCursorShell::PopMode) at 
sw/source/uibase/wrtsh/wrtsh1.cxx:2016
    493 SwEditWin::GetSurroundingTextSelection() const at 
sw/source/uibase/docvw/edtwin.cxx:6656
    
    This SwCallLink looks unnecessary here, but it's triggered because it
    compares the state before Pop() to the state after Pop(), instead of the
    state before Push() to the state after Pop().
    
    This problem could probably benefit from being solved more generally,
    but with 2 functions involved it gets rather ugly as it can't easily be
    encapsulated in SwCursorShell.
    
    (probably regression from aac9bd235e65b27faf63e64bba3ecd94837381d6)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137987
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 581ba395222e04e43697484bef9181c877d1fd61)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138027
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit d7a427d9c869729c21285df7c32106f934f66a04)
    
    Change-Id: Ief176b54daf96da378d2e5d57f3dd5b4a0817299

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 4a9d8dc2497d..3a5d395733e8 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -45,6 +45,7 @@
 
 class SfxItemSet;
 class SfxPoolItem;
+class SwCallLink;
 class SwContentFrame;
 class SwUnoCursor;
 class SwFormatField;
@@ -437,6 +438,7 @@ public:
      *      stack
      *  @return <true> if there was one on the stack, <false> otherwise
      */
+    bool Pop(PopMode, ::std::unique_ptr<SwCallLink> pLink);
     bool Pop(PopMode);
     /*
      * Combine 2 Cursors.
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index fce0ca5219c2..f7ddd3a3f1d7 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -2243,7 +2243,14 @@ void SwCursorShell::Push()
 */
 bool SwCursorShell::Pop(PopMode const eDelete)
 {
-    SwCallLink aLk( *this ); // watch Cursor-Moves; call Link if needed
+    ::std::unique_ptr<SwCallLink> 
pLink(::std::make_unique<SwCallLink>(*this)); // watch Cursor-Moves; call Link 
if needed
+    return Pop(eDelete, ::std::move(pLink));
+}
+
+bool SwCursorShell::Pop(PopMode const eDelete,
+        [[maybe_unused]] ::std::unique_ptr<SwCallLink> const pLink)
+{
+    assert(pLink); // parameter exists only to be deleted before return
 
     // are there any left?
     if (nullptr == m_pStackCursor)
diff --git a/sw/source/uibase/docvw/edtwin.cxx 
b/sw/source/uibase/docvw/edtwin.cxx
index 9dfcf20f7c83..08bfd444b27b 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -163,6 +163,9 @@
 #include <sfx2/event.hxx>
 #include <memory>
 
+#include "../../core/crsr/callnk.hxx"
+
+
 using namespace sw::mark;
 using namespace ::com::sun::star;
 
@@ -6318,13 +6321,15 @@ Selection SwEditWin::GetSurroundingTextSelection() const
         // around the visible cursor.
         TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
 
+        // store shell state *before* Push
+        ::std::unique_ptr<SwCallLink> 
pLink(::std::make_unique<SwCallLink>(rSh));
         rSh.Push();
 
         rSh.HideCursor();
         rSh.GoStartSentence();
         TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
 
-        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
+        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, ::std::move(pLink));
         rSh.ShowCursor();
 
         return Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - 
nStartPos));
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index bf6e9d961a13..7a653bf55490 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -140,6 +140,7 @@ public:
         // is there a text- or frameselection?
     bool    HasSelection() const { return SwCursorShell::HasSelection() ||
                                         IsMultiSelection() || IsSelFrameMode() 
|| IsObjSelected(); }
+    bool    Pop(SwCursorShell::PopMode, ::std::unique_ptr<SwCallLink> const 
pLink);
     bool    Pop(SwCursorShell::PopMode = SwCursorShell::PopMode::DeleteStack);
 
     void    EnterStdMode();
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx 
b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 53e8ae7a2fbd..c240c630df3a 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -118,6 +118,9 @@
 #include <comphelper/lok.hxx>
 #include <memory>
 
+#include "../../core/crsr/callnk.hxx"
+
+
 using namespace sw::mark;
 using namespace com::sun::star;
 namespace {
@@ -1730,7 +1733,13 @@ SwWrtShell::~SwWrtShell()
 
 bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
 {
-    bool bRet = SwCursorShell::Pop(eDelete);
+    ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(*this));
+    return Pop(eDelete, ::std::move(pLink));
+}
+
+bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, 
::std::unique_ptr<SwCallLink> pLink)
+{
+    bool bRet = SwCursorShell::Pop(eDelete, ::std::move(pLink));
     if( bRet && IsSelection() )
     {
         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
commit 1f7143a45bd7ec89d16055879bf3f34b1b1e6cf3
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Mar 4 21:53:38 2022 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:31:54 2022 +0200

    sw_redlinehide: more issues with SwEditWin Surrounding functions
    
    .. and SwEditWinUIObject.
    
    These need to work with TextFrameIndex.  Add some functions to
    SwCursorShell to make it possible.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131042
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 112592ac580108998a2cd99ae9bbf376c80c10d8)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131109
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 26830d91d2f2a2d50f989fa3f36d18d55ea0eafd)
    
    Change-Id: I884c4822a0e7ecf254ea09a893762e1e6d539534
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131625
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 189fd3ba5061..4a9d8dc2497d 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -26,6 +26,9 @@
 #include <vcl/keycod.hxx>
 #include <o3tl/typed_flags_set.hxx>
 
+#ifdef SW_DLLIMPLEMENTATION
+#include <TextFrameIndex.hxx>
+#endif
 #include "IShellCursorSupplier.hxx"
 #include "swdllapi.h"
 #include "docary.hxx"
@@ -792,8 +795,12 @@ public:
     bool GotoINetAttr( const SwTextINetFormat& rAttr );
     const SwFormatINetFormat* FindINetAttr( const OUString& rName ) const;
 
-    bool SelectText( const sal_Int32 nStart,
-                        const sal_Int32 nEnd );
+    bool SelectTextModel(sal_Int32 nStart, sal_Int32 nEnd);
+#ifdef SW_DLLIMPLEMENTATION
+    bool SelectTextView(TextFrameIndex nStart, TextFrameIndex nEnd);
+    // result is only valid while cursor isn't moved!
+    TextFrameIndex GetCursorPointAsViewIndex() const;
+#endif
 
     bool CheckTableBoxContent( const SwPosition* pPos = nullptr );
     void SaveTableBoxContent( const SwPosition* pPos = nullptr );
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx 
b/sw/qa/extras/uiwriter/uiwriter.cxx
index 79a1026e38b3..1e0b5b46114e 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -3825,7 +3825,7 @@ void SwUiWriterTest::testUndoDelAsCharTdf107512()
     CPPUNIT_ASSERT(rIDCO.InsertGraphicObject(*pShell->GetCursor(), grf, 
&frameSet, &grfSet));
     CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetFlyCount(FLYCNTTYPE_GRF));
     SvxCharHiddenItem hidden(true, RES_CHRATR_HIDDEN);
-    pShell->SelectText(1, 4);
+    pShell->SelectTextModel(1, 4);
     rIDCO.InsertPoolItem(*pShell->GetCursor(), hidden);
     // now we have "\1foo\1" with the "foo" hidden
     
CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0,
 RES_TXTATR_FLYCNT));
@@ -3839,7 +3839,7 @@ void SwUiWriterTest::testUndoDelAsCharTdf107512()
     query.ClearItem(RES_CHRATR_HIDDEN);
 
     // delete from the start
-    pShell->SelectText(0, 4);
+    pShell->SelectTextModel(0, 4);
     rIDCO.DeleteAndJoin(*pShell->GetCursor());
     
CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0,
 RES_TXTATR_FLYCNT));
     CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF));
@@ -3882,7 +3882,7 @@ void SwUiWriterTest::testUndoDelAsCharTdf107512()
     query.ClearItem(RES_CHRATR_HIDDEN);
 
     // delete from the end
-    pShell->SelectText(1, 5);
+    pShell->SelectTextModel(1, 5);
     rIDCO.DeleteAndJoin(*pShell->GetCursor());
     
CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0,
 RES_TXTATR_FLYCNT));
     CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF));
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 9153b8b34e85..11fb5db02df6 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -1930,7 +1930,7 @@ bool SwContentAtPos::IsInRTLText()const
     return bRet;
 }
 
-bool SwCursorShell::SelectText( const sal_Int32 nStart,
+bool SwCursorShell::SelectTextModel( const sal_Int32 nStart,
                                  const sal_Int32 nEnd )
 {
     SET_CURR_SHELL( this );
@@ -1954,6 +1954,43 @@ bool SwCursorShell::SelectText( const sal_Int32 nStart,
     return bRet;
 }
 
+TextFrameIndex SwCursorShell::GetCursorPointAsViewIndex() const
+{
+    SwPosition const*const pPos(GetCursor()->GetPoint());
+    SwTextNode const*const pTextNode(pPos->nNode.GetNode().GetTextNode());
+    assert(pTextNode);
+    SwTextFrame const*const pFrame(static_cast<SwTextFrame 
const*>(pTextNode->getLayoutFrame(GetLayout())));
+    assert(pFrame);
+    return pFrame->MapModelToViewPos(*pPos);
+}
+
+bool SwCursorShell::SelectTextView(TextFrameIndex const nStart,
+                                 TextFrameIndex const nEnd)
+{
+    CurrShell aCurr( this );
+    bool bRet = false;
+
+    SwCallLink aLk( *this );
+    SwCursorSaveState aSaveState( *m_pCurrentCursor );
+
+    SwPosition& rPos = *m_pCurrentCursor->GetPoint();
+    m_pCurrentCursor->DeleteMark();
+    // indexes must correspond to cursor point!
+    SwTextFrame const*const pFrame(static_cast<SwTextFrame 
const*>(m_pCurrentCursor->GetPoint()->nNode.GetNode().GetTextNode()->getLayoutFrame(GetLayout())));
+    assert(pFrame);
+    rPos = pFrame->MapViewToModelPos(nStart);
+    m_pCurrentCursor->SetMark();
+    rPos = pFrame->MapViewToModelPos(nEnd);
+
+    if (!m_pCurrentCursor->IsSelOvr())
+    {
+        UpdateCursor();
+        bRet = true;
+    }
+
+    return bRet;
+}
+
 bool SwCursorShell::SelectTextAttr( sal_uInt16 nWhich,
                                      bool bExpand,
                                      const SwTextAttr* pTextAttr )
@@ -1977,7 +2014,7 @@ bool SwCursorShell::SelectTextAttr( sal_uInt16 nWhich,
         if( pTextAttr )
         {
             const sal_Int32* pEnd = pTextAttr->End();
-            bRet = SelectText( pTextAttr->GetStart(), ( pEnd ? *pEnd : 
pTextAttr->GetStart() + 1 ) );
+            bRet = SelectTextModel(pTextAttr->GetStart(), (pEnd ? *pEnd : 
pTextAttr->GetStart() + 1));
         }
     }
     return bRet;
diff --git a/sw/source/uibase/docvw/edtwin.cxx 
b/sw/source/uibase/docvw/edtwin.cxx
index 12c0519ed9d8..9dfcf20f7c83 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -3700,7 +3700,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
                     // select content of Input Field, but exclude 
CH_TXT_ATR_INPUTFIELDSTART
                     // and CH_TXT_ATR_INPUTFIELDEND
                     rSh.SttSelect();
-                    rSh.SelectText( aFieldAtPos.pFndTextAttr->GetStart() + 1,
+                    rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() 
+ 1,
                                  *(aFieldAtPos.pFndTextAttr->End()) - 1 );
                 }
                 // don't reset here any longer so that, in case through 
MouseMove
@@ -3730,8 +3730,8 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
             // select content of Input Field, but exclude 
CH_TXT_ATR_INPUTFIELDSTART
             // and CH_TXT_ATR_INPUTFIELDEND
             rSh.SttSelect();
-            rSh.SelectText( aFieldAtPos.pFndTextAttr->GetStart() + 1,
-                         *(aFieldAtPos.pFndTextAttr->End()) - 1 );
+            rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
+                            *(aFieldAtPos.pFndTextAttr->End()) - 1 );
         }
     }
 
@@ -6316,18 +6316,18 @@ Selection SwEditWin::GetSurroundingTextSelection() const
     {
         // Return the position of the visible cursor in the sentence
         // around the visible cursor.
-        SwPosition *pPos = rSh.GetCursor()->GetPoint();
-        const sal_Int32 nPos = pPos->nContent.GetIndex();
+        TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
+
         rSh.Push();
 
         rSh.HideCursor();
         rSh.GoStartSentence();
-        const sal_Int32 nStartPos = 
rSh.GetCursor()->GetPoint()->nContent.GetIndex();
+        TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
 
         rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
         rSh.ShowCursor();
 
-        return Selection( nPos - nStartPos, nPos - nStartPos );
+        return Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - 
nStartPos));
     }
 }
 
diff --git a/sw/source/uibase/shells/textfld.cxx 
b/sw/source/uibase/shells/textfld.cxx
index c65d5d65da6a..072a38ab81b5 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -199,7 +199,7 @@ void SwTextShell::ExecField(SfxRequest &rReq)
                                
SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), true))))
                     {
                         rSh.SttSelect();
-                        rSh.SelectText(
+                        rSh.SelectTextModel(
                             SwCursorShell::StartOfInputFieldAtPos( 
*(rSh.GetCursor()->Start()) ) + 1,
                             SwCursorShell::EndOfInputFieldAtPos( 
*(rSh.GetCursor()->Start()) ) - 1 );
                     }
diff --git a/sw/source/uibase/uitest/uiobject.cxx 
b/sw/source/uibase/uitest/uiobject.cxx
index ecdfd68ad6a8..f44f2b5a70fb 100644
--- a/sw/source/uibase/uitest/uiobject.cxx
+++ b/sw/source/uibase/uitest/uiobject.cxx
@@ -13,6 +13,7 @@
 #include <view.hxx>
 #include <wrtsh.hxx>
 #include <navipi.hxx>
+#include <ndtxt.hxx>
 #include <sfx2/sidebar/Sidebar.hxx>
 #include <sfx2/viewfrm.hxx>
 
@@ -89,14 +90,30 @@ void SwEditWinUIObject::execute(const OUString& rAction,
         {
             auto itr = rParameters.find("START_POS");
             OUString aStartPos = itr->second;
-            sal_Int32 nStartPos = aStartPos.toInt32();
+            TextFrameIndex const nStartPos(aStartPos.toInt32());
 
             itr = rParameters.find("END_POS");
             assert(itr != rParameters.end());
             OUString aEndPos = itr->second;
-            sal_Int32 nEndPos = aEndPos.toInt32();
-
-            getWrtShell(mxEditWin).SelectText(nStartPos, nEndPos);
+            TextFrameIndex const nEndPos(aEndPos.toInt32());
+
+            auto & shell = getWrtShell(mxEditWin);
+            if (shell.GetCursor_()->GetPoint()->nNode.GetNode().GetTextNode())
+            {
+                shell.Push();
+                shell.MovePara(GoCurrPara, fnParaEnd);
+                TextFrameIndex const len(shell.GetCursorPointAsViewIndex());
+                shell.Pop(SwCursorShell::PopMode::DeleteCurrent);
+                SAL_WARN_IF(
+                    sal_Int32(nStartPos) < 0 || nStartPos > len || 
sal_Int32(nEndPos) < 0 || nEndPos > len, "sw.ui",
+                    "SELECT START/END_POS " << sal_Int32(nStartPos) << ".." << 
sal_Int32(nEndPos) << " outside 0.." << sal_Int32(len));
+                shell.SelectTextView(
+                    std::clamp(nStartPos, TextFrameIndex(0), len), 
std::clamp(nEndPos, TextFrameIndex(0), len));
+            }
+            else
+            {
+                SAL_WARN("sw.ui", "SELECT without SwTextNode");
+            }
         }
     }
     else if (rAction == "SIDEBAR")
commit 6538e62b4aee3df747dd47a8ce77b86537d9783c
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Mar 4 20:05:03 2022 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:31:47 2022 +0200

    sw_redlinehide: fix crashes in SwEditWin Surrounding functions
    
    These foolish functions write into the shell cursor!
    
    But the shell cursor's node isn't necessarily the same as before with
    merged paragraphs, so could crash with out of bounds indexes.
    
    Better use Push()/Pop().
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131041
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit aac9bd235e65b27faf63e64bba3ecd94837381d6)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131127
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 08690fe5c4e5028ccaebc80145be650caf62ea76)
    
    Change-Id: I4fd0e2aa915b6c5448772a2c766848607bbf5aaa
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131624
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/source/uibase/docvw/edtwin.cxx 
b/sw/source/uibase/docvw/edtwin.cxx
index 20f5761f1361..12c0519ed9d8 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -6287,8 +6287,7 @@ OUString SwEditWin::GetSurroundingText() const
         rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
     else if( !rSh.HasSelection() )
     {
-        SwPosition *pPos = rSh.GetCursor()->GetPoint();
-        const sal_Int32 nPos = pPos->nContent.GetIndex();
+        rSh.Push();
 
         // get the sentence around the cursor
         rSh.HideCursor();
@@ -6297,8 +6296,7 @@ OUString SwEditWin::GetSurroundingText() const
         rSh.GoEndSentence();
         rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
 
-        pPos->nContent = nPos;
-        rSh.ClearMark();
+        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
         rSh.HideCursor();
     }
 
@@ -6320,13 +6318,13 @@ Selection SwEditWin::GetSurroundingTextSelection() const
         // around the visible cursor.
         SwPosition *pPos = rSh.GetCursor()->GetPoint();
         const sal_Int32 nPos = pPos->nContent.GetIndex();
+        rSh.Push();
 
         rSh.HideCursor();
         rSh.GoStartSentence();
         const sal_Int32 nStartPos = 
rSh.GetCursor()->GetPoint()->nContent.GetIndex();
 
-        pPos->nContent = nPos;
-        rSh.ClearMark();
+        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
         rSh.ShowCursor();
 
         return Selection( nPos - nStartPos, nPos - nStartPos );
commit 7b7c622f544237a4a60c2a97b4a2c2fbef204ad1
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Jul 27 16:06:05 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:19:55 2022 +0200

    sw: SolarMutexGuard missing in SwXBookmark::setPropertyValue()
    
    Change-Id: I41187b02e6b0545529e2a2c5b07da671eae89079
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137506
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    Tested-by: Jenkins
    (cherry picked from commit c7a76952b6fa0e6688028047726ac794fdd5cca3)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137519
    Tested-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/core/unocore/unobkm.cxx 
b/sw/source/core/unocore/unobkm.cxx
index ddeaccf1966b..a4d719016f68 100644
--- a/sw/source/core/unocore/unobkm.cxx
+++ b/sw/source/core/unocore/unobkm.cxx
@@ -410,6 +410,8 @@ void SAL_CALL
 SwXBookmark::setPropertyValue(const OUString& PropertyName,
         const uno::Any& rValue)
 {
+    SolarMutexGuard g;
+
     if (PropertyName == UNO_NAME_BOOKMARK_HIDDEN)
     {
         bool bNewValue = false;
commit a4ea1f361288086e1137ac91e05fefa7317bd023
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Jun 15 15:06:59 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:16:38 2022 +0200

    tdf#135976 sw: preserve flys on backspace/delete with redlining enabled
    
    This is a continuation of commit 85376a02348810812d515ee72140dbf56f2b6040
    for the case when redlining is turned on.
    
    Also try to restore the anchors in SwUndoRedlineDelete.
    
    (regression from commit 3345feb67f2c49a1b76639965b56968e1c5f03ee)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135909
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 932a8efce878547bfd81521d0cf1ddfe8dc33ec6)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135968
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 03834f003c56e6646e3b274c418acd4fc344fd8e)
    
    sw: fix odd m_bCanGroup check in SwUndoRedlineDelete
    
    This looks like copypasta, presumably both flags must be true to allow
    grouping.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135908
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit f31f11f3222933dbc96dc672e6fa52233cda12be)
    
    Change-Id: I4199f5755398d469a606618c037ad9756cb7aeba
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136223
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index 284deb537640..f2a358d46b25 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -28,6 +28,7 @@
 #include <wrtsh.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <flyfrm.hxx>
+#include <pagefrm.hxx>
 #include <fmtanchr.hxx>
 #include <UndoManager.hxx>
 #include <sortedobjs.hxx>
@@ -958,6 +959,100 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf139982)
     CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf135976)
+{
+    SwDoc* const pDoc = createDoc();
+    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    pWrtShell->Insert("foobar");
+
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, 
/*bBasicCall=*/false);
+    SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+    anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+    SfxItemSet flySet(pDoc->GetAttrPool(), svl::Items<RES_ANCHOR, 
RES_ANCHOR>{});
+    flySet.Put(anchor);
+    SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, 
/*bAnchValid=*/true);
+    CPPUNIT_ASSERT(pFly != nullptr);
+
+    // turn on redlining and show changes
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | 
RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+    lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+    CPPUNIT_ASSERT_MESSAGE(
+        "redlines should be visible",
+        
IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->UnSelectFrame();
+    pWrtShell->SttEndDoc(/*bStart=*/false);
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+
+    pWrtShell->DelLeft();
+    pWrtShell->DelLeft();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    // the problem was that the fly was deleted from the layout
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    // check that the anchor was moved outside the redline
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    // check that the anchor was restored
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Redo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    // now again in the other direction:
+
+    pWrtShell->SttEndDoc(/*bStart=*/false);
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 3, 
/*bBasicCall=*/false);
+
+    pWrtShell->DelRight();
+    pWrtShell->DelRight();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    // the problem was that the fly was deleted from the layout
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Redo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf54819)
 {
     load(DATA_DIRECTORY, "tdf54819.fodt");
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index b6dc4158b936..315cf5cdeefa 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3915,7 +3915,7 @@ 
DocumentContentOperationsManager::~DocumentContentOperationsManager()
 }
 //Private methods
 
-bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & 
rPam, SwDeleteFlags const /*flags*/, const bool)
+bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & 
rPam, SwDeleteFlags const flags, const bool)
 {
     assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn());
 
@@ -3995,7 +3995,7 @@ bool 
DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & rPam
         {
             assert(pRedline->HasValidRange());
             undos.emplace_back(std::make_unique<SwUndoRedlineDelete>(
-                        *pRedline, SwUndoId::DELETE));
+                        *pRedline, SwUndoId::DELETE, flags));
         }
         const SwRewriter aRewriter = undos.front()->GetRewriter();
         // can only group a single undo action
diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index 398b5ae1a065..d6072b4b3725 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -28,6 +28,7 @@
 #include <mdiexp.hxx>
 #include <mvsave.hxx>
 #include <redline.hxx>
+#include <rolbck.hxx>
 #include <rootfrm.hxx>
 #include <splargs.hxx>
 #include <swcrsr.hxx>
@@ -130,7 +131,7 @@ void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& 
rArr )
 }
 
 void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
-                       SaveFlyArr& rArr, bool bMoveAllFlys )
+        SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory *const pHistory)
 {
     SwFrameFormats& rFormats = 
*rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrameFormats();
     SwFrameFormat* pFormat;
@@ -176,6 +177,10 @@ void SaveFlyInRange( const SwPaM& rPam, const SwPosition& 
rInsPos,
                     || (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
                             && (bInsPos = (rInsPos == *pAPos))))
             {
+                if (pHistory)
+                {
+                    pHistory->AddChangeFlyAnchor(*pFormat);
+                }
                 SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
                     (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())
                         ? (pAPos->nNode == rSttNdIdx)
diff --git a/sw/source/core/inc/UndoRedline.hxx 
b/sw/source/core/inc/UndoRedline.hxx
index 38ecd86314cb..ada3c34fad7f 100644
--- a/sw/source/core/inc/UndoRedline.hxx
+++ b/sw/source/core/inc/UndoRedline.hxx
@@ -22,6 +22,7 @@
 
 #include <memory>
 #include <undobj.hxx>
+#include <IDocumentContentOperations.hxx>
 
 struct SwSortOptions;
 class SwRangeRedline;
@@ -52,17 +53,22 @@ public:
 
 class SwUndoRedlineDelete : public SwUndoRedline
 {
+private:
+    std::unique_ptr<SwHistory> m_pHistory; ///< for moved fly anchors
+                                           //
     bool bCanGroup : 1;
     bool bIsDelim : 1;
     bool bIsBackspace : 1;
 
     OUString m_sRedlineText;
 
+    void InitHistory(SwPaM const& rRange);
+
     virtual void UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
     virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
 
 public:
-    SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUserId );
+    SwUndoRedlineDelete(const SwPaM& rRange, SwUndoId nUserId, SwDeleteFlags 
flags = SwDeleteFlags::Default);
     virtual SwRewriter GetRewriter() const override;
 
     bool CanGrouping( const SwUndoRedlineDelete& rPrev );
diff --git a/sw/source/core/inc/mvsave.hxx b/sw/source/core/inc/mvsave.hxx
index d6cde5520ecb..5b84b5e10819 100644
--- a/sw/source/core/inc/mvsave.hxx
+++ b/sw/source/core/inc/mvsave.hxx
@@ -34,6 +34,7 @@ class SwDoc;
 class SwFormatAnchor;
 class SwFrameFormat;
 class SwIndex;
+class SwHistory;
 class SwNodeIndex;
 class SwNodeRange;
 class SwPaM;
@@ -119,7 +120,7 @@ void RestFlyInRange( SaveFlyArr& rArr, const SwPosition& 
rSttIdx,
                      const SwNodeIndex* pInsPos, bool isForceToStartPos = 
false);
 void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& rArr );
 void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
-                       SaveFlyArr& rArr, bool bMoveAllFlys );
+        SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory * pHistory = nullptr);
 
 void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
                     const SwNodeIndex& rPtNdIdx,
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index 117a7992ff50..c66d8eed133e 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -26,6 +26,8 @@
 #include <pam.hxx>
 #include <ndtxt.hxx>
 #include <txtfrm.hxx>
+#include <mvsave.hxx>
+#include <rolbck.hxx>
 #include <UndoCore.hxx>
 #include <UndoDelete.hxx>
 #include <strings.hrc>
@@ -153,7 +155,8 @@ void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & 
rPam)
     rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, 
RedlineType::Any);
 }
 
-SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId 
)
+SwUndoRedlineDelete::SwUndoRedlineDelete(
+        const SwPaM& rRange, SwUndoId const nUsrId, SwDeleteFlags const flags)
     : SwUndoRedline( nUsrId != SwUndoId::EMPTY ? nUsrId : SwUndoId::DELETE, 
rRange ),
     bCanGroup( false ), bIsDelim( false ), bIsBackspace( false )
 {
@@ -174,6 +177,24 @@ SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& 
rRange, SwUndoId nUsrId )
     }
 
     m_bCacheComment = false;
+    if (flags & SwDeleteFlags::ArtificialSelection)
+    {
+        InitHistory(rRange);
+    }
+}
+
+void SwUndoRedlineDelete::InitHistory(SwPaM const& rRedline)
+{
+    m_pHistory.reset(new SwHistory);
+    // try to rely on direction of rPam here so it works for
+    // backspacing/deleting consecutive characters
+    SaveFlyArr flys;
+    SaveFlyInRange(rRedline, *rRedline.GetMark(), flys, false, 
m_pHistory.get());
+    RestFlyInRange(flys, *rRedline.GetPoint(), &rRedline.GetPoint()->nNode, 
true);
+    if (m_pHistory->Count())
+    {
+        bCanGroup = false; // how to group history?
+    }
 }
 
 // bit of a hack, replace everything...
@@ -197,12 +218,21 @@ void SwUndoRedlineDelete::SetRedlineText(const OUString & 
rText)
 void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
     rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, 
RedlineType::Any);
+    if (m_pHistory)
+    {
+        m_pHistory->TmpRollback(&rDoc, 0);
+    }
 }
 
 void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
     if (rPam.GetPoint() != rPam.GetMark())
     {
+        if (m_pHistory) // if it was created before, it must be recreated now
+        {
+            rPam.Normalize(bIsBackspace); // to check the correct edge
+            InitHistory(rPam);
+        }
         rDoc.getIDocumentRedlineAccess().AppendRedline( new 
SwRangeRedline(*mpRedlData, rPam), false );
     }
     sw::UpdateFramesForAddDeleteRedline(rDoc, rPam);
@@ -212,7 +242,7 @@ bool SwUndoRedlineDelete::CanGrouping( const 
SwUndoRedlineDelete& rNext )
 {
     bool bRet = false;
     if( SwUndoId::DELETE == mnUserId && mnUserId == rNext.mnUserId &&
-        bCanGroup == rNext.bCanGroup &&
+        bCanGroup && rNext.bCanGroup &&
         bIsDelim == rNext.bIsDelim &&
         bIsBackspace == rNext.bIsBackspace &&
         m_nSttNode == m_nEndNode &&
commit e4d6b7b76a399c462ffd3dbf8efe8bab713bdbf6
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jun 14 17:19:23 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:16:08 2022 +0200

    sw_redlinehide: skip unnecessary updates when undoing redlined delete
    
    When reproducing tdf#135976 and then Undo, an UAF crash happens here:
    
      assert(!pFrame->GetDrawObjs() || !pObjs->Contains(*pObj));
    
    The pObjs was actually deleted and then re-created, because the pObj was
    removed from the frame and added again to the same frame.
    
    This is a bit unexpected, so prevent it by taking a shortcut in the
    caller UpdateFramesForRemoveDeleteRedline() to insert a check that had
    been removed in commit 14e87a4b15d31a34e6053f6194688f3aa23af991.
    
    If the rPam is inside a single node, the sw::RedlineUnDelText hint that
    was sent to the SwTextFrame should be sufficient to update it and the
    rest of the code in the loop that deals with newly split paragraph can
    be skipped.
    
    Change-Id: I5f36eb91bc20003887ee0bad03ea4a6e67135de9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135907
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit cf9a16caf5012d65b2a45a5525e36e40585dd35c)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135892
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 918f435d48de3f29814f187c8621c1a564c5b835)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136222
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index 8ae32f266bdb..e11c1c6f2c4b 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -283,6 +283,12 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, 
SwPaM const& rPam)
                 break;
             }
 
+            // no nodes can be unmerged by this - skip MakeFrames() etc.
+            if (rPam.GetPoint()->nNode == rPam.GetMark()->nNode)
+            {
+                break; // continue with AppendAllObjs()
+            }
+
             // first, call CheckParaRedlineMerge on the first paragraph,
             // to init flag on new merge range (if any) + 1st node post the 
merge
             auto eMode(sw::FrameMode::Existing);
commit 8fa5f170f206793b9a6c98ea04df554fe422d186
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jun 10 18:25:05 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:15:19 2022 +0200

    tdf#148868 sw: handle selection then Insert similar to Replace
    
    ... if the selection is inside one paragraph, to avoid deleting flys
    anchored in the selection.
    
    From a code point of view it's a bit inconsistent to do this, but
    from user point of view there are some ways to conveniently create
    a selection such as by double clicking a word.
    
    (see also tdf#133957)
    
    Also in SwWrtShell::AutoCorrect(), which oddly enough might get called
    with a selection from textsh*.cxx, at least in theory.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135606
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit d72bee64a97650507d042f17846b6fc427b8434c)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135839
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit 67eec140556edb42280def88e987448aaa221c5e)
    
    tdf#148868: sw_uiwriter3: Add unittest
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135827
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit 4e8295638e68295d73b49ddb80e23c3509a49b3e)
    
    Change-Id: I8cf9459e5a7ec7754ce8fe323cd158c7e84a5c93
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136221
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/extras/uiwriter/data/tdf148868.odt 
b/sw/qa/extras/uiwriter/data/tdf148868.odt
new file mode 100644
index 000000000000..7ebf68a82ea3
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/tdf148868.odt differ
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx 
b/sw/qa/extras/uiwriter/uiwriter.cxx
index 355fa17b3fff..79a1026e38b3 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -7754,6 +7754,25 @@ void SwUiWriterTest::testTdf38394()
     CPPUNIT_ASSERT_EQUAL(sReplaced, 
static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf148868)
+{
+    SwDoc* pDoc = createDoc("tdf148868.odt");
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    CPPUNIT_ASSERT_EQUAL(1, getShapes());
+    CPPUNIT_ASSERT_EQUAL(1, getPages());
+
+    pWrtShell->EndPg(/*bSelect=*/false);
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 5, 
/*bBasicCall=*/false);
+    pWrtShell->Insert("X");
+
+    // Without the fix in place, this test would have failed with
+    // - Expected: 1
+    // - Actual  : 0
+    CPPUNIT_ASSERT_EQUAL(1, getShapes());
+    CPPUNIT_ASSERT_EQUAL(1, getPages());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf134021)
 {
     load(DATA_DIRECTORY, "tdf134021.docx");
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 6ec17d5b0e78..bf6e9d961a13 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -279,7 +279,7 @@ typedef bool (SwWrtShell:: *FNSimpleMove)();
     bool    DelLeft();
 
     // also deletes the frame or sets the cursor in the frame when bDelFrame 
== false
-    bool    DelRight();
+    bool    DelRight(bool isReplaceHeuristic = false);
     void    DelToEndOfPara();
     void    DelToStartOfPara();
     bool    DelToEndOfSentence();
diff --git a/sw/source/uibase/wrtsh/delete.cxx 
b/sw/source/uibase/wrtsh/delete.cxx
index b71d1b112404..0a8a46d344ac 100644
--- a/sw/source/uibase/wrtsh/delete.cxx
+++ b/sw/source/uibase/wrtsh/delete.cxx
@@ -288,7 +288,7 @@ bool SwWrtShell::DelLeft()
     return bRet;
 }
 
-bool SwWrtShell::DelRight()
+bool SwWrtShell::DelRight(bool const isReplaceHeuristic)
 {
         // Will be or'ed, if a tableselection exists;
         // will here be implemented on SelectionType::Table
@@ -315,7 +315,7 @@ bool SwWrtShell::DelRight()
                 {
                     SwActContext aActContext(this);
                     ResetCursorStack();
-                    Delete(false);
+                    Delete(isReplaceHeuristic);
                     UpdateAttr();
                 }
                 if( IsBlockMode() )
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx 
b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 0840ed3cd407..53e8ae7a2fbd 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -244,7 +244,8 @@ void SwWrtShell::Insert( const OUString &rStr )
         StartUndo(SwUndoId::REPLACE, &aRewriter);
         bStarted = true;
         Push();
-        bDeleted = DelRight();
+        // let's interpret a selection within the same node as "replace"
+        bDeleted = DelRight(GetCursor()->GetPoint()->nNode == 
GetCursor()->GetMark()->nNode);
         Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore selection (if 
tracking changes)
         NormalizePam(false); // tdf#127635 put point at the end of deletion
         ClearMark();
@@ -1667,7 +1668,7 @@ void SwWrtShell::AutoCorrect( SvxAutoCorrect& rACorr, 
sal_Unicode cChar )
 
             StartUndo( SwUndoId::REPLACE, &aRewriter );
             bStarted = true;
-            DelRight();
+            DelRight(true);
         }
         SwEditShell::AutoCorrect( rACorr, IsInsMode(), cChar );
 
commit f85a5b4d5cafc80e01e2891cb1427ee94abe1d41
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jun 10 16:26:40 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:14:49 2022 +0200

    tdf#139982 sw: preserve flys in Replace with redlining enabled
    
    The problem is that there isn't a redline type "Replace" so it's
    represented as Delete+Insert.
    
    To prevent the flys anchored in the text from being deleted, move the
    anchors to the point between the old (deleted) and new (inserted) text.
    
    (regression from commit 28b77c89dfcafae82cf2a6d85731b643ff9290e5)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135604
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 646c6ddd91a98afddf914e3889cb269fc814c060)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135737
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit b7ab83bd96c70932c2223c8d0b3bc0f24327cef2)
    
    Change-Id: Ib600c9dbfb9421917e4b8d61195c48cf0b364f06
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136220
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index f742288bf2db..284deb537640 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -908,6 +908,56 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf140007)
                          
pDoc->GetNodes()[SwNodeOffset(11)]->GetTextNode()->GetText());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf139982)
+{
+    SwDoc* const pDoc = createDoc();
+    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    // turn on redlining and show changes
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | 
RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+    CPPUNIT_ASSERT_MESSAGE(
+        "redlines should be visible",
+        
IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+
+    pWrtShell->Insert("helloo");
+
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    {
+        SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+        anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+        SfxItemSet flySet(pDoc->GetAttrPool(), svl::Items<RES_ANCHOR, 
RES_ANCHOR>{});
+        flySet.Put(anchor);
+        SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, 
/*bAnchValid=*/true);
+        CPPUNIT_ASSERT(pFly != nullptr);
+    }
+
+    pWrtShell->SttEndDoc(true);
+    pWrtShell->EndPara(/*bSelect=*/true);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Replace("hello", true);
+
+    // the problem was that a redline delete with the same author as redline
+    // insert has its text deleted immediately, including anchored flys.
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf54819)
 {
     load(DATA_DIRECTORY, "tdf54819.fodt");
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 2db40c2e5d57..b6dc4158b936 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -4421,6 +4421,14 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( 
SwPaM& rPam, const OUSt
                 InsertItemSet( aTmpRange, aSet );
             }
 
+            // tdf#139982: Appending the redline may immediately delete flys
+            // anchored in the previous text if it's inside an insert redline.
+            // Also flys will be deleted if the redline is accepted. Move them
+            // to the position between the previous text and the new text,
+            // there the chance of surviving both accept and reject is best.
+            SaveFlyArr flys;
+            SaveFlyInRange(aDelPam, *aDelPam.End(), flys, false);
+
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
@@ -4431,6 +4439,7 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( 
SwPaM& rPam, const OUSt
             pCursor->SetMark();
             *pCursor->GetPoint() = *aDelPam.GetPoint();
             m_rDoc.getIDocumentRedlineAccess().AppendRedline( new 
SwRangeRedline( RedlineType::Delete, aDelPam ), true);
+            RestFlyInRange(flys, *aDelPam.End(), &aDelPam.End()->nNode, true);
             sw::UpdateFramesForAddDeleteRedline(m_rDoc, *pCursor);
 
             *rPam.GetMark() = *aDelPam.GetMark();
diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index 1b93a7a56a78..398b5ae1a065 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -48,7 +48,7 @@ using namespace ::com::sun::star::i18n;
 
 
 void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& rStartPos,
-                      const SwNodeIndex* pInsertPos )
+                      const SwNodeIndex* pInsertPos, bool const 
isForceToStartPos)
 {
     SwPosition aPos(rStartPos);
     for(const SaveFly & rSave : rArr)
@@ -57,7 +57,7 @@ void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& 
rStartPos,
         SwFrameFormat* pFormat = rSave.pFrameFormat;
         SwFormatAnchor aAnchor( pFormat->GetAnchor() );
 
-        if (rSave.isAtInsertNode)
+        if (rSave.isAtInsertNode || isForceToStartPos)
         {
             if( pInsertPos != nullptr )
             {
diff --git a/sw/source/core/inc/mvsave.hxx b/sw/source/core/inc/mvsave.hxx
index c472b6f7bc1a..d6cde5520ecb 100644
--- a/sw/source/core/inc/mvsave.hxx
+++ b/sw/source/core/inc/mvsave.hxx
@@ -116,7 +116,7 @@ struct SaveFly
 typedef std::deque< SaveFly > SaveFlyArr;
 
 void RestFlyInRange( SaveFlyArr& rArr, const SwPosition& rSttIdx,
-                      const SwNodeIndex* pInsPos );
+                     const SwNodeIndex* pInsPos, bool isForceToStartPos = 
false);
 void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& rArr );
 void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
                        SaveFlyArr& rArr, bool bMoveAllFlys );
commit 986fffa7f3d3eb4a49179230b7e39626f74771a4
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Jun 9 18:58:06 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:13:34 2022 +0200

    tdf#140007 sw: fix SwUndoReplace
    
    (regression from commit d6b0e84b236b78f4b21bd16e46dda3fa0876096d)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135585
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 45613274794636ba98d0e978fe872511297d275d)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135549
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit 7df50ecd9dea623058dc7bf9095fd13d9bb49860)
    
    Change-Id: I1facf1584a349d1d087438f4e6fd3a63a80c6f7e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136219
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index 9e6c81bc769f..f742288bf2db 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -820,6 +820,94 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf131912)
     CPPUNIT_ASSERT_EQUAL(OUString("foo"), pWrtShell->GetCursor()->GetText());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf140007)
+{
+    typedef sal_uLong SwNodeOffset;
+    SwDoc* const pDoc = createDoc();
+    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    pWrtShell->Insert("foo");
+    pWrtShell->SplitNode();
+    pWrtShell->Insert("bar");
+    pWrtShell->SplitNode();
+    pWrtShell->Insert("baz");
+    CPPUNIT_ASSERT_EQUAL(sal_uLong(13), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(11)]->GetTextNode()->GetText());
+
+    pWrtShell->SttEndDoc(true);
+    pWrtShell->EndPara(false);
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+    pWrtShell->Replace(" ", true);
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(12), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+
+    pWrtShell->SttEndDoc(true);
+    pWrtShell->EndPara(false);
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+    pWrtShell->Replace(" ", true);
+    CPPUNIT_ASSERT_EQUAL(OUString("foo bar baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(11), pDoc->GetNodes().Count());
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(12), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(13), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(11)]->GetTextNode()->GetText());
+
+    pWrtShell->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(12), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+
+    pWrtShell->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(OUString("foo bar baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(11), pDoc->GetNodes().Count());
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(12), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(SwNodeOffset(13), pDoc->GetNodes().Count());
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"),
+                         
pDoc->GetNodes()[SwNodeOffset(9)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("bar"),
+                         
pDoc->GetNodes()[SwNodeOffset(10)]->GetTextNode()->GetText());
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"),
+                         
pDoc->GetNodes()[SwNodeOffset(11)]->GetTextNode()->GetText());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf54819)
 {
     load(DATA_DIRECTORY, "tdf54819.fodt");
diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx
index 6135466bf73d..f1f7f48188aa 100644
--- a/sw/source/core/undo/unins.cxx
+++ b/sw/source/core/undo/unins.cxx
@@ -689,7 +689,8 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & 
rContext)
 
     if( m_bSplitNext )
     {
-        SwPosition aPos(*pNd, pNd->Len());
+        assert(m_nSttCnt + m_sOld.getLength() <= pNd->Len());
+        SwPosition aPos(*pNd, m_nSttCnt + m_sOld.getLength());
         pDoc->getIDocumentContentOperations().SplitNode( aPos, false );
         pNd->RestoreMetadata(m_pMetadataUndoEnd);
         pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTextNode();
@@ -723,7 +724,7 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & 
rContext)
     }
 
     rPam.GetPoint()->nNode = m_nSttNd;
-    rPam.GetPoint()->nContent = m_nSttCnt;
+    
rPam.GetPoint()->nContent.Assign(rPam.GetPoint()->nNode.GetNode().GetTextNode(),
 m_nSttCnt);
 }
 
 void SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext)
commit f8aea76d216b1c70a03ed204bc0a4dea4edb4c5b
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Jun 8 17:34:32 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:12:33 2022 +0200

    (related: tdf#139514) sw: fix Undo of delete with at-para fly
    
    Nonobviously, there are situations where the anchor node must be
    preserved and restored when it's not on the node that is being deleted.
    
    (probably regression from commit 91b2325808a75174f284c48c8b8afc118fad74e4)
    
    Change-Id: I39f09ddb631204c8ad522f9ec7068d235ca94ad2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135509
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 12acdce71dd6b6af2c52ba8fa3248d3166418543)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135518
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 054c248127c78521b4a4e7aacd8936bd54259996)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136218
    Tested-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index 3fe7f107f052..d611cb4a496b 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -981,10 +981,14 @@ void SwUndoSaveContent::DelContentIndex( const 
SwPosition& rMark,
                             // Moving the anchor?
                             else if 
(!((DelContentType::CheckNoCntnt|DelContentType::ExcludeFlyAtStartEnd)
                                     & nDelContentType) &&
-                                // at least for calls from SwUndoDelete,
-                                // this should work - other Undos don't
-                                // remember the order of the cursor
-                                (rPoint.nNode.GetIndex() == 
pAPos->nNode.GetIndex())
+                                // for SwUndoDelete: rPoint is the node that
+                                // will be Joined - so anchor should be moved
+                                // off it - but UndoImpl() split will insert
+                                // new node *before* existing one so a no-op
+                                // may need to be done here to add it to
+                                // history for Undo.
+                                (rPoint.nNode.GetIndex() == 
pAPos->nNode.GetIndex()
+                                 || pStt->nNode.GetIndex() == 
pAPos->nNode.GetIndex())
                                 // Do not try to move the anchor to a table!
                                 && rMark.nNode.GetNode().IsTextNode())
                             {
commit 3506fab4554238da59d22788cffe4e140c175215
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jun 7 19:01:24 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 23 18:12:09 2022 +0200

    tdf#133957 sw: don't delete flys on Backspace/Delete keys
    
    Also fixes: tdf#134007 tdf#138835 tdf#139514
    
    When a character is deleted via the keyboard by Backspace or Delete key,
    an artificial selection is created in SwWrtShell::DelLeft()/DelRight().
    
    Ideally this should not delete flys that may be anchored to the
    paragraphs, but unfortunately this may happen if there are only 2 empty
    paragraphs in the section, because then the artificial selection cannot
    be distinguished by the SwDoc implementation from a selection from
    Ctrl+A (Select All), which *should* delete the flys.
    
    So introduce a new flag that needs to be passed down multiple layers so
    that SwUndoDelete can use it to determine if flys should be deleted, and
    translating it to a flag that had been introduced to preserve flys in
    ReplaceRange() previously.
    
    There are a couple more callers that look like they want to "replace"
    some text, so guess a bit at where to set this new flag.
    
    (note: of course fly anchored *as char* must be deleted via keys.)
    
    (regression from commit e75dd1fc992f168f24d66595265a978071cdd277)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135476
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 85376a02348810812d515ee72140dbf56f2b6040)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135517
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 5192cd430e8cab0ed04f8c70c5194397455ac705)
    
    Change-Id: Ib4467476b12a12aefbbcb74ab9802f9318cf9aa0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136217
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/inc/IDocumentContentOperations.hxx 
b/sw/inc/IDocumentContentOperations.hxx
index b6857c346a33..6e6b3c1bad3e 100644
--- a/sw/inc/IDocumentContentOperations.hxx
+++ b/sw/inc/IDocumentContentOperations.hxx
@@ -69,6 +69,16 @@ namespace o3tl
     template<> struct typed_flags<SwInsertFlags> : 
is_typed_flags<SwInsertFlags, 0x07> {};
 }
 
+enum class SwDeleteFlags
+{
+    Default = 0,
+    ArtificialSelection = (1<<0), ///< keyboard delete, artificial selection, 
avoid deleting flys
+};
+namespace o3tl
+{
+    template<> struct typed_flags<SwDeleteFlags> : 
is_typed_flags<SwDeleteFlags, 0x01> {};
+}
+
 /** Text operation/manipulation interface
 */
 class IDocumentContentOperations
@@ -130,6 +140,7 @@ public:
         Needed for hiding of deletion redlines
     */
     virtual bool DeleteAndJoin( SwPaM&,
+        SwDeleteFlags flags = SwDeleteFlags::Default,
         const bool bForceJoinNext = false ) = 0;
 
     virtual bool MoveRange(SwPaM&, SwPosition&, SwMoveFlags) = 0;
diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx
index 53b91f44db98..3f2d34d66c2e 100644
--- a/sw/inc/editsh.hxx
+++ b/sw/inc/editsh.hxx
@@ -152,7 +152,7 @@ class SW_DLLPUBLIC SwEditShell : public SwCursorShell
      that will be used by GetGraphic() and GetGraphicSize(). */
     SAL_DLLPRIVATE SwGrfNode *GetGrfNode_() const ;
 
-    SAL_DLLPRIVATE void DeleteSel( SwPaM& rPam, bool* pUndo = nullptr );
+    SAL_DLLPRIVATE void DeleteSel(SwPaM& rPam, bool isArtificialSelection, 
bool* pUndo = nullptr);
 
     SAL_DLLPRIVATE void SetSectionAttr_( SwSectionFormat& rSectFormat, const 
SfxItemSet& rSet );
 
@@ -174,7 +174,7 @@ public:
 
     /** Delete content of all ranges.
      If whole nodes are selected, these nodes get deleted. */
-    bool Delete();
+    bool Delete(bool isArtificialSelection = false);
 
     /// Remove a complete paragraph.
     bool DelFullPara();
diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index 22cd289c7f27..ec18a86241bf 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -1149,7 +1149,7 @@ void SwDocTest::randomTest()
                     break;
                 case 2:
                     *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
-                    
m_pDoc->getIDocumentContentOperations().DeleteAndJoin(*pCrs, !!getRand(1));
+                    
m_pDoc->getIDocumentContentOperations().DeleteAndJoin(*pCrs, 
SwDeleteFlags::Default, !!getRand(1));
                     break;
                 case 3:
                 default:
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index aefb3f438cef..2db40c2e5d57 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -618,8 +618,9 @@ namespace sw
 namespace
 {
 
-    bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & 
rDocumentContentOperations, SwPaM & rPam,
-            bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, 
bool), const bool bForceJoinNext = false)
+    bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & 
rDocumentContentOperations,
+            SwPaM & rPam, SwDeleteFlags const flags,
+            bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, 
SwDeleteFlags, bool), const bool bForceJoinNext = false)
     {
         std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
 
@@ -627,7 +628,7 @@ namespace
 
         if (Breaks.empty())
         {
-            return (rDocumentContentOperations.*pFunc)(rPam, bForceJoinNext);
+            return (rDocumentContentOperations.*pFunc)(rPam, flags, 
bForceJoinNext);
         }
 
         // Deletion must be split into several parts if the text node
@@ -651,7 +652,7 @@ namespace
             rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), 
iter->second + 1);
             if (rStart < rEnd) // check if part is empty
             {
-                bRet &= (rDocumentContentOperations.*pFunc)(aPam, 
bForceJoinNext);
+                bRet &= (rDocumentContentOperations.*pFunc)(aPam, flags, 
bForceJoinNext);
                 nOffset = iter->first - rStart.nNode.GetIndex(); // deleted 
fly nodes...
             }
             rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), 
iter->second);
@@ -661,7 +662,7 @@ namespace
         rStart = *rPam.Start(); // set to original start
         if (rStart < rEnd) // check if part is empty
         {
-            bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
+            bRet &= (rDocumentContentOperations.*pFunc)(aPam, flags, 
bForceJoinNext);
         }
 
         return bRet;
@@ -1997,7 +1998,7 @@ void DocumentContentOperationsManager::DeleteDummyChar(
     assert(aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy);
     (void) cDummy;
 
-    DeleteRangeImpl(aPam);
+    DeleteRangeImpl(aPam, SwDeleteFlags::Default);
 
     if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
         && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
@@ -2008,7 +2009,7 @@ void DocumentContentOperationsManager::DeleteDummyChar(
 
 void DocumentContentOperationsManager::DeleteRange( SwPaM & rPam )
 {
-    lcl_DoWithBreaks( *this, rPam, 
&DocumentContentOperationsManager::DeleteRangeImpl );
+    lcl_DoWithBreaks(*this, rPam, SwDeleteFlags::Default, 
&DocumentContentOperationsManager::DeleteRangeImpl);
 
     if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
         && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
@@ -2111,7 +2112,7 @@ bool DocumentContentOperationsManager::DelFullPara( 
SwPaM& rPam )
             ::PaMCorrAbs( aDelPam, aTmpPos );
         }
 
-        std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aDelPam, true ));
+        std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete(aDelPam, 
SwDeleteFlags::Default, true));
 
         *rPam.GetPoint() = *aDelPam.GetPoint();
         pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
@@ -2206,13 +2207,13 @@ bool DocumentContentOperationsManager::DelFullPara( 
SwPaM& rPam )
 }
 
 // #i100466# Add handling of new optional parameter <bForceJoinNext>
-bool DocumentContentOperationsManager::DeleteAndJoin( SwPaM & rPam,
+bool DocumentContentOperationsManager::DeleteAndJoin(SwPaM & rPam, 
SwDeleteFlags const flags,
                            const bool bForceJoinNext )
 {
     if ( lcl_StrLenOverflow( rPam ) )
         return false;
 
-    bool const ret = lcl_DoWithBreaks( *this, rPam, 
(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
+    bool const ret = lcl_DoWithBreaks( *this, rPam, flags, 
(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
                 ? 
&DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl
                 : &DocumentContentOperationsManager::DeleteAndJoinImpl,
                 bForceJoinNext );
@@ -3345,8 +3346,8 @@ bool DocumentContentOperationsManager::ReplaceRange( 
SwPaM& rPam, const OUString
         if (rStart < rEnd) // check if part is empty
         {
             bRet &= (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
-                ? DeleteAndJoinWithRedlineImpl(aPam)
-                : DeleteAndJoinImpl(aPam, false);
+                ? DeleteAndJoinWithRedlineImpl(aPam, SwDeleteFlags::Default)
+                : DeleteAndJoinImpl(aPam, SwDeleteFlags::Default, false);
             nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly 
nodes...
         }
         rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), 
iter->second);
@@ -3914,7 +3915,7 @@ 
DocumentContentOperationsManager::~DocumentContentOperationsManager()
 }
 //Private methods
 
-bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & 
rPam, const bool )
+bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & 
rPam, SwDeleteFlags const /*flags*/, const bool)
 {
     assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn());
 
@@ -4055,7 +4056,7 @@ bool 
DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPa
     return true;
 }
 
-bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
+bool DocumentContentOperationsManager::DeleteAndJoinImpl(SwPaM & rPam, 
SwDeleteFlags const flags,
                                const bool bForceJoinNext )
 {
     bool bJoinText, bJoinPrev;
@@ -4067,7 +4068,7 @@ bool DocumentContentOperationsManager::DeleteAndJoinImpl( 
SwPaM & rPam,
     }
 
     {
-        bool const bSuccess( DeleteRangeImpl( rPam ) );
+        bool const bSuccess( DeleteRangeImpl(rPam, flags) );
         if (!bSuccess)
             return false;
     }
@@ -4086,14 +4087,14 @@ bool 
DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
     return true;
 }
 
-bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, const 
bool)
+bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, 
SwDeleteFlags const flags, const bool)
 {
     // Move all cursors out of the deleted range, but first copy the
     // passed PaM, because it could be a cursor that would be moved!
     SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
     ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
 
-    bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
+    bool const bSuccess( DeleteRangeImplImpl(aDelPam, flags) );
     if (bSuccess)
     {   // now copy position from temp copy to given PaM
         *rPam.GetPoint() = *aDelPam.GetPoint();
@@ -4102,7 +4103,7 @@ bool 
DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, const bool)
     return bSuccess;
 }
 
-bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
+bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam, 
SwDeleteFlags const flags)
 {
     SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
 
@@ -4167,7 +4168,7 @@ bool 
DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
         }
         if (!bMerged)
         {
-            m_rDoc.GetIDocumentUndoRedo().AppendUndo( 
std::make_unique<SwUndoDelete>( rPam ) );
+            
m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoDelete>(rPam, 
flags));
         }
 
         m_rDoc.getIDocumentState().SetModified();
@@ -4179,8 +4180,11 @@ bool 
DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
         m_rDoc.getIDocumentRedlineAccess().DeleteRedline( rPam, true, 
RedlineType::Any );
 
     // Delete and move all "Flys at the paragraph", which are within the 
Selection
-    DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode,
-        &rPam.GetMark()->nContent, &rPam.GetPoint()->nContent);
+    if (!(flags & SwDeleteFlags::ArtificialSelection))
+    {
+        DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode,
+            &rPam.GetMark()->nContent, &rPam.GetPoint()->nContent);
+    }
     DelBookmarks(
         pStt->nNode,
         pEnd->nNode,
diff --git a/sw/source/core/docnode/ndsect.cxx 
b/sw/source/core/docnode/ndsect.cxx
index 8c2efee0eb7e..6154cfc7d776 100644
--- a/sw/source/core/docnode/ndsect.cxx
+++ b/sw/source/core/docnode/ndsect.cxx
@@ -535,7 +535,7 @@ void SwDoc::DelSectionFormat( SwSectionFormat *pFormat, 
bool bDelNodes )
             {
                 SwNodeIndex aUpdIdx( *pIdx );
                 SwPaM aPaM( *pSectNd->EndOfSectionNode(), *pSectNd );
-                GetIDocumentUndoRedo().AppendUndo( 
std::make_unique<SwUndoDelete>( aPaM ));
+                
GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoDelete>(aPaM, 
SwDeleteFlags::Default));
                 if( pFootnoteEndAtTextEnd )
                     GetFootnoteIdxs().UpdateFootnote( aUpdIdx );
                 getIDocumentState().SetModified();
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index 15a49729ce51..b12fc72228e2 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -2040,7 +2040,7 @@ bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool 
bColumn )
                     bSavePageBreak = true;
                 }
             }
-            std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aPaM ));
+            std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete(aPaM, 
SwDeleteFlags::Default));
             if( bNewTextNd )
                 pUndo->SetTableDelLastNd();
             pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
diff --git a/sw/source/core/edit/autofmt.cxx b/sw/source/core/edit/autofmt.cxx
index cb905187faed..6e4bccb55bcc 100644
--- a/sw/source/core/edit/autofmt.cxx
+++ b/sw/source/core/edit/autofmt.cxx
@@ -1196,7 +1196,7 @@ void SwAutoFormat::DeleteSelImpl(SwPaM & rDelPam, SwPaM & 
rPamToCorrect)
         SwPaM* pPrev = rPamToCorrect.GetPrev();
         rPamToCorrect.GetRingContainer().merge( pShCursor->GetRingContainer() 
);
 
-        m_pEditShell->DeleteSel( rDelPam );
+        m_pEditShell->DeleteSel(rDelPam, true);
 
         // and remove Pam again:
         SwPaM* p;
@@ -1212,7 +1212,7 @@ void SwAutoFormat::DeleteSelImpl(SwPaM & rDelPam, SwPaM & 
rPamToCorrect)
         m_pCurTextFrame = GetFrame(*m_pCurTextNd); // keep it up to date
     }
     else
-        m_pEditShell->DeleteSel( rDelPam );
+        m_pEditShell->DeleteSel(rDelPam, true);
 }
 
 bool SwAutoFormat::DeleteJoinCurNextPara(SwTextFrame const*const pNextFrame,
diff --git a/sw/source/core/edit/eddel.cxx b/sw/source/core/edit/eddel.cxx
index 6389ddc78987..ac60b7343ac4 100644
--- a/sw/source/core/edit/eddel.cxx
+++ b/sw/source/core/edit/eddel.cxx
@@ -38,7 +38,7 @@
 #include <strings.hrc>
 #include <vector>
 
-void SwEditShell::DeleteSel( SwPaM& rPam, bool* pUndo )
+void SwEditShell::DeleteSel(SwPaM& rPam, bool const isArtificialSelection, 
bool *const pUndo)
 {
     bool bSelectAll = StartsWithTable() && ExtendedSelectedAll();
     // only for selections
@@ -121,7 +121,8 @@ void SwEditShell::DeleteSel( SwPaM& rPam, bool* pUndo )
             pPam = pNewPam.get();
         }
         // delete everything
-        GetDoc()->getIDocumentContentOperations().DeleteAndJoin(*pPam);
+        GetDoc()->getIDocumentContentOperations().DeleteAndJoin(*pPam,
+            isArtificialSelection ? SwDeleteFlags::ArtificialSelection : 
SwDeleteFlags::Default);
         SaveTableBoxContent( pPam->GetPoint() );
     }
 
@@ -129,7 +130,7 @@ void SwEditShell::DeleteSel( SwPaM& rPam, bool* pUndo )
     rPam.DeleteMark();
 }
 
-bool SwEditShell::Delete()
+bool SwEditShell::Delete(bool const isArtificialSelection)
 {
     SET_CURR_SHELL( this );
     bool bRet = false;
@@ -148,7 +149,7 @@ bool SwEditShell::Delete()
 
         for(SwPaM& rPaM : GetCursor()->GetRingContainer())
         {
-            DeleteSel( rPaM, &bUndo );
+            DeleteSel(rPaM, isArtificialSelection, &bUndo);
         }
 
         // If undo container then close here
diff --git a/sw/source/core/edit/edglbldc.cxx b/sw/source/core/edit/edglbldc.cxx
index 3d916edc5fe0..c5ea9081d043 100644
--- a/sw/source/core/edit/edglbldc.cxx
+++ b/sw/source/core/edit/edglbldc.cxx
@@ -272,7 +272,7 @@ void SwEditShell::DeleteGlobalDocContent( const 
SwGlblDocContents& rArr ,
                 rPos.nNode = pMyDoc->GetNodes().GetEndOfContent();
             --rPos.nNode;
             if( !pMyDoc->getIDocumentContentOperations().DelFullPara( *pCursor 
) )
-                Delete();
+                Delete(false);
         }
         break;
 
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index 8f84ce42ed75..699997003daf 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -663,7 +663,7 @@ bool SwEditShell::InsertURL( const SwFormatINetFormat& 
rFormat, const OUString&
                 bDelText = bInsText = false;
 
             if( bDelText )
-                Delete();
+                Delete(true);
         }
         else if( pCursor->IsMultiSelection() && rFormat.GetValue() == rStr )
             bInsText = false;
@@ -732,7 +732,7 @@ void SwEditShell::DelINetAttrWithText()
 {
     bool bRet = SelectTextAttr( RES_TXTATR_INETFMT, false );
     if( bRet )
-        DeleteSel( *GetCursor() );
+        DeleteSel(*GetCursor(), true);
 }
 
 /// Set the DontExpand flag at the text character attributes
diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx
index c2470b997a93..8589b8eed579 100644
--- a/sw/source/core/frmedt/fecopy.cxx
+++ b/sw/source/core/frmedt/fecopy.cxx
@@ -1021,7 +1021,7 @@ bool SwFEShell::Paste( SwDoc* pClpDoc, bool bNestedTable )
             {
                 if( bDelTable && IsTableMode() )
                 {
-                    SwEditShell::Delete();
+                    SwEditShell::Delete(false);
                     bDelTable = false;
                 }
 
diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx 
b/sw/source/core/inc/DocumentContentOperationsManager.hxx
index 2d600b6ff8ba..994812dc14b4 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -48,6 +48,7 @@ public:
     // Add optional parameter <bForceJoinNext>, default value <false>
     // Needed for hiding of deletion redlines
     bool DeleteAndJoin( SwPaM&,
+        SwDeleteFlags flags = SwDeleteFlags::Default,
         const bool bForceJoinNext = false ) override;
 
     bool MoveRange(SwPaM&, SwPosition&, SwMoveFlags) override;
@@ -159,10 +160,10 @@ public:
 private:
     SwDoc& m_rDoc;
 

... etc. - the rest is truncated

Reply via email to