sw: fix fly at-char deletion API behaviour change

28b77c89dfcafae82cf2a6d85731b643ff9290e5 changed at-char anchored fly
selection.

WollMux calls setString("") to remove one character in the first
paragraph and a fly anchored at the start of the body text is deleted
due to the new IsAtStartOfSection() check.

It would be possible to treat deletion via API differently than via UI,
as there is already a flag ExcludeFlyAtStartEnd but it would require
passing the flag through 10 functions and also to store it in
SwUndoDelete...

The main intent of the IsAtStartOfSection() check was that Ctrl+A should
delete every fly; this can be achieved by checking that everything was
selected, so that selections only inside the first/last paragraph don't
delete the flys at the edges.

Change-Id: Id62e7d99a10b42eaecea5564372d29b6c43e3f7e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91993
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@cib.de>
(cherry picked from commit 971205dc2110c1c23ff1db1fc4041e2babf6fa9f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92169
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/sw/qa/extras/unowriter/unowriter.cxx b/sw/qa/extras/unowriter/unowriter.cxx
index 788acff..a265bb2 100644
--- a/sw/qa/extras/unowriter/unowriter.cxx
+++ b/sw/qa/extras/unowriter/unowriter.cxx
@@ -16,6 +16,7 @@
#include <com/sun/star/text/XAutoTextGroup.hpp>
#include <com/sun/star/text/XTextPortionAppend.hpp>
#include <com/sun/star/text/XTextContentAppend.hpp>
#include <com/sun/star/text/XTextRangeCompare.hpp>
#include <com/sun/star/rdf/URI.hpp>
#include <com/sun/star/rdf/URIs.hpp>
#include <com/sun/star/awt/XDevice.hpp>
@@ -453,6 +454,56 @@ CPPUNIT_TEST_FIXTURE(SwUnoWriter, testSetPagePrintSettings)
    CPPUNIT_ASSERT_EQUAL(true, aMap.getValue("IsLandscape").get<bool>());
}

CPPUNIT_TEST_FIXTURE(SwUnoWriter, testDeleteFlyAtCharAtStart)
{
    loadURL("private:factory/swriter", nullptr);
    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pTextDoc);
    SwWrtShell* const pWrtShell(pTextDoc->GetDocShell()->GetWrtShell());
    SwDoc* const pDoc(pWrtShell->GetDoc());

    // insert some text
    IDocumentContentOperations& rIDCO(pDoc->getIDocumentContentOperations());
    rIDCO.InsertString(*pWrtShell->GetCursor(), "foo bar baz");

    // insert fly anchored at start of body text
    pWrtShell->ClearMark();
    pWrtShell->SttEndDoc(true);
    SfxItemSet frameSet(pDoc->GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END - 1>{});
    SfxItemSet grfSet(pDoc->GetAttrPool(), svl::Items<RES_GRFATR_BEGIN, RES_GRFATR_END - 1>{});
    SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
    frameSet.Put(anchor);
    GraphicObject grf;
    CPPUNIT_ASSERT(rIDCO.InsertGraphicObject(*pWrtShell->GetCursor(), grf, &frameSet, &grfSet));

    // check fly
    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage->getCount());
    uno::Reference<text::XTextContent> const xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
    // anchored at start of body text?
    uno::Reference<text::XText> const xText(pTextDoc->getText());
    uno::Reference<text::XTextRangeCompare> const xTextRC(xText, uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int16(0),
                         xTextRC->compareRegionStarts(xText->getStart(), xShape->getAnchor()));

    // delete 1st character
    uno::Reference<text::XTextCursor> const xCursor(xText->createTextCursor());
    xCursor->goRight(1, true);
    xCursor->setString("");

    // there is exactly one fly
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage->getCount());

    // select entire body text
    xCursor->gotoStart(true);
    xCursor->gotoEnd(true);
    xCursor->setString("");

    // there is no fly
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xDrawPage->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUnoWriter, testSelectionInTableEnum)
{
    load(mpTestDocumentPath, "selection-in-table-enum.odt");
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index 3b3f8f2..a73ceeb 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -1568,14 +1568,14 @@ bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos,
                && ((rStart.nNode != rEnd.nNode && rStart.nContent == 0
                        // but not if the selection is backspace/delete!
                        && IsNotBackspaceHeuristic(rStart, rEnd))
                    || IsAtStartOfSection(rAnchorPos))))
                    || (IsAtStartOfSection(rAnchorPos) && IsAtEndOfSection(rEnd)))))
        && ((rAnchorPos < rEnd)
            || (rAnchorPos == rEnd
                && !(nDelContentType & DelContentType::ExcludeFlyAtStartEnd)
                // special case: fully deleted node
                && ((rEnd.nNode != rStart.nNode && rEnd.nContent == rEnd.nNode.GetNode().GetTextNode()->Len()
                        && IsNotBackspaceHeuristic(rStart, rEnd))
                    || IsAtEndOfSection(rAnchorPos))));
                    || (IsAtEndOfSection(rAnchorPos) && IsAtStartOfSection(rStart)))));
}

bool IsSelectFrameAnchoredAtPara(SwPosition const & rAnchorPos,