cool#13988 sw redline tooltip LOK API: expose anchor range
Open a document with a tracked change in a LOK client, hover your mouse
over the tracked change, LOK_CALLBACK_TOOLTIP gets triggered, but no
info is sent about the redline itself.
Something similar already happens for content controls, there
LOK_CALLBACK_CONTENT_CONTROL has a 'rectangles' key to describe the
range (rectangles) of the content control.
Fix the problem in a similar way: let SwEditWin::RequestHelp() check if
the content under the cursor is a redline and if so, emit the redline
range's rectangles as a new property of the tooltip.
This time do it as a JSON array, e.g.
{ "type": "generaltooltip", "text": "Deleted: ...", "rectangle": "...", "anchorRectangles": [ "1418, 1966, 2390, 264", "2159, 1701, 9231, 264"]}
to do less string parsing on the LOK client side. And finally expose the
redline type in a similar way, so the LOK client can color the highlight
accordingly.
Change-Id: I6b72d5ff38d2a2b4fab0bda3564dd5b2770779d6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199849
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
@@ -9,15 +9,25 @@
|
||||
|
||||
#include <swmodeltestbase.hxx>
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <com/sun/star/text/XTextDocument.hpp>
|
||||
|
||||
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
|
||||
#include <comphelper/lok.hxx>
|
||||
#include <sfx2/lokhelper.hxx>
|
||||
#include <test/lokcallback.hxx>
|
||||
#include <vcl/event.hxx>
|
||||
#include <vcl/scheduler.hxx>
|
||||
|
||||
#include <docsh.hxx>
|
||||
#include <edtwin.hxx>
|
||||
#include <flyfrm.hxx>
|
||||
#include <frameformats.hxx>
|
||||
#include <IDocumentRedlineAccess.hxx>
|
||||
#include <unotxdoc.hxx>
|
||||
#include <view.hxx>
|
||||
#include <viscrs.hxx>
|
||||
#include <wrtsh.hxx>
|
||||
|
||||
namespace
|
||||
@@ -187,6 +197,95 @@ CPPUNIT_TEST_FIXTURE(Test, testShiftDoubleClickOnImage)
|
||||
CPPUNIT_ASSERT_GREATER(0, nGraphicDialogs);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Test LOK callback, handling just LOK_CALLBACK_TOOLTIP.
|
||||
struct TooltipCallback
|
||||
{
|
||||
std::string rect;
|
||||
std::string anchorRectangles;
|
||||
std::string redlineType;
|
||||
|
||||
static void callback(int nType, const char* pPayload, void* pData);
|
||||
void callbackImpl(int nType, const char* pPayload);
|
||||
};
|
||||
|
||||
void TooltipCallback::callback(int nType, const char* pPayload, void* pData)
|
||||
{
|
||||
static_cast<TooltipCallback*>(pData)->callbackImpl(nType, pPayload);
|
||||
}
|
||||
|
||||
void TooltipCallback::callbackImpl(int nType, const char* pPayload)
|
||||
{
|
||||
if (nType == LOK_CALLBACK_TOOLTIP)
|
||||
{
|
||||
std::stringstream aStream(pPayload);
|
||||
boost::property_tree::ptree aTree;
|
||||
boost::property_tree::read_json(aStream, aTree);
|
||||
rect = aTree.get_child("rectangle").get_value<std::string>();
|
||||
auto it = aTree.find("anchorRectangles");
|
||||
if (it != aTree.not_found())
|
||||
{
|
||||
std::vector<std::string> aRects;
|
||||
for (const auto& rRect : it->second)
|
||||
aRects.push_back(rRect.second.get_value<std::string>());
|
||||
std::stringstream aRectStream;
|
||||
for (size_t i = 0; i < aRects.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
aRectStream << "; ";
|
||||
aRectStream << aRects[i];
|
||||
}
|
||||
anchorRectangles = aRectStream.str();
|
||||
}
|
||||
auto itType = aTree.find("redlineType");
|
||||
if (itType != aTree.not_found())
|
||||
redlineType = itType->second.get_value<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testRedlineTooltipAnchorRectangles)
|
||||
{
|
||||
// Set up LOK:
|
||||
comphelper::LibreOfficeKit::setActive(true);
|
||||
|
||||
// Given a document with a redline:
|
||||
createSwDoc();
|
||||
getSwTextDoc()->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
|
||||
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
|
||||
TooltipCallback aCallback;
|
||||
TestLokCallbackWrapper aCallbackWrapper(&TooltipCallback::callback, &aCallback);
|
||||
pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&aCallbackWrapper);
|
||||
aCallbackWrapper.setLOKViewId(SfxLokHelper::getView(*pWrtShell->GetSfxViewShell()));
|
||||
pWrtShell->SetRedlineFlagsAndCheckInsMode(RedlineFlags::On | RedlineFlags::ShowMask);
|
||||
pWrtShell->Insert(u"test"_ustr);
|
||||
|
||||
// When moving the mouse over the redline:
|
||||
SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
|
||||
CPPUNIT_ASSERT(pShellCursor);
|
||||
pWrtShell->EndOfSection(/*bSelect=*/false);
|
||||
Point aEnd = pShellCursor->GetSttPos();
|
||||
pWrtShell->StartOfSection(/*bSelect=*/false);
|
||||
Point aStart = pShellCursor->GetSttPos();
|
||||
Point aMiddle((aStart.getX() + aEnd.getX()) / 2, (aStart.getY() + aEnd.getY()) / 2);
|
||||
getSwTextDoc()->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE, aMiddle.getX(), aMiddle.getY(), 1, 0,
|
||||
0);
|
||||
Scheduler::ProcessEventsToIdle();
|
||||
|
||||
// Then make sure the tooltip callback has redlineType and anchorRectangles:
|
||||
// Without the accompanying fix in place, this test would have failed, no anchor rectangles were
|
||||
// emitted.
|
||||
CPPUNIT_ASSERT(!aCallback.anchorRectangles.empty());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Insert"), aCallback.redlineType);
|
||||
|
||||
// Tear down LOK:
|
||||
pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
|
||||
mxComponent->dispose();
|
||||
mxComponent.clear();
|
||||
comphelper::LibreOfficeKit::setActive(false);
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
#include <names.hxx>
|
||||
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
|
||||
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
|
||||
#include <viscrs.hxx>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -314,13 +315,31 @@ OUString SwEditWin::ClipLongToolTip(const OUString& rText)
|
||||
return sDisplayText;
|
||||
}
|
||||
|
||||
static OString getTooltipPayload(const OUString& tooltip, const SwRect& rect)
|
||||
static OString getTooltipPayload(const OUString& tooltip, const SwRect& rect,
|
||||
SwWrtShell& rSh,
|
||||
const SwRangeRedline* pRedline = nullptr)
|
||||
{
|
||||
tools::JsonWriter writer;
|
||||
{
|
||||
writer.put("type", "generaltooltip");
|
||||
writer.put("text", tooltip);
|
||||
writer.put("rectangle", rect.SVRect().toString());
|
||||
|
||||
if (pRedline)
|
||||
{
|
||||
writer.put("redlineType",
|
||||
SwRedlineTypeToOUString(pRedline->GetRedlineData().GetType()));
|
||||
|
||||
SwShellCursor aCursor(rSh, *pRedline->Start());
|
||||
aCursor.SetMark();
|
||||
*aCursor.GetMark() = *pRedline->End();
|
||||
aCursor.FillRects();
|
||||
auto aArray = writer.startArray("anchorRectangles");
|
||||
for (const auto& rRect : aCursor)
|
||||
{
|
||||
writer.putSimpleValue(OUString::fromUtf8(rRect.SVRect().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return writer.finishAndGetAsOString();
|
||||
}
|
||||
@@ -699,8 +718,13 @@ void SwEditWin::RequestHelp(const HelpEvent &rEvt)
|
||||
{
|
||||
if (comphelper::LibreOfficeKit::isActive())
|
||||
{
|
||||
m_rView.libreOfficeKitViewCallback(
|
||||
LOK_CALLBACK_TOOLTIP, getTooltipPayload(sText, aFieldRect));
|
||||
const SwRangeRedline* pRedline = nullptr;
|
||||
if (aContentAtPos.eContentAtPos == IsAttrAtPos::Redline)
|
||||
{
|
||||
pRedline = aContentAtPos.aFnd.pRedl;
|
||||
}
|
||||
OString aPayload = getTooltipPayload(sText, aFieldRect, rSh, pRedline);
|
||||
m_rView.libreOfficeKitViewCallback(LOK_CALLBACK_TOOLTIP, aPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user