[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - 7 commits - desktop/inc desktop/qa desktop/source include/LibreOfficeKit include/vcl sc/inc sc/qa sc/source sd/inc sd/qa sd/source sfx2/source sw/inc sw/qa sw/source vcl/inc vcl/source vcl/unx

Jan Holesovsky kendy at collabora.com
Thu Jun 16 13:43:07 UTC 2016


 desktop/inc/lib/init.hxx                       |  112 ++++++++++++++++++++++-
 desktop/qa/desktop_lib/test_desktop_lib.cxx    |    4 
 desktop/source/lib/init.cxx                    |   57 +++++++-----
 desktop/source/lib/lokinteractionhandler.cxx   |    4 
 include/LibreOfficeKit/LibreOfficeKit.h        |    4 
 include/LibreOfficeKit/LibreOfficeKit.hxx      |    6 +
 include/LibreOfficeKit/LibreOfficeKitEnums.h   |   23 ++++
 include/vcl/ITiledRenderable.hxx               |    6 +
 include/vcl/menu.hxx                           |    8 -
 sc/inc/document.hxx                            |    1 
 sc/inc/docuno.hxx                              |    3 
 sc/inc/table.hxx                               |    2 
 sc/qa/unit/tiledrendering/tiledrendering.cxx   |   18 +++
 sc/source/core/data/document.cxx               |   13 ++
 sc/source/core/data/table1.cxx                 |    5 +
 sc/source/ui/inc/gridwin.hxx                   |    2 
 sc/source/ui/unoobj/docuno.cxx                 |   17 +++
 sd/inc/sdpage.hxx                              |    1 
 sd/qa/unit/tiledrendering/tiledrendering.cxx   |   18 +++
 sd/source/core/sdpage.cxx                      |    5 +
 sd/source/ui/inc/unomodel.hxx                  |    2 
 sd/source/ui/unoidl/unomodel.cxx               |   22 ++++
 sfx2/source/menu/mnumgr.cxx                    |  118 ++++++++++++++++++++++++-
 sw/inc/unotxdoc.hxx                            |    2 
 sw/qa/extras/tiledrendering/tiledrendering.cxx |   16 +++
 sw/source/uibase/inc/edtwin.hxx                |    4 
 sw/source/uibase/uno/unotxdoc.cxx              |   17 +++
 vcl/inc/unx/gtk/gtksalmenu.hxx                 |    4 
 vcl/source/window/menu.cxx                     |   15 +--
 vcl/unx/gtk/gtksalmenu.cxx                     |   10 --
 30 files changed, 462 insertions(+), 57 deletions(-)

New commits:
commit db54f76efcc3b3b74c02ae7ea2259abd42d05189
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Thu Apr 21 19:04:58 2016 +0200

    lok: getPartHash should be at the end, it is a new API call.
    
    Also add it to the init.cxx so that it is actually used.
    
    (cherry picked from commit b74163742ff1288ad9ea1ec8e83ac08faf686893)
    
    Change-Id: I255411158d0822718116ac05aad1ee925a9a7a9a

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 4fa84fd..10125a2 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -380,6 +380,7 @@ static unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
                           const char *pFontName,
                           int* pFontWidth,
                           int* pFontHeight);
+static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart);
 
 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent)
     : mxComponent(xComponent)
@@ -399,7 +400,6 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
         m_pDocumentClass->setPart = doc_setPart;
         m_pDocumentClass->getPartName = doc_getPartName;
         m_pDocumentClass->setPartMode = doc_setPartMode;
-        m_pDocumentClass->renderFont = doc_renderFont;
         m_pDocumentClass->paintTile = doc_paintTile;
         m_pDocumentClass->getTileMode = doc_getTileMode;
         m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
@@ -423,6 +423,9 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
         m_pDocumentClass->getView = doc_getView;
         m_pDocumentClass->getViews = doc_getViews;
 
+        m_pDocumentClass->renderFont = doc_renderFont;
+        m_pDocumentClass->getPartHash = doc_getPartHash;
+
         gDocumentClass = m_pDocumentClass;
     }
     pClass = m_pDocumentClass.get();
@@ -916,6 +919,23 @@ static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart)
 
 }
 
+static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart)
+{
+    ITiledRenderable* pDoc = getTiledRenderable(pThis);
+    if (!pDoc)
+    {
+        gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
+        return nullptr;
+    }
+
+    OUString sHash = pDoc->getPartHash(nPart);
+    OString aString = OUStringToOString(sHash, RTL_TEXTENCODING_UTF8);
+    char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
+    strcpy(pMemory, aString.getStr());
+    return pMemory;
+
+}
+
 static void doc_setPartMode(LibreOfficeKitDocument* pThis,
                             int nPartMode)
 {
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index d66028a..be833db 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -116,10 +116,6 @@ struct _LibreOfficeKitDocumentClass
     char* (*getPartName) (LibreOfficeKitDocument* pThis,
                           int nPart);
 
-    /// @see lok::Document::getPartHash().
-    char* (*getPartHash) (LibreOfficeKitDocument* pThis,
-                          int nPart);
-
     /// @see lok::Document::setPartMode().
     void (*setPartMode) (LibreOfficeKitDocument* pThis,
                          int nMode);
@@ -226,6 +222,10 @@ struct _LibreOfficeKitDocumentClass
                        const char* pFontName,
                        int* pFontWidth,
                        int* pFontHeight);
+
+    /// @see lok::Document::getPartHash().
+    char* (*getPartHash) (LibreOfficeKitDocument* pThis,
+                          int nPart);
 #endif // LOK_USE_UNSTABLE_API
 };
 
commit 9c8cd262837f8324d8a4138d551d99d5c7b87816
Author: Henry Castro <hcastro at collabora.com>
Date:   Wed Apr 20 13:52:31 2016 -0400

    lokit: add getPartHash
    
    In the tiled rendering case, the slides, no matter
    if it is inserted or deleted, the part names always return
    sequential names i.e. Slide 1, Slide 2, ..., Slide N.
    
    However the client side needs to know what slides had been
    deleted or inserted, so it is necessary to send the hash codes.
    
    Reviewed-on: https://gerrit.libreoffice.org/24267
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    (cherry picked from commit 1a74c6333a79ccf0579b33ebc42ce2ccc23ccadb)
    
    Change-Id: I0e9caeec660c3e42dd9f751bdce7690f9ad365a1

diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index 4feaaf7..d66028a 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -116,6 +116,10 @@ struct _LibreOfficeKitDocumentClass
     char* (*getPartName) (LibreOfficeKitDocument* pThis,
                           int nPart);
 
+    /// @see lok::Document::getPartHash().
+    char* (*getPartHash) (LibreOfficeKitDocument* pThis,
+                          int nPart);
+
     /// @see lok::Document::setPartMode().
     void (*setPartMode) (LibreOfficeKitDocument* pThis,
                          int nMode);
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index 8128090..b9d36cf 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -116,6 +116,12 @@ public:
         return mpDoc->pClass->getPartName(mpDoc, nPart);
     }
 
+    /// Get the current part's hash.
+    inline char* getPartHash(int nPart)
+    {
+        return mpDoc->pClass->getPartHash(mpDoc, nPart);
+    }
+
     inline void setPartMode(int nMode)
     {
         mpDoc->pClass->setPartMode(mpDoc, nMode);
diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index 87b2dff..94902bf 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -84,6 +84,12 @@ public:
         return OUString("");
     }
 
+    /**
+     * Get the hash of the currently displayed part, i.e. sheet in a spreadsheet
+     * or slide in a presentation.
+     */
+    virtual OUString getPartHash(int nPart) = 0;
+
     /// @see lok::Document::setPartMode().
     virtual void setPartMode(int nPartMode)
     {
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 16db763..f5e2f87 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -605,6 +605,7 @@ public:
     SC_DLLPUBLIC void           SetVisibleTab(SCTAB nTab)   { nVisibleTab = nTab; }
 
     SC_DLLPUBLIC bool HasTable( SCTAB nTab ) const;
+    SC_DLLPUBLIC bool GetHashCode( SCTAB nTab, sal_Int64& rHashCode) const;
     SC_DLLPUBLIC bool GetName( SCTAB nTab, OUString& rName ) const;
     SC_DLLPUBLIC bool GetCodeName( SCTAB nTab, OUString& rName ) const;
     SC_DLLPUBLIC bool SetCodeName( SCTAB nTab, const OUString& rName );
diff --git a/sc/inc/docuno.hxx b/sc/inc/docuno.hxx
index f4430e5..f010b06 100644
--- a/sc/inc/docuno.hxx
+++ b/sc/inc/docuno.hxx
@@ -375,6 +375,9 @@ public:
     /// @see vcl::ITiledRenderable::getPartName().
     virtual OUString getPartName(int nPart) override;
 
+    /// @see vcl::ITiledRenderable::getPartHash().
+    virtual OUString getPartHash( int nPart ) override;
+
     /// @see vcl::ITiledRenderable::initializeForTiledRendering().
     virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 9efd590..4d25a47 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -293,6 +293,8 @@ public:
     void        SetLink( ScLinkMode nMode, const OUString& rDoc, const OUString& rFlt,
                         const OUString& rOpt, const OUString& rTab, sal_uLong nRefreshDelay );
 
+    sal_Int64   GetHashCode () const;
+
     void        GetName( OUString& rName ) const;
     void        SetName( const OUString& rNewName );
 
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 1843357..e9cba5a 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -48,12 +48,14 @@ public:
 #if !defined(WNT) && !defined(MACOSX)
     void testRowColumnSelections();
     void testSortAscendingDescending();
+    void testPartHash();
 #endif
 
     CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
 #if !defined(WNT) && !defined(MACOSX)
     CPPUNIT_TEST(testRowColumnSelections);
     CPPUNIT_TEST(testSortAscendingDescending);
+    CPPUNIT_TEST(testPartHash);
 #endif
     CPPUNIT_TEST_SUITE_END();
 
@@ -251,6 +253,22 @@ void ScTiledRenderingTest::testSortAscendingDescending()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void ScTiledRenderingTest::testPartHash()
+{
+    comphelper::LibreOfficeKit::setActive();
+    ScModelObj* pModelObj = createDoc("sort-range.ods");
+
+    int nParts = pModelObj->getParts();
+    for (int it = 0; it < nParts; it++)
+    {
+        CPPUNIT_ASSERT(!pModelObj->getPartHash(it).isEmpty());
+    }
+
+    // check part that it does not exists
+    CPPUNIT_ASSERT(pModelObj->getPartHash(100).isEmpty());
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 #endif
 
 CPPUNIT_TEST_SUITE_REGISTRATION(ScTiledRenderingTest);
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index dc2aeb3..4deb5da 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -193,6 +193,19 @@ bool ScDocument::HasTable( SCTAB nTab ) const
     return false;
 }
 
+bool ScDocument::GetHashCode( SCTAB nTab, sal_Int64& rHashCode ) const
+{
+    if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
+    {
+        if (maTabs[nTab])
+        {
+            rHashCode = maTabs[nTab]->GetHashCode();
+            return true;
+        }
+    }
+    return false;
+}
+
 bool ScDocument::GetName( SCTAB nTab, OUString& rName ) const
 {
     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index df05e22..105aa16 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -354,6 +354,11 @@ ScTable::~ScTable()
         aCol[k].PrepareBroadcastersForDestruction();
 }
 
+sal_Int64 ScTable::GetHashCode() const
+{
+    return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
+}
+
 void ScTable::GetName( OUString& rName ) const
 {
     rName = aName;
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 372d44e..37fab3df 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -522,6 +522,13 @@ OUString ScModelObj::getPartName( int nPart )
     return sTabName;
 }
 
+OUString ScModelObj::getPartHash( int nPart )
+{
+    sal_Int64 nHashCode;
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    return (pViewData->GetDocument()->GetHashCode(nPart, nHashCode) ? OUString::number(nHashCode) : OUString());
+}
+
 Size ScModelObj::getDocumentSize()
 {
     Size aSize(10, 10); // minimum size
diff --git a/sd/inc/sdpage.hxx b/sd/inc/sdpage.hxx
index a7d6097..a62463d 100644
--- a/sd/inc/sdpage.hxx
+++ b/sd/inc/sdpage.hxx
@@ -179,6 +179,7 @@ public:
     OUString        GetPresObjText(PresObjKind eObjKind) const;
     SfxStyleSheet* GetStyleSheetForMasterPageBackground() const;
     SfxStyleSheet*  GetStyleSheetForPresObj(PresObjKind eObjKind) const;
+    sal_Int64       GetHashCode() const;
     bool            RestoreDefaultText( SdrObject* pObj );
 
     /** @return true if the given SdrObject is inside the presentation object list */
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 871c8a2..5e7acf1 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -63,6 +63,7 @@ public:
     void testResizeTableColumn();
     void testSearchAllNotifications();
     void testSearchAllFollowedBySearch();
+    void testPartHash();
 #endif
 
     CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
@@ -82,6 +83,7 @@ public:
     CPPUNIT_TEST(testResizeTableColumn);
     CPPUNIT_TEST(testSearchAllNotifications);
     CPPUNIT_TEST(testSearchAllFollowedBySearch);
+    CPPUNIT_TEST(testPartHash);
 #endif
     CPPUNIT_TEST_SUITE_END();
 
@@ -753,6 +755,22 @@ void SdTiledRenderingTest::testInsertDeletePage()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SdTiledRenderingTest::testPartHash()
+{
+    comphelper::LibreOfficeKit::setActive();
+    SdXImpressDocument* pDoc = createDoc("dummy.odp");
+
+    int nParts = pDoc->getParts();
+    for (int it = 0; it < nParts; it++)
+    {
+        CPPUNIT_ASSERT(!pDoc->getPartHash(it).isEmpty());
+    }
+
+    // check part that it does not exists
+    CPPUNIT_ASSERT(pDoc->getPartHash(100).isEmpty());
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 #endif
 
 CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);
diff --git a/sd/source/core/sdpage.cxx b/sd/source/core/sdpage.cxx
index f140cca..7c56516 100644
--- a/sd/source/core/sdpage.cxx
+++ b/sd/source/core/sdpage.cxx
@@ -2698,6 +2698,11 @@ SdPage* SdPage::getImplementation( const css::uno::Reference< css::drawing::XDra
     return nullptr;
 }
 
+sal_Int64 SdPage::GetHashCode() const
+{
+    return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
+}
+
 void SdPage::SetName (const OUString& rName)
 {
     OUString aOldName( GetName() );
diff --git a/sd/source/ui/inc/unomodel.hxx b/sd/source/ui/inc/unomodel.hxx
index fe09a74..8f144a2 100644
--- a/sd/source/ui/inc/unomodel.hxx
+++ b/sd/source/ui/inc/unomodel.hxx
@@ -241,6 +241,8 @@ public:
     virtual int  getPart() override;
     virtual int  getParts() override;
     virtual OUString getPartName( int nPart ) override;
+    virtual OUString getPartHash( int nPart ) override;
+
     virtual void setPartMode( int nPartMode ) override;
 
     /// @see vcl::ITiledRenderable::initializeForTiledRendering().
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 0eafe10..66dd6d0 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2328,6 +2328,18 @@ OUString SdXImpressDocument::getPartName( int nPart )
     return pPage->GetName();
 }
 
+OUString SdXImpressDocument::getPartHash( int nPart )
+{
+    SdPage* pPage = mpDoc->GetSdPage( nPart, PK_STANDARD );
+    if (!pPage)
+    {
+        SAL_WARN("sd", "DrawViewShell not available!");
+        return OUString();
+    }
+
+    return OUString::number(pPage->GetHashCode());
+}
+
 void SdXImpressDocument::setPartMode( int nPartMode )
 {
     DrawViewShell* pViewSh = GetViewShell();
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index 81dd85e..cffdb64 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -413,6 +413,8 @@ public:
     virtual int getPart() override;
     /// @see vcl::ITiledRenderable::getPartName().
     virtual OUString getPartName(int nPart) override;
+    /// @see vcl::ITiledRenderable::getPartHash().
+    virtual OUString getPartHash(int nPart) override;
     /// @see vcl::ITiledRenderable::initializeForTiledRendering().
     virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
     /// @see vcl::ITiledRenderable::registerCallback().
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index ed2c22f..ed9cf71 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -49,6 +49,7 @@ public:
     void testSearchAll();
     void testSearchAllNotifications();
     void testPageDownInvalidation();
+    void testPartHash();
 
     CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -66,6 +67,7 @@ public:
     CPPUNIT_TEST(testSearchAll);
     CPPUNIT_TEST(testSearchAllNotifications);
     CPPUNIT_TEST(testPageDownInvalidation);
+    CPPUNIT_TEST(testPartHash);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -511,6 +513,20 @@ void SwTiledRenderingTest::testPageDownInvalidation()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SwTiledRenderingTest::testPartHash()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    SwXTextDocument* pXTextDocument = createDoc("pagedown-invalidation.odt");
+    int nParts = pXTextDocument->getParts();
+    for (int it = 0; it < nParts; it++)
+    {
+        CPPUNIT_ASSERT(!pXTextDocument->getPartHash(it).isEmpty());
+    }
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index d276c54..1cd8593 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3224,6 +3224,14 @@ OUString SwXTextDocument::getPartName(int nPart)
     return OUString(SW_RES(STR_PAGE)) + OUString::number(nPart + 1);
 }
 
+OUString SwXTextDocument::getPartHash(int nPart)
+{
+    SolarMutexGuard aGuard;
+    OUString sPart(OUString(SW_RES(STR_PAGE)) + OUString::number(nPart + 1));
+
+    return OUString::number(sPart.hashCode());
+}
+
 void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
 {
     SolarMutexGuard aGuard;
commit f9999c3186393e7b3bb9d1911f7d8181979abf0f
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Tue Apr 19 21:26:42 2016 -0400

    New LOKDocument callback queue to flush events lazily on idle
    
    Since desktop now queues up callback notifications
    and flushes them to the client on idle, the
    unit-tests must yield and process all tasks
    before they validate post-conditions.
    
    (cherry picked from commit e6a429770bde5da75239961ae88c06c78cfa5686)
    (cherry picked from commit 1f278848117080cd6e819f04ba428be52416af7c)
    (cherry picked from commit 6ca6f22777eb3651109cbf403577d0022a735c9b)
    (cherry picked from commit 548faf728cf097d93c3f6478ceea5f8747e789c6)
    
    Reviewed-on: https://gerrit.libreoffice.org/24377
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit c327bb5c88573c96f22e9a8cfc4b8a733ae6b671)
    
    Change-Id: I78307db29a9ce647ffaed3539f953227c605968e

diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index d077297..0f5943a 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -10,24 +10,126 @@
 #ifndef INCLUDED_DESKTOP_INC_LIB_INIT_HXX
 #define INCLUDED_DESKTOP_INC_LIB_INIT_HXX
 
+#include <map>
+#include <memory>
+#include <mutex>
+
+#include <osl/thread.h>
+#include <vcl/idle.hxx>
 #include <LibreOfficeKit/LibreOfficeKit.h>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/lang/XComponent.hpp>
-#include <memory>
-#include <map>
+
 #include "../../source/inc/desktopdllapi.h"
-#include <osl/thread.h>
 
 class LOKInteractionHandler;
 
 namespace desktop {
+
+    class CallbackFlushHandler : public Idle
+    {
+    public:
+        explicit CallbackFlushHandler(LibreOfficeKitCallback pCallback, void* pData)
+            : Idle( "lokit timer callback" ),
+              m_pCallback(pCallback),
+              m_pData(pData)
+        {
+            SetPriority(SchedulerPriority::POST_PAINT);
+
+            // Add the states that are safe to skip duplicates on,
+            // even when not consequent.
+            m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL");
+            m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL");
+            m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL");
+
+            Start();
+        }
+
+        virtual ~CallbackFlushHandler()
+        {
+            Stop();
+
+            // We might have important notification (.uno:save?).
+            flush();
+        }
+
+        virtual void Invoke() override
+        {
+            flush();
+        }
+
+        static
+        void callback(const int type, const char* payload, void* data)
+        {
+            CallbackFlushHandler* self = reinterpret_cast<CallbackFlushHandler*>(data);
+            if (self)
+            {
+                self->queue(type, payload);
+            }
+        }
+
+        void queue(const int type, const char* data)
+        {
+            const std::string payload(data ? data : "(nil)");
+            std::unique_lock<std::mutex> lock(m_mutex);
+
+            const auto stateIt = m_states.find(type);
+            if (stateIt != m_states.end())
+            {
+                // If the state didn't change, it's safe to ignore.
+                if (stateIt->second == payload)
+                {
+                    return;
+                }
+
+                stateIt->second = payload;
+            }
+
+            if (type == LOK_CALLBACK_INVALIDATE_TILES &&
+                !m_queue.empty() && std::get<0>(m_queue.back()) == type && std::get<1>(m_queue.back()) == payload)
+            {
+                // Supress duplicate invalidation only when they are in sequence.
+                return;
+            }
+
+            m_queue.emplace_back(type, payload);
+
+            lock.unlock();
+            if (!IsActive())
+            {
+                Start();
+            }
+        }
+
+    private:
+        void flush()
+        {
+            if (m_pCallback)
+            {
+                std::unique_lock<std::mutex> lock(m_mutex);
+                for (auto& pair : m_queue)
+                {
+                    m_pCallback(std::get<0>(pair), std::get<1>(pair).c_str(), m_pData);
+                }
+
+                m_queue.clear();
+            }
+        }
+
+    private:
+        std::vector<std::tuple<int, std::string>> m_queue;
+        std::map<int, std::string> m_states;
+        LibreOfficeKitCallback m_pCallback;
+        void *m_pData;
+        std::mutex m_mutex;
+    };
+
     struct DESKTOP_DLLPUBLIC LibLODocument_Impl : public _LibreOfficeKitDocument
     {
         css::uno::Reference<css::lang::XComponent> mxComponent;
         std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass;
-        LibreOfficeKitCallback mpCallback;
-        void *mpCallbackData;
+        std::shared_ptr<CallbackFlushHandler> mpCallbackFlushHandler;
 
         explicit LibLODocument_Impl(const css::uno::Reference <css::lang::XComponent> &xComponent);
         ~LibLODocument_Impl();
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index dc1282f..2ad43c0 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -317,6 +317,7 @@ void DesktopLOKTest::testSearchCalc()
         {"SearchItem.Command", uno::makeAny(static_cast<sal_uInt16>(SvxSearchCmd::FIND_ALL))},
     }));
     comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
+    Scheduler::ProcessEventsToIdle();
 
     std::vector<OString> aSelections;
     sal_Int32 nIndex = 0;
@@ -590,6 +591,7 @@ void DesktopLOKTest::testCommandResult()
     // the condition var.
     m_aCommandResultCondition.reset();
     pDocument->pClass->postUnoCommand(pDocument, ".uno:Bold", nullptr, true);
+    Scheduler::ProcessEventsToIdle();
     m_aCommandResultCondition.wait(aTimeValue);
 
     CPPUNIT_ASSERT(m_aCommandResult.isEmpty());
@@ -599,6 +601,7 @@ void DesktopLOKTest::testCommandResult()
 
     m_aCommandResultCondition.reset();
     pDocument->pClass->postUnoCommand(pDocument, ".uno:Bold", nullptr, true);
+    Scheduler::ProcessEventsToIdle();
     m_aCommandResultCondition.wait(aTimeValue);
 
     boost::property_tree::ptree aTree;
@@ -621,6 +624,7 @@ void DesktopLOKTest::testWriterComments()
     TimeValue aTimeValue = {2 , 0}; // 2 seconds max
     m_aCommandResultCondition.reset();
     pDocument->pClass->postUnoCommand(pDocument, ".uno:InsertAnnotation", nullptr, true);
+    Scheduler::ProcessEventsToIdle();
     m_aCommandResultCondition.wait(aTimeValue);
     CPPUNIT_ASSERT(!m_aCommandResult.isEmpty());
     xToolkit->reschedule();
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 2a079dd..4fa84fd 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -383,8 +383,6 @@ static unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
 
 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent)
     : mxComponent(xComponent)
-    , mpCallback(nullptr)
-    , mpCallbackData(nullptr)
 {
     if (!(m_pDocumentClass = gDocumentClass.lock()))
     {
@@ -953,11 +951,11 @@ static void doc_setPartMode(LibreOfficeKitDocument* pThis,
     }
 }
 
-void doc_paintTile (LibreOfficeKitDocument* pThis,
-                    unsigned char* pBuffer,
-                    const int nCanvasWidth, const int nCanvasHeight,
-                    const int nTilePosX, const int nTilePosY,
-                    const int nTileWidth, const int nTileHeight)
+void doc_paintTile(LibreOfficeKitDocument* pThis,
+                   unsigned char* pBuffer,
+                   const int nCanvasWidth, const int nCanvasHeight,
+                   const int nTilePosX, const int nTilePosY,
+                   const int nTileWidth, const int nTileHeight)
 {
     SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth << "x" << nTileHeight <<
               "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
@@ -1065,13 +1063,12 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
 {
     LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
 
-    pDocument->mpCallback = pCallback;
-    pDocument->mpCallbackData = pData;
+    pDocument->mpCallbackFlushHandler.reset(new CallbackFlushHandler(pCallback, pData));
 
     if (comphelper::LibreOfficeKit::isViewCallback())
     {
         if (SfxViewShell* pViewShell = SfxViewFrame::Current()->GetViewShell())
-            pViewShell->registerLibreOfficeKitViewCallback(pCallback, pData);
+            pViewShell->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandler.get());
     }
     else
     {
@@ -1082,7 +1079,7 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
             return;
         }
 
-        pDoc->registerCallback(pCallback, pData);
+        pDoc->registerCallback(CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandler.get());
     }
 }
 
@@ -1108,14 +1105,12 @@ static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nChar
 class DispatchResultListener : public cppu::WeakImplHelper<css::frame::XDispatchResultListener>
 {
     OString maCommand;                 ///< Command for which this is the result.
-    LibreOfficeKitCallback mpCallback; ///< Callback to call.
-    void* mpCallbackData;              ///< The callback's data.
+    std::shared_ptr<CallbackFlushHandler> mpCallback; ///< Callback to call.
 
 public:
-    DispatchResultListener(const char* pCommand, LibreOfficeKitCallback pCallback, void* pCallbackData)
+    DispatchResultListener(const char* pCommand, std::shared_ptr<CallbackFlushHandler>& pCallback)
         : maCommand(pCommand)
         , mpCallback(pCallback)
-        , mpCallbackData(pCallbackData)
     {
         assert(mpCallback);
     }
@@ -1136,7 +1131,7 @@ public:
 
         std::stringstream aStream;
         boost::property_tree::write_json(aStream, aTree);
-        mpCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, strdup(aStream.str().c_str()), mpCallbackData);
+        mpCallback->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, strdup(aStream.str().c_str()));
     }
 
     virtual void SAL_CALL disposing(const css::lang::EventObject&) throw (css::uno::RuntimeException, std::exception) override {}
@@ -1165,10 +1160,10 @@ static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pComma
 
     bool bResult = false;
 
-    if (bNotifyWhenFinished && pDocument->mpCallback)
+    if (bNotifyWhenFinished && pDocument->mpCallbackFlushHandler)
     {
         bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector),
-                new DispatchResultListener(pCommand, pDocument->mpCallback, pDocument->mpCallbackData));
+                new DispatchResultListener(pCommand, pDocument->mpCallbackFlushHandler));
     }
     else
         bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector));
@@ -1200,9 +1195,9 @@ static void doc_postMouseEvent(LibreOfficeKitDocument* pThis, int nType, int nX,
     }
 
     LibLODocument_Impl* pLib = static_cast<LibLODocument_Impl*>(pThis);
-    if (pLib->mpCallback && pLib->mpCallbackData)
+    if (pLib->mpCallbackFlushHandler)
     {
-        pLib->mpCallback(LOK_CALLBACK_MOUSE_POINTER, aPointerString.getStr(), pLib->mpCallbackData);
+        pLib->mpCallbackFlushHandler->queue(LOK_CALLBACK_MOUSE_POINTER, aPointerString.getStr());
     }
 }
 
diff --git a/desktop/source/lib/lokinteractionhandler.cxx b/desktop/source/lib/lokinteractionhandler.cxx
index e4c3ee5..a1e5568 100644
--- a/desktop/source/lib/lokinteractionhandler.cxx
+++ b/desktop/source/lib/lokinteractionhandler.cxx
@@ -115,8 +115,8 @@ void LOKInteractionHandler::postError(css::task::InteractionClassification class
     std::stringstream aStream;
     boost::property_tree::write_json(aStream, aTree);
 
-    if (m_pLOKDocument && m_pLOKDocument->mpCallback)
-        m_pLOKDocument->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKDocument->mpCallbackData);
+    if (m_pLOKDocument && m_pLOKDocument->mpCallbackFlushHandler)
+        m_pLOKDocument->mpCallbackFlushHandler->queue(LOK_CALLBACK_ERROR, aStream.str().c_str());
     else if (m_pLOKit->mpCallback)
         m_pLOKit->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKit->mpCallbackData);
 }
commit f1da122d64f434d027909218709e86d46936a3b1
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Apr 8 16:35:57 2016 +0200

    lok context menu: Handle the case we only get the slot-id.
    
    Change-Id: I7a2537ccebf80c79bf61f041bfb18cd6ddc93ca2
    (cherry picked from commit 421a67af7ee2ffcd4faa53866482cb96a444b8a9)

diff --git a/sfx2/source/menu/mnumgr.cxx b/sfx2/source/menu/mnumgr.cxx
index 788dc32..7ea4dd8 100644
--- a/sfx2/source/menu/mnumgr.cxx
+++ b/sfx2/source/menu/mnumgr.cxx
@@ -361,7 +361,14 @@ namespace {
             else
             {
                 const sal_uInt16 nItemId = pMenu->GetItemId(nPos);
-                const OUString aCommandURL = pMenu->GetItemCommand(nItemId);
+                OUString aCommandURL = pMenu->GetItemCommand(nItemId);
+
+                if (aCommandURL.isEmpty())
+                {
+                    const SfxSlot *pSlot = SFX_SLOTPOOL().GetSlot(nItemId);
+                    if (pSlot)
+                        aCommandURL = pSlot->GetCommandString();
+                }
 
                 const OUString aItemText = pMenu->GetItemText(nItemId);
                 Menu* pPopupSubmenu = pMenu->GetPopupMenu(nItemId);
commit 5836276910b84d62d46b9e996f3bb5f94563a02e
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Apr 8 09:15:55 2016 +0200

    lok context menu: Expose the disabled commands too.
    
    OTOH, don't show choices that don't have the .uno: command, we have no way to
    handle them.
    
    Change-Id: I0df6ffe2049bbf11ba4b8931164be6a3381d3916
    (cherry picked from commit 728233b1afccbb27ee09994aaceea840d5537284)

diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 88098b1..c1d8508 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -284,15 +284,22 @@ typedef enum
     /**
      * Context menu structure
      *
-     * Returns the structure of context menu
+     * Returns the structure of context menu.  Contains all the separators &
+     * submenus, example of the returned structure:
      *
      * {
-     *      "menu": [
-     *          {"text": "label text", "type": "command | separator | menu",
-     *      "command | menu": "..." },
-     *          ...
-     *      ]
+     *     "menu": [
+     *         { "text": "label text1", "type": "command", "command": ".uno:Something1", "enabled": "true" },
+     *         { "text": "label text2", "type": "command", "command": ".uno:Something2", "enabled": "false" },
+     *         { "type": "separator" },
+     *         { "text": "label text2", "type": "menu", "menu": [ { ... }, { ... }, ... ] },
+     *         ...
+     *     ]
      * }
+     *
+     * The 'command' can additionally have a checkable status, like:
+     *
+     *     {"text": "label text3", "type": "command", "command": ".uno:Something3", "checktype": "checkmark|radio|auto", "checked": "true|false"}
      */
     LOK_CALLBACK_CONTEXT_MENU,
 
diff --git a/sfx2/source/menu/mnumgr.cxx b/sfx2/source/menu/mnumgr.cxx
index e0da916..788dc32 100644
--- a/sfx2/source/menu/mnumgr.cxx
+++ b/sfx2/source/menu/mnumgr.cxx
@@ -366,57 +366,44 @@ namespace {
                 const OUString aItemText = pMenu->GetItemText(nItemId);
                 Menu* pPopupSubmenu = pMenu->GetPopupMenu(nItemId);
 
-                if (!pMenu->IsItemEnabled(nItemId))
-                    continue;
-
                 if (!aItemText.isEmpty())
-                    aItemTree.put("text", std::string(aItemText.toUtf8().getStr()));
+                    aItemTree.put("text", aItemText.toUtf8().getStr());
 
                 if (pPopupSubmenu)
                 {
                     boost::property_tree::ptree aSubmenu = fillPopupMenu(pPopupSubmenu);
-                    if (!aSubmenu.empty())
-                    {
-                        aItemTree.put("type", "menu");
-                        aItemTree.push_back(std::make_pair("menu", aSubmenu));
-                    }
-                    else
-                        aItemTree.clear();
+                    if (aSubmenu.empty())
+                        continue;
+
+                    aItemTree.put("type", "menu");
+                    aItemTree.push_back(std::make_pair("menu", aSubmenu));
                 }
                 else
                 {
-                    if (!aCommandURL.isEmpty())
-                    {
-                        aItemTree.put("type", "command");
-                        aItemTree.put("command", std::string(aCommandURL.toUtf8().getStr()));
-                    }
+                    // no point in exposing choices that don't have the .uno:
+                    // command
+                    if (aCommandURL.isEmpty())
+                        continue;
+
+                    aItemTree.put("type", "command");
+                    aItemTree.put("command", aCommandURL.toUtf8().getStr());
                 }
 
+                aItemTree.put("enabled", pMenu->IsItemEnabled(nItemId));
+
                 MenuItemBits aItemBits = pMenu->GetItemBits(nItemId);
-                bool bHasChecks = false;
+                bool bHasChecks = true;
                 if (aItemBits & MenuItemBits::CHECKABLE)
-                {
                     aItemTree.put("checktype", "checkmark");
-                    bHasChecks = true;
-                }
                 else if (aItemBits & MenuItemBits::RADIOCHECK)
-                {
                     aItemTree.put("checktype", "radio");
-                    bHasChecks = true;
-                }
                 else if (aItemBits & MenuItemBits::AUTOCHECK)
-                {
                     aItemTree.put("checktype", "auto");
-                    bHasChecks = true;
-                }
+                else
+                    bHasChecks = false;
 
                 if (bHasChecks)
-                {
-                    if (pMenu->IsItemChecked(nItemId))
-                        aItemTree.put("checked", "true");
-                    else
-                        aItemTree.put("checked", "false");
-                }
+                    aItemTree.put("checked", pMenu->IsItemChecked(nItemId));
             }
 
             if (!aItemTree.empty())
commit 91f8ce601f6c128317837b8aa3dd2c7ce6388acd
Author: Pranav Kant <pranavk at collabora.com>
Date:   Thu Mar 31 14:47:27 2016 +0530

    lok context menu: Expose context menu
    
    (cherry picked from commit 6be044e919d28b93332f04bdc18f6def2925b098)
    
    Change-Id: I0968689630e10f838c075e86357eb36a9a220d0d

diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 343d169..88098b1 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -280,6 +280,22 @@ typedef enum
      * }
      */
     LOK_CALLBACK_ERROR,
+
+    /**
+     * Context menu structure
+     *
+     * Returns the structure of context menu
+     *
+     * {
+     *      "menu": [
+     *          {"text": "label text", "type": "command | separator | menu",
+     *      "command | menu": "..." },
+     *          ...
+     *      ]
+     * }
+     */
+    LOK_CALLBACK_CONTEXT_MENU,
+
 }
 LibreOfficeKitCallbackType;
 
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 4e0172e..017ca86 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -296,7 +296,6 @@ protected:
     virtual void    LoseFocus() override;
 
     virtual void    RequestHelp( const HelpEvent& rEvt ) override;
-    virtual void    Command( const CommandEvent& rCEvt ) override;
 
     virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
     virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
@@ -314,6 +313,7 @@ public:
     rtl::Reference<sdr::overlay::OverlayManager> getOverlayManager();
     void flushOverlayManager();
 
+    virtual void    Command( const CommandEvent& rCEvt ) override;
     virtual void    DataChanged( const DataChangedEvent& rDCEvt ) override;
 
     virtual void    MouseButtonDown( const MouseEvent& rMEvt ) override;
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 3c5779c..372d44e 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -596,13 +596,21 @@ void ScModelObj::postMouseEvent(int nType, int nX, int nY, int nCount, int nButt
                        Fraction(nTilePixelHeight * TWIPS_PER_PIXEL, nTileTwipHeight), true);
 
     // Calc operates in pixels...
-    MouseEvent aEvent(Point(nX * pViewData->GetPPTX(), nY * pViewData->GetPPTY()), nCount,
+    Point aPos(nX * pViewData->GetPPTX(), nY * pViewData->GetPPTY());
+    MouseEvent aEvent(aPos, nCount,
             MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
 
     switch (nType)
     {
     case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
         pGridWindow->MouseButtonDown(aEvent);
+
+        // Invoke the context menu
+        if (nButtons & MOUSE_RIGHT)
+        {
+            const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu, true, nullptr);
+            pGridWindow->Command(aCEvt);
+        }
         break;
     case LOK_MOUSEEVENT_MOUSEBUTTONUP:
         pGridWindow->MouseButtonUp(aEvent);
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 0a26a84..0eafe10 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2446,16 +2446,24 @@ void SdXImpressDocument::postMouseEvent(int nType, int nX, int nY, int nCount, i
     SolarMutexGuard aGuard;
 
     DrawViewShell* pViewShell = GetViewShell();
+    Window* pWindow = pViewShell->GetActiveWindow();
     if (!pViewShell)
         return;
 
-    MouseEvent aEvent(Point(convertTwipToMm100(nX), convertTwipToMm100(nY)), nCount,
+    Point aPos(Point(convertTwipToMm100(nX), convertTwipToMm100(nY)));
+    MouseEvent aEvent(aPos, nCount,
             MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
 
     switch (nType)
     {
     case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
         pViewShell->LogicMouseButtonDown(aEvent);
+
+        if (nButtons & MOUSE_RIGHT)
+        {
+            const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu, true, nullptr);
+            pViewShell->Command(aCEvt, pWindow);
+        }
         break;
     case LOK_MOUSEEVENT_MOUSEBUTTONUP:
         pViewShell->LogicMouseButtonUp(aEvent);
diff --git a/sfx2/source/menu/mnumgr.cxx b/sfx2/source/menu/mnumgr.cxx
index 0a97499..e0da916 100644
--- a/sfx2/source/menu/mnumgr.cxx
+++ b/sfx2/source/menu/mnumgr.cxx
@@ -17,6 +17,8 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include <boost/property_tree/json_parser.hpp>
+
 #include <com/sun/star/embed/VerbDescriptor.hpp>
 #include <com/sun/star/embed/VerbAttributes.hpp>
 #include <com/sun/star/container/XNamed.hpp>
@@ -64,6 +66,9 @@
 #include <sfx2/objface.hxx>
 #include "thessubmenu.hxx"
 
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+
 // static member initialization
 PopupMenu * SfxPopupMenuManager::pStaticThesSubMenu = nullptr;
 
@@ -327,6 +332,105 @@ SfxPopupMenuManager* SfxPopupMenuManager::Popup( const ResId& rResId, SfxViewFra
     return nullptr;
 }
 
+namespace {
+
+    boost::property_tree::ptree fillPopupMenu(Menu* pMenu)
+    {
+        // Activate this menu first
+        pMenu->HandleMenuActivateEvent(pMenu);
+        pMenu->HandleMenuDeActivateEvent(pMenu);
+
+        boost::property_tree::ptree aTree;
+        // If last item inserted is some valid text
+        bool bIsLastItemText = false;
+        sal_uInt16 nCount = pMenu->GetItemCount();
+        for (sal_uInt16 nPos = 0; nPos < nCount; nPos++)
+        {
+            boost::property_tree::ptree aItemTree;
+            const MenuItemType aItemType = pMenu->GetItemType(nPos);
+
+            if (aItemType == MenuItemType::DONTKNOW)
+                continue;
+
+            if (aItemType == MenuItemType::SEPARATOR)
+            {
+                if (bIsLastItemText)
+                    aItemTree.put("type", "separator");
+                bIsLastItemText = false;
+            }
+            else
+            {
+                const sal_uInt16 nItemId = pMenu->GetItemId(nPos);
+                const OUString aCommandURL = pMenu->GetItemCommand(nItemId);
+
+                const OUString aItemText = pMenu->GetItemText(nItemId);
+                Menu* pPopupSubmenu = pMenu->GetPopupMenu(nItemId);
+
+                if (!pMenu->IsItemEnabled(nItemId))
+                    continue;
+
+                if (!aItemText.isEmpty())
+                    aItemTree.put("text", std::string(aItemText.toUtf8().getStr()));
+
+                if (pPopupSubmenu)
+                {
+                    boost::property_tree::ptree aSubmenu = fillPopupMenu(pPopupSubmenu);
+                    if (!aSubmenu.empty())
+                    {
+                        aItemTree.put("type", "menu");
+                        aItemTree.push_back(std::make_pair("menu", aSubmenu));
+                    }
+                    else
+                        aItemTree.clear();
+                }
+                else
+                {
+                    if (!aCommandURL.isEmpty())
+                    {
+                        aItemTree.put("type", "command");
+                        aItemTree.put("command", std::string(aCommandURL.toUtf8().getStr()));
+                    }
+                }
+
+                MenuItemBits aItemBits = pMenu->GetItemBits(nItemId);
+                bool bHasChecks = false;
+                if (aItemBits & MenuItemBits::CHECKABLE)
+                {
+                    aItemTree.put("checktype", "checkmark");
+                    bHasChecks = true;
+                }
+                else if (aItemBits & MenuItemBits::RADIOCHECK)
+                {
+                    aItemTree.put("checktype", "radio");
+                    bHasChecks = true;
+                }
+                else if (aItemBits & MenuItemBits::AUTOCHECK)
+                {
+                    aItemTree.put("checktype", "auto");
+                    bHasChecks = true;
+                }
+
+                if (bHasChecks)
+                {
+                    if (pMenu->IsItemChecked(nItemId))
+                        aItemTree.put("checked", "true");
+                    else
+                        aItemTree.put("checked", "false");
+                }
+            }
+
+            if (!aItemTree.empty())
+            {
+                aTree.push_back(std::make_pair("", aItemTree));
+                if (aItemType != MenuItemType::SEPARATOR)
+                    bIsLastItemText = true;
+            }
+        }
+
+        return aTree;
+    }
+
+} // end anonymous namespace
 
 void SfxPopupMenuManager::ExecutePopup( const ResId& rResId, SfxViewFrame* pFrame, const Point& rPoint, vcl::Window* pWindow )
 {
@@ -369,9 +473,23 @@ void SfxPopupMenuManager::ExecutePopup( const ResId& rResId, SfxViewFrame* pFram
             pSVMenu = static_cast<PopupMenu*>( pMenu );
         }
 
-        SfxPopupMenuManager aPop( pSVMenu, pFrame->GetBindings() );
-        aPop.RemoveDisabledEntries();
-        aPop.Execute( rPoint, pWindow );
+        if (comphelper::LibreOfficeKit::isActive())
+        {
+            boost::property_tree::ptree aMenu = fillPopupMenu(pSVMenu);
+            boost::property_tree::ptree aRoot;
+            aRoot.add_child("menu", aMenu);
+
+            std::stringstream aStream;
+            boost::property_tree::write_json(aStream, aRoot, true);
+            const SfxObjectShell* objSh = pFrame->GetObjectShell();
+            objSh->libreOfficeKitCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str());
+        }
+        else
+        {
+            SfxPopupMenuManager aPop( pSVMenu, pFrame->GetBindings() );
+            aPop.RemoveDisabledEntries();
+            aPop.Execute( rPoint, pWindow );
+        }
 
         // #i112646 avoid crash when context menu is closed.
         // the (manually inserted) sub-menu needs to be destroyed before
diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx
index 41db7bf..236e89b 100644
--- a/sw/source/uibase/inc/edtwin.hxx
+++ b/sw/source/uibase/inc/edtwin.hxx
@@ -197,8 +197,6 @@ protected:
     virtual void    MouseButtonUp(const MouseEvent& rMEvt) override;
     virtual void    RequestHelp(const HelpEvent& rEvt) override;
 
-    virtual void    Command( const CommandEvent& rCEvt ) override;
-
                                 // Drag & Drop Interface
     virtual sal_Int8    AcceptDrop( const AcceptDropEvent& rEvt ) override;
     virtual sal_Int8    ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
@@ -295,6 +293,8 @@ public:
     virtual ~SwEditWin();
     virtual void dispose() override;
 
+    virtual void    Command( const CommandEvent& rCEvt ) override;
+
     /// @see OutputDevice::LogicInvalidate().
     void LogicInvalidate(const Rectangle* pRectangle) override;
     /// Same as MouseButtonDown(), but coordinates are in logic unit.
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index f7db986..d276c54 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3303,12 +3303,19 @@ void SwXTextDocument::postMouseEvent(int nType, int nX, int nY, int nCount, int
     SolarMutexGuard aGuard;
 
     SwEditWin& rEditWin = pDocShell->GetView()->GetEditWin();
-    MouseEvent aEvent(Point(nX, nY), nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
+    Point aPos(nX , nY);
+    MouseEvent aEvent(aPos, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
 
     switch (nType)
     {
     case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
         rEditWin.LogicMouseButtonDown(aEvent);
+
+        if (nButtons & MOUSE_RIGHT)
+        {
+            const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu, true, nullptr);
+            rEditWin.Command(aCEvt);
+        }
         break;
     case LOK_MOUSEEVENT_MOUSEBUTTONUP:
         rEditWin.LogicMouseButtonUp(aEvent);
commit 8b39330497f80c09e0a8e9f0f87b6fa94a09cdde
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Mon Feb 22 20:57:52 2016 +0000

    gtk3: some changes towards enabling native gtk3 popup menus
    
    these menubar things can be menu things and can then do
    away with the casting, no logic changes intended
    
    Change-Id: Ibb1b5354d5e1483327f172d6890e134f1e4b9ee4

diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx
index ade703b..14c3356 100644
--- a/include/vcl/menu.hxx
+++ b/include/vcl/menu.hxx
@@ -404,8 +404,11 @@ public:
 
     void HighlightItem( sal_uInt16 nItemPos );
     void DeHighlight() { HighlightItem( 0xFFFF ); } // MENUITEMPOS_INVALID
-};
 
+    bool HandleMenuCommandEvent(Menu *pMenu, sal_uInt16 nEventId) const;
+    bool HandleMenuActivateEvent(Menu *pMenu) const;
+    bool HandleMenuDeActivateEvent(Menu *pMenu) const;
+};
 
 namespace vcl { namespace MenuInvalidator {
 
@@ -463,10 +466,7 @@ public:
     void ShowButtons( bool bClose, bool bFloat, bool bHide );
 
     virtual void SelectItem(sal_uInt16 nId) override;
-    bool HandleMenuActivateEvent(Menu *pMenu) const;
-    bool HandleMenuDeActivateEvent(Menu *pMenu) const;
     bool HandleMenuHighlightEvent(Menu *pMenu, sal_uInt16 nEventId) const;
-    bool HandleMenuCommandEvent(Menu *pMenu, sal_uInt16 nEventId) const;
     bool HandleMenuButtonEvent(Menu *pMenu, sal_uInt16 nEventId);
 
     void SetCloseButtonClickHdl( const Link<void*,void>& rLink ) { maCloseHdl = rLink; }
diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
index 011c3e4..cae1cc1 100644
--- a/vcl/inc/unx/gtk/gtksalmenu.hxx
+++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
@@ -42,7 +42,7 @@ class GtkSalMenu : public SalMenu
 private:
     std::vector< GtkSalMenuItem* >  maItems;
 
-    bool                        mbMenuBar;
+    bool                            mbMenuBar;
     Menu*                           mpVCLMenu;
     GtkSalMenu*                     mpParentSalMenu;
     const GtkSalFrame*              mpFrame;
@@ -53,7 +53,7 @@ private:
 
     GtkSalMenu*                 GetMenuForItemCommand( gchar* aCommand, int& rDupsToSkip, gboolean bGetSubmenu );
     void                        ImplUpdate( gboolean bRecurse );
-    void                        ActivateAllSubmenus(MenuBar* pMenuBar);
+    void                        ActivateAllSubmenus(Menu* pMenuBar);
 
 public:
     GtkSalMenu( bool bMenuBar );
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index 3a6e54c..6a9670c 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2673,14 +2673,13 @@ void MenuBar::SelectItem(sal_uInt16 nId)
 }
 
 // handler for native menu selection and command events
-
-bool MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
+bool Menu::HandleMenuActivateEvent( Menu *pMenu ) const
 {
     if( pMenu )
     {
         ImplMenuDelData aDelData( this );
 
-        pMenu->pStartedFrom = const_cast<MenuBar*>(this);
+        pMenu->pStartedFrom = const_cast<Menu*>(this);
         pMenu->bInCallback = true;
         pMenu->Activate();
 
@@ -2690,13 +2689,13 @@ bool MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
     return true;
 }
 
-bool MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
+bool Menu::HandleMenuDeActivateEvent( Menu *pMenu ) const
 {
     if( pMenu )
     {
         ImplMenuDelData aDelData( this );
 
-        pMenu->pStartedFrom = const_cast<MenuBar*>(this);
+        pMenu->pStartedFrom = const_cast<Menu*>(this);
         pMenu->bInCallback = true;
         pMenu->Deactivate();
         if( !aDelData.isDeleted() )
@@ -2729,14 +2728,14 @@ bool MenuBar::HandleMenuHighlightEvent( Menu *pMenu, sal_uInt16 nHighlightEventI
         return false;
 }
 
-bool MenuBar::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const
+bool Menu::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const
 {
     if( !pMenu )
-        pMenu = const_cast<MenuBar*>(this)->ImplFindMenu(nCommandEventId);
+        pMenu = const_cast<Menu*>(this)->ImplFindMenu(nCommandEventId);
     if( pMenu )
     {
         pMenu->nSelectedId = nCommandEventId;
-        pMenu->pStartedFrom = const_cast<MenuBar*>(this);
+        pMenu->pStartedFrom = const_cast<Menu*>(this);
         pMenu->ImplSelect();
         return true;
     }
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index b6295fa..15bcccb 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -699,11 +699,10 @@ void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand )
     GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aCommand), nDupsToSkip, FALSE );
     Menu* pSubMenu = ( pSalSubMenu != nullptr ) ? pSalSubMenu->GetMenu() : nullptr;
 
-    MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
-    pMenuBar->HandleMenuCommandEvent( pSubMenu, itemId );
+    mpVCLMenu->HandleMenuCommandEvent( pSubMenu, itemId );
 }
 
-void GtkSalMenu::ActivateAllSubmenus(MenuBar* pMenuBar)
+void GtkSalMenu::ActivateAllSubmenus(Menu* pMenuBar)
 {
     pMenuBar->HandleMenuActivateEvent(mpVCLMenu);
     for ( size_t nPos = 0; nPos < maItems.size(); nPos++ )
@@ -721,7 +720,7 @@ void GtkSalMenu::Activate()
 {
     if ( !mbMenuBar )
         return;
-    ActivateAllSubmenus(static_cast<MenuBar*>(mpVCLMenu));
+    ActivateAllSubmenus(mpVCLMenu);
 }
 
 void GtkSalMenu::Deactivate( const gchar* aMenuCommand )
@@ -734,8 +733,7 @@ void GtkSalMenu::Deactivate( const gchar* aMenuCommand )
     GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aMenuCommand), nDupsToSkip, TRUE );
 
     if ( pSalSubMenu != nullptr ) {
-        MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
-        pMenuBar->HandleMenuDeActivateEvent( pSalSubMenu->mpVCLMenu );
+        mpVCLMenu->HandleMenuDeActivateEvent( pSalSubMenu->mpVCLMenu );
     }
 }
 


More information about the Libreoffice-commits mailing list