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.stahl@allotropia.de>
Tested-by: Jenkins
This commit is contained in:
Michael Stahl 2022-07-22 19:34:12 +02:00
parent 316e4c01f4
commit baf8d2c1c1
8 changed files with 59 additions and 16 deletions

View file

@ -24,6 +24,9 @@
#include <com/sun/star/container/XEnumeration.hpp>
#include <cppuhelper/implbase.hxx>
#include <o3tl/typed_flags_set.hxx>
#include <vcl/svapp.hxx>
class SfxPoolItem;
@ -53,6 +56,22 @@ enum class CursorType
ContentControl,
};
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
*/

View file

@ -102,9 +102,7 @@ public:
bool IsAtEndOfMeta() const;
bool IsAtEndOfContentControl() 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;

View file

@ -109,7 +109,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;

View file

@ -1306,6 +1306,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);
}

View file

@ -1136,7 +1136,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;

View file

@ -705,7 +705,7 @@ SwXTextCursor::~SwXTextCursor()
}
void SwXTextCursor::DeleteAndInsert(const OUString& rText,
const bool bForceExpandHints)
::sw::DeleteAndInsertMode const eMode)
{
auto pUnoCursor = static_cast<SwCursor*>(m_pUnoCursor.get());
if (!pUnoCursor)
@ -721,13 +721,16 @@ void SwXTextCursor::DeleteAndInsert(const OUString& rText,
{
if (pCurrent->HasMark())
{
rDoc.getIDocumentContentOperations().DeleteAndJoin(*pCurrent);
rDoc.getIDocumentContentOperations().DeleteAndJoin(*pCurrent,
// is it "delete" or "replace"?
// FIXME still test failure because insertTextContent calls with empty string
(nTextLen != 0 || eMode & ::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default);
}
if(nTextLen)
{
const bool bSuccess(
SwUnoCursorHelper::DocInsertStringSplitCR(
rDoc, *pCurrent, rText, bForceExpandHints ) );
rDoc, *pCurrent, rText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints)));
OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." );
SwUnoCursorHelper::SelectPam(*pUnoCursor, true);
@ -1724,7 +1727,7 @@ SwXTextCursor::setString(const OUString& aString)
const bool bForceExpandHints( (CursorType::Meta == m_eType)
&& dynamic_cast<SwXMeta&>(*m_xParentText)
.CheckForOwnMemberMeta(*GetPaM(), true) );
DeleteAndInsert(aString, bForceExpandHints);
DeleteAndInsert(aString, bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default);
}
uno::Any SwUnoCursorHelper::GetPropertyValue(

View file

@ -800,7 +800,7 @@ static void DeleteTable(SwDoc & rDoc, SwTable& rTable)
}
void SwXTextRange::DeleteAndInsert(
const OUString& rText, const bool bForceExpandHints)
const OUString& rText, ::sw::DeleteAndInsertMode const eMode)
{
if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition)
{
@ -887,13 +887,14 @@ void SwXTextRange::DeleteAndInsert(
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());
@ -1060,7 +1061,7 @@ void SAL_CALL SwXTextRange::setString(const OUString& rString)
{
SolarMutexGuard aGuard;
DeleteAndInsert(rString, false);
DeleteAndInsert(rString, ::sw::DeleteAndInsertMode::Default);
}
bool SwXTextRange::GetPositions(SwPaM& rToFill, ::sw::TextRangeMode const eMode) const

View file

@ -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,9 +607,23 @@ SwXText::insertTextContent(
|| pSection || pReferenceMark || pMeta || pContentControl || pTextField;
if (bAbsorb && !bAttribute)
{
uno::Reference<lang::XUnoTunnel> const xRangeTunnel(xRange, uno::UNO_QUERY);
if (SwXTextRange *const pRange = comphelper::getFromUnoTunnel<SwXTextRange>(xRangeTunnel))
{
pRange->DeleteAndInsert(OUString(), ::sw::DeleteAndInsertMode::ForceReplace
| (bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default));
}
else if (SwXTextCursor *const pCursor = dynamic_cast<SwXTextCursor*>(comphelper::getFromUnoTunnel<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();
if (bForceExpandHints)