include/vcl/menu.hxx                  |    3 +
 sfx2/source/dialog/StyleList.cxx      |   12 +++--
 sfx2/source/inc/StyleList.hxx         |    1 
 vcl/inc/jsdialog/enabled.hxx          |    1 
 vcl/inc/jsdialog/jsdialogbuilder.hxx  |    3 +
 vcl/inc/jsdialog/jsdialogmessages.hxx |   28 +++++++++---
 vcl/inc/jsdialog/jsdialogsender.hxx   |   12 +++--
 vcl/jsdialog/enabled.cxx              |    9 ++++
 vcl/jsdialog/executor.cxx             |   19 +++++---
 vcl/jsdialog/jsdialogbuilder.cxx      |   13 +++--
 vcl/jsdialog/jsdialogsender.cxx       |   76 +++++++++++++++++++++++++++-------
 vcl/source/window/builder.cxx         |    2 
 vcl/source/window/menu.cxx            |   21 +++++++++
 13 files changed, 158 insertions(+), 42 deletions(-)

New commits:
commit c6a0ccf1dc3b4a217de4915402f9d61df49bb41d
Author:     Szymon Kłos <[email protected]>
AuthorDate: Tue Dec 10 12:38:04 2024 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Wed Dec 11 13:22:39 2024 +0100

    jsdialog: add const
    
    Change-Id: If689daf52ca01904bc22c8f2e72f65247be2a3f5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178223
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Tomaž Vajngerl <[email protected]>

diff --git a/vcl/inc/jsdialog/jsdialogmessages.hxx 
b/vcl/inc/jsdialog/jsdialogmessages.hxx
index fba40e151d82..7a9ebe904836 100644
--- a/vcl/inc/jsdialog/jsdialogmessages.hxx
+++ b/vcl/inc/jsdialog/jsdialogmessages.hxx
@@ -105,19 +105,19 @@ public:
     void clearQueue();
     void forceUpdate();
     template <class VclType>
-    void sendMessage(jsdialog::MessageType eType, VclPtr<VclType> pWindow,
+    void sendMessage(const jsdialog::MessageType eType, const VclPtr<VclType>& 
pWindow,
                      std::unique_ptr<jsdialog::ActionDataMap> pData = nullptr);
 
 private:
     void send(const OString& sMsg);
     OString generateFullUpdate() const;
-    OString generateWidgetUpdate(VclPtr<vcl::Window> pWindow) const;
+    OString generateWidgetUpdate(const VclPtr<vcl::Window>& pWindow) const;
     OString generateCloseMessage() const;
-    OString generateActionMessage(VclPtr<vcl::Window> pWindow,
+    OString generateActionMessage(const VclPtr<vcl::Window>& pWindow,
                                   std::unique_ptr<jsdialog::ActionDataMap> 
pData) const;
-    OString generatePopupMessage(VclPtr<vcl::Window> pWindow, OUString 
sParentId,
-                                 OUString sCloseId) const;
-    OString generateClosePopupMessage(OUString sWindowId) const;
+    OString generatePopupMessage(const VclPtr<vcl::Window>& pWindow, const 
OUString& sParentId,
+                                 const OUString& sCloseId) const;
+    OString generateClosePopupMessage(const OUString& sWindowId) const;
     OString generateMenuMessage(const VclPtr<PopupMenu>& pMenu) const;
 };
 
diff --git a/vcl/inc/jsdialog/jsdialogsender.hxx 
b/vcl/inc/jsdialog/jsdialogsender.hxx
index 85066e10f37d..44324fb07844 100644
--- a/vcl/inc/jsdialog/jsdialogsender.hxx
+++ b/vcl/inc/jsdialog/jsdialogsender.hxx
@@ -48,8 +48,8 @@ public:
         : m_bCanClose(true)
     {
     }
-    JSDialogSender(VclPtr<vcl::Window> aNotifierWindow, VclPtr<vcl::Window> 
aContentWindow,
-                   const OUString& sTypeOfJSON)
+    JSDialogSender(const VclPtr<vcl::Window>& aNotifierWindow,
+                   const VclPtr<vcl::Window>& aContentWindow, const OUString& 
sTypeOfJSON)
         : m_bCanClose(true)
     {
         initializeSender(aNotifierWindow, aContentWindow, sTypeOfJSON);
@@ -59,10 +59,11 @@ public:
 
     virtual void sendFullUpdate(bool bForce = false);
     void sendClose();
-    void sendUpdate(VclPtr<vcl::Window> pWindow, bool bForce = false);
-    virtual void sendAction(VclPtr<vcl::Window> pWindow,
+    void sendUpdate(const VclPtr<vcl::Window>& pWindow, bool bForce = false);
+    virtual void sendAction(const VclPtr<vcl::Window>& pWindow,
                             std::unique_ptr<jsdialog::ActionDataMap> pData);
-    virtual void sendPopup(VclPtr<vcl::Window> pWindow, OUString sParentId, 
OUString sCloseId);
+    virtual void sendPopup(const VclPtr<vcl::Window>& pWindow, const OUString& 
sParentId,
+                           const OUString& sCloseId);
     virtual void sendMenu(const VclPtr<PopupMenu>& pMenu);
     virtual void sendClosePopup(vcl::LOKWindowId nWindowId);
     void flush() { mpIdleNotify->Invoke(); }
diff --git a/vcl/jsdialog/jsdialogsender.cxx b/vcl/jsdialog/jsdialogsender.cxx
index b166ed76cc6e..fac9cf229013 100644
--- a/vcl/jsdialog/jsdialogsender.cxx
+++ b/vcl/jsdialog/jsdialogsender.cxx
@@ -46,7 +46,8 @@ void JSDialogNotifyIdle::send(const OString& sMsg)
 }
 
 template <class VclType>
-void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType eType, 
VclPtr<VclType> pTarget,
+void JSDialogNotifyIdle::sendMessage(const jsdialog::MessageType eType,
+                                     const VclPtr<VclType>& pTarget,
                                      std::unique_ptr<jsdialog::ActionDataMap> 
pData)
 {
     std::scoped_lock aGuard(m_aQueueMutex);
@@ -94,7 +95,7 @@ OString JSDialogNotifyIdle::generateFullUpdate() const
     return aJsonWriter.finishAndGetAsOString();
 }
 
-OString JSDialogNotifyIdle::generateWidgetUpdate(VclPtr<vcl::Window> pWindow) 
const
+OString JSDialogNotifyIdle::generateWidgetUpdate(const VclPtr<vcl::Window>& 
pWindow) const
 {
     if (!pWindow || !m_aNotifierWindow)
         return OString();
@@ -125,7 +126,7 @@ OString JSDialogNotifyIdle::generateCloseMessage() const
 }
 
 OString
-JSDialogNotifyIdle::generateActionMessage(VclPtr<vcl::Window> pWindow,
+JSDialogNotifyIdle::generateActionMessage(const VclPtr<vcl::Window>& pWindow,
                                           
std::unique_ptr<jsdialog::ActionDataMap> pData) const
 {
     tools::JsonWriter aJsonWriter;
@@ -146,8 +147,9 @@ 
JSDialogNotifyIdle::generateActionMessage(VclPtr<vcl::Window> pWindow,
     return aJsonWriter.finishAndGetAsOString();
 }
 
-OString JSDialogNotifyIdle::generatePopupMessage(VclPtr<vcl::Window> pWindow, 
OUString sParentId,
-                                                 OUString sCloseId) const
+OString JSDialogNotifyIdle::generatePopupMessage(const VclPtr<vcl::Window>& 
pWindow,
+                                                 const OUString& sParentId,
+                                                 const OUString& sCloseId) 
const
 {
     if (!pWindow || !m_aNotifierWindow)
         return OString();
@@ -195,7 +197,7 @@ OString 
JSDialogNotifyIdle::generatePopupMessage(VclPtr<vcl::Window> pWindow, OU
     return aJsonWriter.finishAndGetAsOString();
 }
 
-OString JSDialogNotifyIdle::generateClosePopupMessage(OUString sWindowId) const
+OString JSDialogNotifyIdle::generateClosePopupMessage(const OUString& 
sWindowId) const
 {
     if (!m_aNotifierWindow)
         return OString();
@@ -322,7 +324,7 @@ void JSDialogSender::sendClose()
     flush();
 }
 
-void JSDialogSender::sendUpdate(VclPtr<vcl::Window> pWindow, bool bForce)
+void JSDialogSender::sendUpdate(const VclPtr<vcl::Window>& pWindow, bool 
bForce)
 {
     if (!mpIdleNotify)
         return;
@@ -334,7 +336,7 @@ void JSDialogSender::sendUpdate(VclPtr<vcl::Window> 
pWindow, bool bForce)
     mpIdleNotify->Start();
 }
 
-void JSDialogSender::sendAction(VclPtr<vcl::Window> pWindow,
+void JSDialogSender::sendAction(const VclPtr<vcl::Window>& pWindow,
                                 std::unique_ptr<jsdialog::ActionDataMap> pData)
 {
     if (!mpIdleNotify)
@@ -344,7 +346,8 @@ void JSDialogSender::sendAction(VclPtr<vcl::Window> pWindow,
     mpIdleNotify->Start();
 }
 
-void JSDialogSender::sendPopup(VclPtr<vcl::Window> pWindow, OUString 
sParentId, OUString sCloseId)
+void JSDialogSender::sendPopup(const VclPtr<vcl::Window>& pWindow, const 
OUString& sParentId,
+                               const OUString& sCloseId)
 {
     if (!mpIdleNotify)
         return;
commit b79031d14cc39bb9f4ac87f1f57865ba00fd9b5a
Author:     Szymon Kłos <[email protected]>
AuthorDate: Wed Dec 4 10:41:22 2024 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Wed Dec 11 13:22:31 2024 +0100

    jsdialog: send message for weld::Menu
    
    - we need to setup correct notifier
    - enable context menu in the style sidebar in Writer
    - handle menu actions
    - base of vcl::Window and PopupMenu is VclReferenceBase
    - prepare template function sendMessage to handle both
    
    Change-Id: I54c8dc468856c0f98495bdaf4ddd504c2f56562f
    Signed-off-by: Szymon Kłos <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177782
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Tomaž Vajngerl <[email protected]>

diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx
index a28182e51fe2..791faa85f692 100644
--- a/include/vcl/menu.hxx
+++ b/include/vcl/menu.hxx
@@ -32,6 +32,7 @@
 #include <vcl/vclreferencebase.hxx>
 #include <com/sun/star/uno/Reference.hxx>
 #include <o3tl/typed_flags_set.hxx>
+#include <tools/json_writer.hxx>
 #include <list>
 
 class OutputDevice;
@@ -402,6 +403,8 @@ public:
      * Get the ID of the window.
      */
     const OUString& get_id() const { return maID; }
+
+    virtual void DumpAsPropertyTree(tools::JsonWriter&) const;
 };
 
 struct MenuBarButtonCallbackArg
diff --git a/sfx2/source/dialog/StyleList.cxx b/sfx2/source/dialog/StyleList.cxx
index e7bdd9e3b4a3..0d23c4361f16 100644
--- a/sfx2/source/dialog/StyleList.cxx
+++ b/sfx2/source/dialog/StyleList.cxx
@@ -182,7 +182,7 @@ void StyleList::CreateContextMenu()
         m_bBindingUpdate = false;
     }
     mxMenu.reset();
-    mxMenuBuilder = Application::CreateBuilder(nullptr, 
"sfx/ui/stylecontextmenu.ui");
+    mxMenuBuilder = Application::CreateBuilder(m_pContainer, 
"sfx/ui/stylecontextmenu.ui");
     mxMenu = mxMenuBuilder->weld_menu("menu");
     mxMenu->set_sensitive("edit", m_bCanEdit);
     mxMenu->set_sensitive("delete", m_bCanDel);
@@ -1472,13 +1472,14 @@ IMPL_LINK_NOARG(StyleList, Clear, void*, void)
         i.reset();
 }
 
+IMPL_LINK(StyleList, OnPopupEnd, const OUString&, sCommand, void) { 
MenuSelect(sCommand); }
+
 void StyleList::ShowMenu(const CommandEvent& rCEvt)
 {
     CreateContextMenu();
     weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : 
m_xFmtLb.get();
-    OUString sCommand(
-        mxMenu->popup_at_rect(pTreeView, 
tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
-    MenuSelect(sCommand);
+    mxMenu->connect_activate(LINK(this, StyleList, OnPopupEnd));
+    mxMenu->popup_at_rect(pTreeView, 
tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
 }
 
 void StyleList::MenuSelect(const OUString& rIdent)
@@ -1612,6 +1613,9 @@ IMPL_LINK_NOARG(StyleList, MenuSelectAsyncHdl, void*, 
void)
         HideHdl();
     else if (sLastItemIdent == "show")
         ShowHdl();
+
+    mxMenu.reset();
+    mxMenuBuilder.reset();
 }
 
 // Double-click on a style sheet in the ListBox is applied.
diff --git a/sfx2/source/inc/StyleList.hxx b/sfx2/source/inc/StyleList.hxx
index fe4ff6269bd5..9cd478a84634 100644
--- a/sfx2/source/inc/StyleList.hxx
+++ b/sfx2/source/inc/StyleList.hxx
@@ -129,6 +129,7 @@ public:
     void FilterSelect(sal_uInt16 nActFilter, bool bsetFilter);
 
     DECL_LINK(NewMenuExecuteAction, void*, void);
+    DECL_LINK(OnPopupEnd, const OUString&, void);
 
     bool HasStylesHighlighterFeature() { return 
m_bModuleHasStylesHighlighterFeature; }
     void SetHighlightParaStyles(bool bSet) { m_bHighlightParaStyles = bSet; }
diff --git a/vcl/inc/jsdialog/enabled.hxx b/vcl/inc/jsdialog/enabled.hxx
index 422a8d80fb50..5c85f310f155 100644
--- a/vcl/inc/jsdialog/enabled.hxx
+++ b/vcl/inc/jsdialog/enabled.hxx
@@ -15,6 +15,7 @@ namespace jsdialog
 {
 bool isBuilderEnabled(std::u16string_view rUIFile, bool bMobile);
 bool isBuilderEnabledForPopup(std::u16string_view rUIFile);
+bool isBuilderEnabledForMenu(std::u16string_view rUIFile);
 bool isBuilderEnabledForSidebar(std::u16string_view rUIFile);
 bool isBuilderEnabledForAddressInput(std::u16string_view rUIFile);
 bool isBuilderEnabledForFormulabar(std::u16string_view rUIFile);
diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx 
b/vcl/inc/jsdialog/jsdialogbuilder.hxx
index 25a5f969a1be..fc8f13fdd502 100644
--- a/vcl/inc/jsdialog/jsdialogbuilder.hxx
+++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx
@@ -757,6 +757,9 @@ public:
 
 class JSMenu final : public SalInstanceMenu
 {
+    VclPtr<PopupMenu> m_pPopupMenu;
+    JSDialogSender* m_pSender;
+
 public:
     JSMenu(JSDialogSender* pSender, PopupMenu* pMenu, SalInstanceBuilder* 
pBuilder,
            bool bTakeOwnership);
diff --git a/vcl/inc/jsdialog/jsdialogmessages.hxx 
b/vcl/inc/jsdialog/jsdialogmessages.hxx
index 6bbd4f166f4b..fba40e151d82 100644
--- a/vcl/inc/jsdialog/jsdialogmessages.hxx
+++ b/vcl/inc/jsdialog/jsdialogmessages.hxx
@@ -14,6 +14,7 @@
 #include <rtl/ustring.hxx>
 #include <vcl/idle.hxx>
 #include <vcl/jsdialog/executor.hxx>
+#include <vcl/menu.hxx>
 #include <vcl/window.hxx>
 
 namespace jsdialog
@@ -25,7 +26,8 @@ enum MessageType
     Close,
     Action,
     Popup,
-    PopupClose
+    PopupClose,
+    Menu,
 };
 }
 
@@ -35,6 +37,7 @@ class JSDialogMessageInfo
 public:
     jsdialog::MessageType m_eType;
     VclPtr<vcl::Window> m_pWindow;
+    VclPtr<PopupMenu> m_pMenu;
     std::unique_ptr<jsdialog::ActionDataMap> m_pData;
 
 private:
@@ -42,6 +45,7 @@ private:
     {
         this->m_eType = rInfo.m_eType;
         this->m_pWindow = rInfo.m_pWindow;
+        this->m_pMenu = rInfo.m_pMenu;
         if (rInfo.m_pData)
         {
             std::unique_ptr<jsdialog::ActionDataMap> pData(
@@ -59,6 +63,14 @@ public:
     {
     }
 
+    JSDialogMessageInfo(jsdialog::MessageType eType, VclPtr<PopupMenu> pMenu,
+                        std::unique_ptr<jsdialog::ActionDataMap> pData)
+        : m_eType(eType)
+        , m_pMenu(std::move(pMenu))
+        , m_pData(std::move(pData))
+    {
+    }
+
     JSDialogMessageInfo(const JSDialogMessageInfo& rInfo) { copy(rInfo); }
 
     JSDialogMessageInfo& operator=(JSDialogMessageInfo aInfo)
@@ -92,7 +104,8 @@ public:
 
     void clearQueue();
     void forceUpdate();
-    void sendMessage(jsdialog::MessageType eType, VclPtr<vcl::Window> pWindow,
+    template <class VclType>
+    void sendMessage(jsdialog::MessageType eType, VclPtr<VclType> pWindow,
                      std::unique_ptr<jsdialog::ActionDataMap> pData = nullptr);
 
 private:
@@ -105,6 +118,7 @@ private:
     OString generatePopupMessage(VclPtr<vcl::Window> pWindow, OUString 
sParentId,
                                  OUString sCloseId) const;
     OString generateClosePopupMessage(OUString sWindowId) const;
+    OString generateMenuMessage(const VclPtr<PopupMenu>& pMenu) const;
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/inc/jsdialog/jsdialogsender.hxx 
b/vcl/inc/jsdialog/jsdialogsender.hxx
index f6a899a23d90..85066e10f37d 100644
--- a/vcl/inc/jsdialog/jsdialogsender.hxx
+++ b/vcl/inc/jsdialog/jsdialogsender.hxx
@@ -63,6 +63,7 @@ public:
     virtual void sendAction(VclPtr<vcl::Window> pWindow,
                             std::unique_ptr<jsdialog::ActionDataMap> pData);
     virtual void sendPopup(VclPtr<vcl::Window> pWindow, OUString sParentId, 
OUString sCloseId);
+    virtual void sendMenu(const VclPtr<PopupMenu>& pMenu);
     virtual void sendClosePopup(vcl::LOKWindowId nWindowId);
     void flush() { mpIdleNotify->Invoke(); }
 
diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx
index d8803bd46945..6ff842226e5b 100644
--- a/vcl/jsdialog/enabled.cxx
+++ b/vcl/jsdialog/enabled.cxx
@@ -338,6 +338,15 @@ bool isBuilderEnabledForPopup(std::u16string_view rUIFile)
     return false;
 }
 
+bool isBuilderEnabledForMenu(std::u16string_view rUIFile)
+{
+    if (// sfx2
+        rUIFile == u"sfx/ui/stylecontextmenu.ui")
+        return true;
+
+    return false;
+}
+
 bool isBuilderEnabledForSidebar(std::u16string_view rUIFile)
 {
     return // scalc
diff --git a/vcl/jsdialog/executor.cxx b/vcl/jsdialog/executor.cxx
index 6e42d9ac3eec..16ef9a715e33 100644
--- a/vcl/jsdialog/executor.cxx
+++ b/vcl/jsdialog/executor.cxx
@@ -81,10 +81,10 @@ bool ExecuteAction(const OUString& nWindowId, const 
OUString& rWidget, StringMap
     if (pWidget == nullptr)
     {
         // weld::Menu doesn't have base of weld::Widget
-        if (sControlType == "menu")
+        if (rWidget == "__MENU__")
         {
             weld::Menu* pMenu = JSInstanceBuilder::Menus().Find(nWindowId);
-            if (pMenu && sAction == "activated")
+            if (pMenu && sAction == "select")
             {
                 LOKTrigger::trigger_activated(*pMenu, rData["data"]);
                 return true;
@@ -581,12 +581,17 @@ bool ExecuteAction(const OUString& nWindowId, const 
OUString& rWidget, StringMap
                     sal_Int32 nEntryAbsPos = o3tl::toInt32(rData["data"]);
 
                     std::unique_ptr<weld::TreeIter> 
itEntry(pTreeView->make_iterator());
-                    pTreeView->get_iter_abs_pos(*itEntry, nEntryAbsPos);
-
-                    tools::Rectangle aRect = pTreeView->get_row_area(*itEntry);
-                    CommandEvent aCommand(aRect.Center(), 
CommandEventId::ContextMenu);
+                    if (pTreeView->get_iter_abs_pos(*itEntry, nEntryAbsPos))
+                    {
+                        tools::Rectangle aRect = 
pTreeView->get_row_area(*itEntry);
+                        CommandEvent aCommand(aRect.Center(), 
CommandEventId::ContextMenu);
 
-                    LOKTrigger::trigger_popup_menu(*pTreeView, aCommand);
+                        LOKTrigger::trigger_popup_menu(*pTreeView, aCommand);
+                    }
+                    else
+                        SAL_WARN("vcl", "No absolute position found for " << 
nEntryAbsPos
+                                                                          << " 
in treeview");
+                    return true;
                 }
             }
         }
diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx
index c7b809147f29..8405622d48ea 100644
--- a/vcl/jsdialog/jsdialogbuilder.cxx
+++ b/vcl/jsdialog/jsdialogbuilder.cxx
@@ -375,7 +375,7 @@ JSInstanceBuilder::~JSInstanceBuilder()
         jsdialog::SendFullUpdate(OUString::number(m_nWindowId), "__DIALOG__");
     }
 
-    if (m_sTypeOfJSON == "popup")
+    if (m_sTypeOfJSON == "popup" || m_sTypeOfJSON == "menu")
         sendClosePopup(m_nWindowId);
 
     if (m_aWindowToRelease)
@@ -399,6 +399,7 @@ JSInstanceBuilder::~JSInstanceBuilder()
     }
 
     JSInstanceBuilder::Popups().Forget(OUString::number(m_nWindowId));
+    JSInstanceBuilder::Menus().Forget(OUString::number(m_nWindowId));
 }
 
 const OUString& JSInstanceBuilder::GetTypeOfJSON() const { return 
m_sTypeOfJSON; }
@@ -1960,19 +1961,21 @@ void JSMenuButton::set_active(bool bActive)
     }
 }
 
-JSMenu::JSMenu(JSDialogSender* /*pSender*/, PopupMenu* pPopupMenu, 
SalInstanceBuilder* /*pBuilder*/,
+JSMenu::JSMenu(JSDialogSender* pSender, PopupMenu* pPopupMenu, 
SalInstanceBuilder* /*pBuilder*/,
                bool bTakeOwnership)
     : SalInstanceMenu(pPopupMenu, bTakeOwnership)
+    , m_pPopupMenu(pPopupMenu)
+    , m_pSender(pSender)
 {
 }
 
 OUString JSMenu::popup_at_rect(weld::Widget* /*pParent*/, const 
tools::Rectangle& /*rRect*/,
                                weld::Placement /*ePlace*/)
 {
-    // TODO: send message
+    // Do not block with SalInstanceMenu::popup_at_rect(pParent, rRect, 
ePlace);
+    m_pSender->sendMenu(m_pPopupMenu);
 
-    // first only send menu and cancel menu
-    // no return SalInstanceMenu::popup_at_rect(pParent, rRect, ePlace);
+    // Don't return any action - simulate canceled menu
     return "";
 }
 
diff --git a/vcl/jsdialog/jsdialogsender.cxx b/vcl/jsdialog/jsdialogsender.cxx
index 7cecdbeb9eed..b166ed76cc6e 100644
--- a/vcl/jsdialog/jsdialogsender.cxx
+++ b/vcl/jsdialog/jsdialogsender.cxx
@@ -45,7 +45,8 @@ void JSDialogNotifyIdle::send(const OString& sMsg)
     }
 }
 
-void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType eType, 
VclPtr<vcl::Window> pWindow,
+template <class VclType>
+void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType eType, 
VclPtr<VclType> pTarget,
                                      std::unique_ptr<jsdialog::ActionDataMap> 
pData)
 {
     std::scoped_lock aGuard(m_aQueueMutex);
@@ -53,10 +54,14 @@ void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType 
eType, VclPtr<vcl::Wi
     // we want only the latest update of same type
     // TODO: also if we met full update - previous updates are not valid
     auto it = m_aMessageQueue.begin();
+    const VclReferenceBase* pRawTarget = 
static_cast<VclReferenceBase*>(pTarget);
 
     while (it != m_aMessageQueue.end())
     {
-        if (it->m_eType == eType && it->m_pWindow == pWindow)
+        const VclReferenceBase* pRawWindow = 
static_cast<VclReferenceBase*>(it->m_pWindow.get());
+        const VclReferenceBase* pRawMenu = it->m_pMenu.get();
+
+        if (it->m_eType == eType && (pRawWindow == pRawTarget || pRawMenu == 
pRawTarget))
         {
             // actions should be always sent, eg. rendering of custom entries 
in combobox
             if (eType == jsdialog::MessageType::Action)
@@ -70,7 +75,7 @@ void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType 
eType, VclPtr<vcl::Wi
             it++;
     }
 
-    JSDialogMessageInfo aMessage(eType, pWindow, std::move(pData));
+    JSDialogMessageInfo aMessage(eType, pTarget, std::move(pData));
     m_aMessageQueue.push_back(aMessage);
 }
 
@@ -205,6 +210,30 @@ OString 
JSDialogNotifyIdle::generateClosePopupMessage(OUString sWindowId) const
     return aJsonWriter.finishAndGetAsOString();
 }
 
+OString JSDialogNotifyIdle::generateMenuMessage(const VclPtr<PopupMenu>& 
pMenu) const
+{
+    if (!pMenu || !m_aNotifierWindow)
+        return OString();
+
+    tools::JsonWriter aJsonWriter;
+
+    {
+        auto aChildren = aJsonWriter.startArray("children");
+        {
+            auto aStruct = aJsonWriter.startStruct();
+            pMenu->DumpAsPropertyTree(aJsonWriter);
+        }
+    }
+
+    aJsonWriter.put("jsontype", "dialog");
+    aJsonWriter.put("type", "dropdown");
+    aJsonWriter.put("cancellable", true);
+    aJsonWriter.put("popupParent", m_aNotifierWindow->get_id());
+    aJsonWriter.put("id", m_aNotifierWindow->GetLOKWindowId());
+
+    return aJsonWriter.finishAndGetAsOString();
+}
+
 void JSDialogNotifyIdle::Invoke()
 {
     std::deque<JSDialogMessageInfo> aMessageQueue;
@@ -248,6 +277,12 @@ void JSDialogNotifyIdle::Invoke()
             case jsdialog::MessageType::PopupClose:
                 send(generateClosePopupMessage((*rMessage.m_pData)[WINDOW_ID 
""_ostr]));
                 break;
+
+            case jsdialog::MessageType::Menu:
+            {
+                send(generateMenuMessage(rMessage.m_pMenu));
+                break;
+            }
         }
     }
 }
@@ -273,7 +308,7 @@ void JSDialogSender::sendFullUpdate(bool bForce)
     if (bForce)
         mpIdleNotify->forceUpdate();
 
-    mpIdleNotify->sendMessage(jsdialog::MessageType::FullUpdate, nullptr);
+    mpIdleNotify->sendMessage(jsdialog::MessageType::FullUpdate, 
VclPtr<vcl::Window>(nullptr));
     mpIdleNotify->Start();
 }
 
@@ -283,7 +318,7 @@ void JSDialogSender::sendClose()
         return;
 
     mpIdleNotify->clearQueue();
-    mpIdleNotify->sendMessage(jsdialog::MessageType::Close, nullptr);
+    mpIdleNotify->sendMessage(jsdialog::MessageType::Close, 
VclPtr<vcl::Window>(nullptr));
     flush();
 }
 
@@ -328,8 +363,18 @@ void JSDialogSender::sendClosePopup(vcl::LOKWindowId 
nWindowId)
 
     std::unique_ptr<jsdialog::ActionDataMap> pData = 
std::make_unique<jsdialog::ActionDataMap>();
     (*pData)[WINDOW_ID ""_ostr] = OUString::number(nWindowId);
-    mpIdleNotify->sendMessage(jsdialog::MessageType::PopupClose, nullptr, 
std::move(pData));
+    mpIdleNotify->sendMessage(jsdialog::MessageType::PopupClose, 
VclPtr<vcl::Window>(nullptr),
+                              std::move(pData));
     flush();
 }
 
+void JSDialogSender::sendMenu(const VclPtr<PopupMenu>& pMenu)
+{
+    if (!mpIdleNotify)
+        return;
+
+    mpIdleNotify->sendMessage(jsdialog::MessageType::Menu, pMenu);
+    mpIdleNotify->Start();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index 6344cd8e8871..43e954da025d 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -191,6 +191,8 @@ std::unique_ptr<weld::Builder> 
Application::CreateBuilder(weld::Widget* pParent,
             return JSInstanceBuilder::CreateSidebarBuilder(pParent, 
AllSettings::GetUIRootDir(), rUIFile, nLOKWindowId);
         else if (jsdialog::isBuilderEnabledForPopup(rUIFile))
             return JSInstanceBuilder::CreatePopupBuilder(pParent, 
AllSettings::GetUIRootDir(), rUIFile);
+        else if (jsdialog::isBuilderEnabledForMenu(rUIFile))
+            return JSInstanceBuilder::CreateMenuBuilder(pParent, 
AllSettings::GetUIRootDir(), rUIFile);
         else if (jsdialog::isBuilderEnabled(rUIFile, bMobile))
             return JSInstanceBuilder::CreateDialogBuilder(pParent, 
AllSettings::GetUIRootDir(), rUIFile);
     }
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index a0a03be455cb..c3566b5f5617 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2387,6 +2387,27 @@ void Menu::HighlightItem( sal_uInt16 nItemPos )
     }
 }
 
+void Menu::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) const
+{
+    rJsonWriter.put("id", "__MENU__"); // we have single instance of menu at 
the time per session
+    rJsonWriter.put("type", "menu");
+    rJsonWriter.put("count", GetItemCount());
+    {
+        auto aEntries = rJsonWriter.startArray("entries");
+        for (size_t i = 0; i < GetItemCount(); i++)
+        {
+            auto aEntry = rJsonWriter.startStruct();
+            sal_uInt16 nId = GetItemId(i);
+            rJsonWriter.put("row", GetItemIdent(nId));
+            {
+                auto aColumns = rJsonWriter.startArray("columns");
+                auto aColumn = rJsonWriter.startStruct();
+                rJsonWriter.put("text", GetItemText(nId));
+            }
+        }
+    }
+}
+
 MenuBarWindow* MenuBar::getMenuBarWindow()
 {
     // so far just a dynamic_cast, hopefully to be turned into something saner

Reply via email to