Writer: Fix empty selection callback.

Issue: When selecting words using CTRL+Mouse click, core side needs to send the selection rectangles to Online side.
Rectangles are not sent but an empty message.

Fix: Aggregate selection rectangles from all cursors in the ring.
In add mode (CTRL+click multi-selection), the actual selections
are stored in ring cursors, while m_pCurrentCursor may be empty.
Without aggregation, callback only reads from m_pCurrentCursor and sends an empty payload,
clearing the selection on the online side.

Change-Id: I9af5d850ab59644f56358a9ecc5985b2ad529619
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201841
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
Gökay Şatır
2026-03-17 08:11:33 +01:00
committed by Miklos Vajna
parent 2252e91755
commit 85057d938d
3 changed files with 31 additions and 21 deletions
+1 -1
View File
@@ -138,7 +138,7 @@ public:
static void Get1PixelInLogic( const SwViewShell& rSh,
tools::Long* pX = nullptr, tools::Long* pY = nullptr );
std::optional<OString> getLOKPayload(int nType, int nViewId) const;
std::optional<OString> getLOKPayload(int nType) const;
};
/// Represents the current text cursor of one opened edit window.
+1 -18
View File
@@ -531,7 +531,7 @@ void SwSelPaintRects::Show(std::vector<OString>* pSelectionRectangles)
pSelectionRectangles->push_back(sRect);
}
std::optional<OString> SwSelPaintRects::getLOKPayload(int nType, int nViewId) const
std::optional<OString> SwSelPaintRects::getLOKPayload(int nType) const
{
switch( nType )
{
@@ -565,23 +565,6 @@ std::optional<OString> SwSelPaintRects::getLOKPayload(int nType, int nViewId) co
}
}
break;
case LOK_CALLBACK_TEXT_SELECTION:
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
{
std::vector<OString> aRect;
aRect.reserve(size());
for (size_type i = 0; i < size(); ++i)
{
const SwRect& rRect = (*this)[i];
aRect.push_back(rRect.SVRect().toString());
}
OString sRect = comphelper::string::join("; ", aRect);
if( nType == LOK_CALLBACK_TEXT_SELECTION )
return sRect;
else // LOK_CALLBACK_TEXT_VIEW_SELECTION
return SfxLokHelper::makePayloadJSON(GetShell()->GetSfxViewShell(), nViewId, "selection", sRect);
}
break;
}
abort();
}
+29 -2
View File
@@ -18,8 +18,11 @@
*/
#include <wrtsh.hxx>
#include <viscrs.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/string.hxx>
#include <sfx2/lokhelper.hxx>
// Private methods, which move the cursor over search.
// The removal of the selection must be made on the level above.
@@ -242,10 +245,34 @@ std::optional<OString> SwWrtShell::getLOKPayload(int nType, int nViewId) const
case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
return GetVisibleCursor()->getLOKPayload(nType, nViewId);
case LOK_CALLBACK_TEXT_SELECTION:
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
{
// Aggregate selection rectangles from all cursors in the ring.
// In add mode (CTRL+click multi-selection), the actual selections
// are stored in ring cursors, while m_pCurrentCursor may be empty.
// Without aggregation, callback only reads from m_pCurrentCursor and send an empty payload,
// clearing the selection on the online side.
std::vector<OString> aAllRects;
for (const SwPaM& rPaM : GetCursor_()->GetRingContainer())
{
const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rPaM);
if (!pShCursor)
continue;
for (size_t i = 0; i < pShCursor->size(); ++i)
{
const SwRect& rRect = (*pShCursor)[i];
aAllRects.push_back(rRect.SVRect().toString());
}
}
OString sRect = comphelper::string::join("; ", aAllRects);
if (nType == LOK_CALLBACK_TEXT_SELECTION)
return sRect;
else // LOK_CALLBACK_TEXT_VIEW_SELECTION
return SfxLokHelper::makePayloadJSON(GetSfxViewShell(), nViewId, "selection", sRect);
}
case LOK_CALLBACK_TEXT_SELECTION_START:
case LOK_CALLBACK_TEXT_SELECTION_END:
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
return GetCursor_()->getLOKPayload(nType, nViewId);
return GetCursor_()->getLOKPayload(nType);
}
abort();
}