desktop/source/lib/init.cxx                    |   28 +++++------
 include/LibreOfficeKit/LibreOfficeKitEnums.h   |   14 +++++
 libreofficekit/source/gtk/lokdocview.cxx       |    1 
 sfx2/source/view/lokhelper.cxx                 |    3 +
 sw/qa/extras/tiledrendering/tiledrendering.cxx |   45 ++++++++++++++++++
 sw/source/uibase/docvw/edtwin2.cxx             |   60 ++++++++++++++++---------
 6 files changed, 116 insertions(+), 35 deletions(-)

New commits:
commit 6a20e8ae6c7d60ea39df4e2308f57880d64b7229
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Tue Dec 26 14:08:07 2023 +0600
Commit:     Michael Meeks <michael.me...@collabora.com>
CommitDate: Tue Jan 16 21:01:58 2024 +0000

    Send tooltip text to LOK
    
    Call vcl::Window::RequestHelp from LOKPostAsyncEvent for
    mouse movement. Introduce LOK_CALLBACK_TOOLTIP callback
    type, and send it from SwEditWin::RequestHelp.
    
    Intention is, that the tooltip is shown by client at the
    current mouse pointer position, which is hopefully not
    far away from the point that generated the mouse event.
    On the next movement, the client starts a timer to hide
    the tooltip. If the next tooltip message arrives, the
    tooltip would be updated in the new place.
    
    Alternatively, the payload could contain the coordinates
    from the HelpEvent.
    
    Change-Id: I8e96eb6e6983ad8d13b4c5d7be4d51ff3fd11893
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161302
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 6d141aeca865..6701988a5c0a 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1845,6 +1845,7 @@ void CallbackFlushHandler::queue(const int type, 
CallbackData& aCallbackData)
             case LOK_CALLBACK_GRAPHIC_SELECTION:
             case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
             case LOK_CALLBACK_INVALIDATE_TILES:
+            case LOK_CALLBACK_TOOLTIP:
                 if (removeAll(type))
                     SAL_INFO("lok", "Removed dups of [" << type << "]: [" << 
aCallbackData.getPayload() << "].");
                 break;
@@ -1872,6 +1873,7 @@ void CallbackFlushHandler::queue(const int type, 
CallbackData& aCallbackData)
             case LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED:
             case LOK_CALLBACK_A11Y_FOCUSED_CELL_CHANGED:
             case LOK_CALLBACK_COLOR_PALETTES:
+            case LOK_CALLBACK_TOOLTIP:
             {
                 if (removeAll(type))
                     SAL_INFO("lok", "Removed dups of [" << type << "]: [" << 
aCallbackData.getPayload() << "].");
@@ -1881,28 +1883,26 @@ void CallbackFlushHandler::queue(const int type, 
CallbackData& aCallbackData)
             // These are safe to use the latest state and ignore previous
             // ones (if any) since the last overrides previous ones,
             // but only if the view is the same.
+            case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+                // deleting the duplicate of visible cursor message can cause 
hyperlink popup not to show up on second/or more click on the same place.
+                // If the hyperlink is not empty we can bypass that to show 
the popup
+                if (aCallbackData.getPayload().indexOf("\"hyperlink\":\"\"") 
== -1
+                    && aCallbackData.getPayload().indexOf("\"hyperlink\": {}") 
== -1)
+                    break;
+                [[fallthrough]];
             case LOK_CALLBACK_CELL_VIEW_CURSOR:
             case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
             case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
-            case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
             case LOK_CALLBACK_TEXT_VIEW_SELECTION:
             case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
             case LOK_CALLBACK_CALC_FUNCTION_LIST:
             case LOK_CALLBACK_FORM_FIELD_BUTTON:
             {
-                // deleting the duplicate of visible cursor message can cause 
hyperlink popup not to show up on second/or more click on the same place.
-                // If the hyperlink is not empty we can bypass that to show 
the popup
-                const bool hyperLinkException = type == 
LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
-                    aCallbackData.getPayload().indexOf("\"hyperlink\":\"\"") 
== -1 &&
-                    aCallbackData.getPayload().indexOf("\"hyperlink\": {}") == 
-1;
-                if(!hyperLinkException)
-                {
-                    const int nViewId = aCallbackData.getViewId();
-                    removeAll(type, [nViewId] (const CallbackData& elemData) {
-                            return (nViewId == elemData.getViewId());
-                        }
-                    );
-                }
+                const int nViewId = aCallbackData.getViewId();
+                removeAll(type, [nViewId] (const CallbackData& elemData) {
+                        return (nViewId == elemData.getViewId());
+                    }
+                );
             }
             break;
 
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h 
b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 5eb0602e38f5..2b499b091105 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -1033,7 +1033,17 @@ typedef enum
      *
      * Payload is the log to be sent
      */
-    LOK_CALLBACK_CORE_LOG = 70
+    LOK_CALLBACK_CORE_LOG = 70,
+
+    /**
+     * Tooltips shown in the documents, like redline author and date.
+     *
+     *  {
+     *      "text": "text of tooltip",
+     *      "rectangle": "x, y, width, height"
+     *  }
+     */
+    LOK_CALLBACK_TOOLTIP = 71,
 
 }
 LibreOfficeKitCallbackType;
@@ -1205,6 +1215,8 @@ static inline const char* lokCallbackTypeToString(int 
nType)
         return "LOK_CALLBACK_A11Y_SELECTION_CHANGED";
     case LOK_CALLBACK_CORE_LOG:
         return "LOK_CALLBACK_CORE_LOG";
+    case LOK_CALLBACK_TOOLTIP:
+        return "LOK_CALLBACK_TOOLTIP";
     }
 
     assert(!"Unknown LibreOfficeKitCallbackType type.");
diff --git a/libreofficekit/source/gtk/lokdocview.cxx 
b/libreofficekit/source/gtk/lokdocview.cxx
index bd2cec88f071..f025cf99a140 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1497,6 +1497,7 @@ callback (gpointer pData)
     case LOK_CALLBACK_A11Y_EDITING_IN_SELECTION_STATE:
     case LOK_CALLBACK_A11Y_SELECTION_CHANGED:
     case LOK_CALLBACK_CORE_LOG:
+    case LOK_CALLBACK_TOOLTIP:
     {
         // TODO: Implement me
         break;
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 1df7a3b92d9a..f21457e1b16d 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -896,6 +896,9 @@ namespace
         case VclEventId::WindowMouseMove:
             
pLOKEv->mpWindow->SetLastMousePos(pLOKEv->maMouseEvent.GetPosPixel());
             pLOKEv->mpWindow->MouseMove(pLOKEv->maMouseEvent);
+            pLOKEv->mpWindow->RequestHelp(HelpEvent{
+                
pLOKEv->mpWindow->OutputToScreenPixel(pLOKEv->maMouseEvent.GetPosPixel()),
+                HelpEventMode::QUICK }); // If needed, HelpEventMode should be 
taken from a config
             break;
         case VclEventId::ExtTextInput:
         case VclEventId::EndExtTextInput:
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 2325ce93b423..7f9bb18c0498 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -114,6 +114,11 @@ protected:
     OString m_aFormFieldButton;
     OString m_aContentControl;
     OString m_ShapeSelection;
+    struct
+    {
+        std::string text;
+        std::string rect;
+    } m_aTooltip;
     TestLokCallbackWrapper m_callbackWrapper;
 };
 
@@ -301,6 +306,15 @@ void SwTiledRenderingTest::callbackImpl(int nType, const 
char* pPayload)
                 m_ShapeSelection = OString(pPayload);
             }
             break;
+        case LOK_CALLBACK_TOOLTIP:
+            {
+                std::stringstream aStream(pPayload);
+                boost::property_tree::ptree aTree;
+                boost::property_tree::read_json(aStream, aTree);
+                m_aTooltip.text = 
aTree.get_child("text").get_value<std::string>();
+                m_aTooltip.rect = 
aTree.get_child("rectangle").get_value<std::string>();
+            }
+            break;
     }
 
 }
@@ -4043,6 +4057,37 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testSavedAuthorField)
     assertXPath(pXmlDoc, 
"/root/page[1]/body/txt[1]/SwParaPortion[1]/SwLineLayout[1]/SwFieldPortion[1]"_ostr,
 "expand"_ostr, sAuthor);
 }
 
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testRedlineTooltip)
+{
+    SwXTextDocument* pXTextDoc = createDoc();
+    SwWrtShell* pWrtShell = pXTextDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+    setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
+    pWrtShell->SetRedlineFlagsAndCheckInsMode(RedlineFlags::On | 
RedlineFlags::ShowMask);
+    uno::Reference<text::XText> xText(pXTextDoc->getText(), 
uno::UNO_SET_THROW);
+    xText->insertString(xText->getEnd(), "test", /*bAbsorb=*/false);
+
+    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);
+    pXTextDoc->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE, aMiddle.getX(), 
aMiddle.getY(), 1, 0, 0);
+    Scheduler::ProcessEventsToIdle();
+
+    CPPUNIT_ASSERT(m_aTooltip.text.starts_with("Inserted: "));
+
+    std::vector<OUString> vec = 
comphelper::string::split(OUString::fromUtf8(m_aTooltip.rect), ',');
+    CPPUNIT_ASSERT_EQUAL(size_t(4), vec.size());
+    CPPUNIT_ASSERT(vec[0].toInt32() != 0);
+    CPPUNIT_ASSERT(vec[1].toInt32() != 0);
+    CPPUNIT_ASSERT(vec[2].toInt32() != 0);
+    CPPUNIT_ASSERT(vec[3].toInt32() != 0);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/docvw/edtwin2.cxx 
b/sw/source/uibase/docvw/edtwin2.cxx
index 0c47b2ec5540..b6dcfdbeb70e 100644
--- a/sw/source/uibase/docvw/edtwin2.cxx
+++ b/sw/source/uibase/docvw/edtwin2.cxx
@@ -21,6 +21,7 @@
 #include <osl/diagnose.h>
 #include <osl/thread.h>
 #include <vcl/help.hxx>
+#include <tools/json_writer.hxx>
 #include <tools/urlobj.hxx>
 #include <fmtrfmrk.hxx>
 #include <svl/urihelper.hxx>
@@ -62,6 +63,7 @@
 #include <rootfrm.hxx>
 #include <unomap.hxx>
 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 namespace {
 
@@ -309,6 +311,16 @@ OUString SwEditWin::ClipLongToolTip(const OUString& rText)
     return sDisplayText;
 }
 
+static OString getTooltipPayload(const OUString& tooltip, const SwRect& rect)
+{
+    tools::JsonWriter writer;
+    {
+        writer.put("text", tooltip);
+        writer.put("rectangle", rect.SVRect().toString());
+    }
+    return writer.finishAndGetAsOString();
+}
+
 void SwEditWin::RequestHelp(const HelpEvent &rEvt)
 {
     SwWrtShell &rSh = m_rView.GetWrtShell();
@@ -615,28 +627,36 @@ void SwEditWin::RequestHelp(const HelpEvent &rEvt)
             }
             if (!sText.isEmpty())
             {
-                tools::Rectangle aRect( aFieldRect.SVRect() );
-                Point aPt( OutputToScreenPixel( LogicToPixel( aRect.TopLeft() 
)));
-                aRect.SetLeft( aPt.X() );
-                aRect.SetTop( aPt.Y() );
-                aPt = OutputToScreenPixel( LogicToPixel( aRect.BottomRight() 
));
-                aRect.SetRight( aPt.X() );
-                aRect.SetBottom( aPt.Y() );
-
-                // tdf#136336 ensure tooltip area surrounds the current mouse 
position with at least a pixel margin
-                aRect.Union(tools::Rectangle(rEvt.GetMousePosPixel(), Size(1, 
1)));
-                aRect.AdjustLeft(-1);
-                aRect.AdjustRight(1);
-                aRect.AdjustTop(-1);
-                aRect.AdjustBottom(1);
-
-                if( bBalloon )
-                    Help::ShowBalloon( this, rEvt.GetMousePosPixel(), aRect, 
sText );
+                if (comphelper::LibreOfficeKit::isActive())
+                {
+                    m_rView.libreOfficeKitViewCallback(
+                        LOK_CALLBACK_TOOLTIP, getTooltipPayload(sText, 
aFieldRect));
+                }
                 else
                 {
-                    // the show the help
-                    OUString sDisplayText(ClipLongToolTip(sText));
-                    Help::ShowQuickHelp(this, aRect, sDisplayText, nStyle);
+                    tools::Rectangle aRect(aFieldRect.SVRect());
+                    Point 
aPt(OutputToScreenPixel(LogicToPixel(aRect.TopLeft())));
+                    aRect.SetLeft(aPt.X());
+                    aRect.SetTop(aPt.Y());
+                    aPt = 
OutputToScreenPixel(LogicToPixel(aRect.BottomRight()));
+                    aRect.SetRight(aPt.X());
+                    aRect.SetBottom(aPt.Y());
+
+                    // tdf#136336 ensure tooltip area surrounds the current 
mouse position with at least a pixel margin
+                    aRect.Union(tools::Rectangle(rEvt.GetMousePosPixel(), 
Size(1, 1)));
+                    aRect.AdjustLeft(-1);
+                    aRect.AdjustRight(1);
+                    aRect.AdjustTop(-1);
+                    aRect.AdjustBottom(1);
+
+                    if (bBalloon)
+                        Help::ShowBalloon(this, rEvt.GetMousePosPixel(), 
aRect, sText);
+                    else
+                    {
+                        // the show the help
+                        OUString sDisplayText(ClipLongToolTip(sText));
+                        Help::ShowQuickHelp(this, aRect, sDisplayText, nStyle);
+                    }
                 }
             }
 

Reply via email to