tdf#131548 Android: jump to cell

Added LOK_CALLBACK_SC_FOLLOW_JUMP: fire this signal to jump to cell
cursor in android viewer. Payload format same as
LOK_CALLBACK_INVALIDATE_TILES.

Change-Id: Ic896baccf1327d6ccdf104811446e3454a42679e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116448
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
diff --git a/android/Bootstrap/src/org/libreoffice/kit/Document.java b/android/Bootstrap/src/org/libreoffice/kit/Document.java
index 69f8f76..ed7208d 100644
--- a/android/Bootstrap/src/org/libreoffice/kit/Document.java
+++ b/android/Bootstrap/src/org/libreoffice/kit/Document.java
@@ -92,6 +92,7 @@ public class Document {
    public static final int CALLBACK_COMMENT = 32;
    public static final int CALLBACK_INVALIDATE_HEADER = 33;
    public static final int CALLBACK_CELL_ADDRESS = 34;
    public static final int CALLBACK_SC_FOLLOW_JUMP = 52;

    /**
     * Set text selection types
diff --git a/android/source/src/java/org/libreoffice/InvalidationHandler.java b/android/source/src/java/org/libreoffice/InvalidationHandler.java
index d74f150..0f3f1dd 100644
--- a/android/source/src/java/org/libreoffice/InvalidationHandler.java
+++ b/android/source/src/java/org/libreoffice/InvalidationHandler.java
@@ -55,6 +55,7 @@ public class InvalidationHandler implements Document.MessageCallback, Office.Mes
                    && messageID != Document.CALLBACK_DOCUMENT_PASSWORD
                    && messageID != Document.CALLBACK_HYPERLINK_CLICKED
                    && messageID != Document.CALLBACK_SEARCH_RESULT_SELECTION
                    && messageID != Document.CALLBACK_SC_FOLLOW_JUMP
                    && messageID != Document.CALLBACK_TEXT_SELECTION
                    && messageID != Document.CALLBACK_TEXT_SELECTION_START
                    && messageID != Document.CALLBACK_TEXT_SELECTION_END)
@@ -114,6 +115,9 @@ public class InvalidationHandler implements Document.MessageCallback, Office.Mes
            case Document.CALLBACK_CELL_CURSOR:
                invalidateCellCursor(payload);
                break;
            case Document.CALLBACK_SC_FOLLOW_JUMP:
                jumpToCell(payload);
                break;
            case Document.CALLBACK_INVALIDATE_HEADER:
                invalidateHeader();
                break;
@@ -214,6 +218,14 @@ public class InvalidationHandler implements Document.MessageCallback, Office.Mes
        }
    }

    private void jumpToCell(String payload) {
        RectF cellCursorRect = convertPayloadCellToRectangle(payload);

        if (cellCursorRect != null) {
            moveViewportToMakeSelectionVisible(cellCursorRect);
        }
    }

    /**
     * Handles the search result selection message, which is a JSONObject
     *
@@ -368,6 +380,40 @@ public class InvalidationHandler implements Document.MessageCallback, Office.Mes
        if (coordinates.length != 4) {
            return null;
        }
        return convertPayloadToRectangle(coordinates);
    }

    /**
     * Parses the payload text with rectangle coordinates and converts to rectangle in pixel coordinates
     *
     * @param payload - invalidation message payload text
     * @return rectangle in pixel coordinates
     */
    public RectF convertPayloadCellToRectangle(String payload) {
        String payloadWithoutWhitespace = payload.replaceAll("\\s", ""); // remove all whitespace from the string

        if (payloadWithoutWhitespace.isEmpty() || payloadWithoutWhitespace.equals("EMPTY")) {
            return null;
        }

        String[] coordinates = payloadWithoutWhitespace.split(",");

        if (coordinates.length != 6 ) {
            return null;
        }
        return convertPayloadToRectangle(coordinates);
    }

    /**
     * Converts rectangle coordinates to rectangle in pixel coordinates
     *
     * @param coordinates - the first four items defines the rectangle
     * @return rectangle in pixel coordinates
     */
    public RectF convertPayloadToRectangle(String[] coordinates) {
        if (coordinates.length < 4 ) {
            return null;
        }

        int x = Integer.decode(coordinates[0]);
        int y = Integer.decode(coordinates[1]);
@@ -377,10 +423,10 @@ public class InvalidationHandler implements Document.MessageCallback, Office.Mes
        float dpi = LOKitShell.getDpi(mContext);

        return new RectF(
                LOKitTileProvider.twipToPixel(x, dpi),
                LOKitTileProvider.twipToPixel(y, dpi),
                LOKitTileProvider.twipToPixel(x + width, dpi),
                LOKitTileProvider.twipToPixel(y + height, dpi)
            LOKitTileProvider.twipToPixel(x, dpi),
            LOKitTileProvider.twipToPixel(y, dpi),
            LOKitTileProvider.twipToPixel(x + width, dpi),
            LOKitTileProvider.twipToPixel(y + height, dpi)
        );
    }

diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index ae8eacd..4090fc8 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -772,6 +772,19 @@ typedef enum
     * The payload format is JSON: { "title": "title text", "content": "content text" }
     */
    LOK_CALLBACK_VALIDITY_INPUT_HELP = 51,

    /**
     * The position of the cell cursor jumped to.
     *
     * Payload format: "x, y, width, height, column, row", where the first
     * 4 numbers are document coordinates, in twips, and the last 2 are table
     * coordinates starting from 0.
     * When the cursor is not shown the payload format is the "EMPTY" string.
     *
     * Rectangle format is the same as LOK_CALLBACK_INVALIDATE_TILES.
     */
    LOK_CALLBACK_SC_FOLLOW_JUMP = 52,

}
LibreOfficeKitCallbackType;

@@ -904,6 +917,8 @@ static inline const char* lokCallbackTypeToString(int nType)
        return "LOK_CALLBACK_FORM_FIELD_BUTTON";
    case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY:
        return "LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY";
    case LOK_CALLBACK_SC_FOLLOW_JUMP:
        return "LOK_CALLBACK_SC_FOLLOW_JUMP";
    }

    assert(!"Unknown LibreOfficeKitCallbackType type.");
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 46568b8..3edc58b 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1414,6 +1414,7 @@ callback (gpointer pData)
    case LOK_CALLBACK_TAB_STOP_LIST:
    case LOK_CALLBACK_FORM_FIELD_BUTTON:
    case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY:
    case LOK_CALLBACK_SC_FOLLOW_JUMP:
    {
        // TODO: Implement me
        break;
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 5010910..e5de1d0 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -483,6 +483,9 @@ public:
    void updateKitOtherCursors() const;
    void updateOtherKitSelections() const;

    void notifyKitCellFollowJump() const;


    /// Same as MouseButtonDown(), but coordinates are in logic unit.
    virtual void LogicMouseButtonDown(const MouseEvent& rMouseEvent) override;
    /// Same as MouseButtonUp(), but coordinates are in logic unit.
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 0e52760..2ef44c4 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -4870,6 +4870,13 @@ void ScGridWindow::updateLOKValListButton( bool bVisible, const ScAddress& rPos 
    pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_VALIDITY_LIST_BUTTON, ss.str().c_str());
}

void ScGridWindow::notifyKitCellFollowJump( ) const
{
    ScTabViewShell* pViewShell = mrViewData.GetViewShell();

    pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SC_FOLLOW_JUMP, getCellCursor().getStr());
}

void ScGridWindow::UpdateListValPos( bool bVisible, const ScAddress& rPos )
{
    bool bOldButton = bListValButton;
diff --git a/sc/source/ui/view/tabvwsh3.cxx b/sc/source/ui/view/tabvwsh3.cxx
index e0b5a6e..ec1cee9 100644
--- a/sc/source/ui/view/tabvwsh3.cxx
+++ b/sc/source/ui/view/tabvwsh3.cxx
@@ -472,6 +472,8 @@ void ScTabViewShell::Execute( SfxRequest& rReq )
                        // align to cursor even if the cursor position hasn't changed,
                        // because the cursor may be set outside the visible area.
                        AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
                        if ( nSlot == SID_JUMPTOMARK && comphelper::LibreOfficeKit::isActive() )
                            rViewData.GetActiveWin()->notifyKitCellFollowJump();
                    }

                    rReq.SetReturnValue( SfxStringItem( SID_CURRENTCELL, aAddress ) );