include/vcl/jsdialog/executor.hxx | 10 +++++ include/vcl/weld.hxx | 4 ++ vcl/inc/jsdialog/jsdialogbuilder.hxx | 16 ++++++++ vcl/inc/salvtables.hxx | 5 +- vcl/jsdialog/executor.cxx | 28 ++++++++++++++- vcl/jsdialog/jsdialogbuilder.cxx | 64 +++++++++++++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 3 deletions(-)
New commits: commit 2d7ab2b66bf1266246fcbab6e428faf0af94d913 Author: Szymon Kłos <szymon.k...@collabora.com> AuthorDate: Fri Nov 22 15:04:03 2024 +0100 Commit: Szymon Kłos <szymon.k...@collabora.com> CommitDate: Thu Dec 5 22:31:30 2024 +0100 jsdialog: weld::Menu - weld::Menu doesn't have base with weld::Widget - use separate container, only one menu per WindowId - first only send menu and cancel, when user activates option we will send another request and execute entry as menu can be blocking - there is connect_activated way of async setup too Change-Id: Iea03f82a91ecc19af67b91f85364675c119056ea Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177722 (cherry picked from commit efeb511607dacce991866bcf328c96a01ab594f9) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177852 Tested-by: Jenkins Reviewed-by: Szymon Kłos <szymon.k...@collabora.com> diff --git a/include/vcl/jsdialog/executor.hxx b/include/vcl/jsdialog/executor.hxx index ef667a70ce26..260be394d6b8 100644 --- a/include/vcl/jsdialog/executor.hxx +++ b/include/vcl/jsdialog/executor.hxx @@ -44,6 +44,16 @@ public: rTreeView.signal_row_activated(); } + static void trigger_popup_menu(weld::TreeView& rTreeView, const CommandEvent& rCommand) + { + rTreeView.signal_popup_menu(rCommand); + } + + static void trigger_activated(weld::Menu& rMenu, const OUString& rIdent) + { + rMenu.signal_activate(rIdent); + } + static void trigger_item_activated(weld::IconView& rIconView) { rIconView.signal_item_activated(); diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index e55cf8a205f0..74290a3c9ec7 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1009,6 +1009,8 @@ protected: return m_aEditingDoneHdl.Call(rIterText); } + void signal_popup_menu(const CommandEvent& rCommand) { m_aPopupMenuHdl.Call(rCommand); } + Link<const TreeIter&, OUString> m_aQueryTooltipHdl; OUString signal_query_tooltip(const TreeIter& rIter) { return m_aQueryTooltipHdl.Call(rIter); } @@ -2449,6 +2451,8 @@ enum class Placement class VCL_DLLPUBLIC Menu { + friend class ::LOKTrigger; + Link<const OUString&, void> m_aActivateHdl; protected: diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx b/vcl/inc/jsdialog/jsdialogbuilder.hxx index ec8cef53e238..420722c9997b 100644 --- a/vcl/inc/jsdialog/jsdialogbuilder.hxx +++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx @@ -309,6 +309,7 @@ public: virtual std::unique_ptr<weld::RadioButton> weld_radio_button(const OUString& id) override; virtual std::unique_ptr<weld::Frame> weld_frame(const OUString& id) override; virtual std::unique_ptr<weld::MenuButton> weld_menu_button(const OUString& id) override; + virtual std::unique_ptr<weld::Menu> weld_menu(const OUString& id) override; virtual std::unique_ptr<weld::Popover> weld_popover(const OUString& id) override; virtual std::unique_ptr<weld::Box> weld_box(const OUString& id) override; virtual std::unique_ptr<weld::Widget> weld_widget(const OUString& id) override; @@ -330,6 +331,11 @@ public: static void ForgetPopup(const OUString& nWindowId); static vcl::Window* FindPopup(const OUString& nWindowId); + // menus in separate container as they don't share base class with weld::Widget + static void RememberMenu(const OUString& nWindowId, weld::Menu* pMenu); + static void ForgetMenu(const OUString& nWindowId); + static weld::Menu* FindMenu(const OUString& nWindowId); + private: const OUString& GetTypeOfJSON() const; VclPtr<vcl::Window>& GetContentWindow(); @@ -871,6 +877,16 @@ public: virtual void set_active(bool active) override; }; +class JSMenu final : public SalInstanceMenu +{ +public: + JSMenu(JSDialogSender* pSender, PopupMenu* pMenu, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + + virtual OUString popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect, + weld::Placement ePlace = weld::Placement::Under) override; +}; + class JSPopover : public JSWidget<SalInstancePopover, DockingWindow> { vcl::LOKWindowId mnWindowId; diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index 534e158b4196..c183b7fdb57c 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -146,11 +146,12 @@ public: virtual ~SalInstanceBuilder() override; }; -class SAL_DLLPUBLIC_RTTI SalInstanceMenu final : public weld::Menu +class SAL_DLLPUBLIC_RTTI SalInstanceMenu : public weld::Menu { -private: +protected: VclPtr<PopupMenu> m_xMenu; +private: bool m_bTakeOwnership; sal_uInt16 m_nLastId; diff --git a/vcl/jsdialog/executor.cxx b/vcl/jsdialog/executor.cxx index c6ab95c293e3..bb000d3daa97 100644 --- a/vcl/jsdialog/executor.cxx +++ b/vcl/jsdialog/executor.cxx @@ -74,7 +74,21 @@ bool ExecuteAction(const OUString& nWindowId, const OUString& rWidget, StringMap } } - if (pWidget != nullptr) + if (pWidget == nullptr) + { + // weld::Menu doesn't have base of weld::Widget + if (sControlType == "menu") + { + weld::Menu* pMenu = JSInstanceBuilder::FindMenu(nWindowId); + if (pMenu && sAction == "activated") + { + LOKTrigger::trigger_activated(*pMenu, rData["data"]); + return true; + } + } + return false; + } + else { // shared actions @@ -558,6 +572,18 @@ bool ExecuteAction(const OUString& nWindowId, const OUString& rWidget, StringMap pTreeView->drag_end(); return true; } + else if (sAction == "contextmenu") + { + 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); + + LOKTrigger::trigger_popup_menu(*pTreeView, aCommand); + } } } else if (sControlType == "iconview") diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx index f5459f2e9a5c..5c1e82397f9f 100644 --- a/vcl/jsdialog/jsdialogbuilder.cxx +++ b/vcl/jsdialog/jsdialogbuilder.cxx @@ -13,6 +13,7 @@ #include <comphelper/lok.hxx> #include <iconview.hxx> #include <utility> +#include <vcl/menu.hxx> #include <vcl/svapp.hxx> #include <vcl/toolbox.hxx> #include <vcl/toolkit/button.hxx> @@ -39,6 +40,14 @@ static std::map<OUString, vcl::Window*>& GetLOKPopupsMap() return s_aLOKPopupsMap; } +static std::map<OUString, weld::Menu*>& GetLOKMenusMap() +{ + // Map to remember the LOKWindowId <-> weld menu binding. + static std::map<OUString, weld::Menu*> s_aLOKMenusMap; + + return s_aLOKMenusMap; +} + namespace { void response_help(vcl::Window* pWindow) @@ -318,7 +327,10 @@ JSDialogSender::~JSDialogSender() COVERITY_NOEXCEPT_FALSE void JSDialogSender::sendFullUpdate(bool bForce) { if (!mpIdleNotify) + { + assert(false); return; + } if (bForce) mpIdleNotify->forceUpdate(); @@ -798,6 +810,28 @@ void JSInstanceBuilder::ForgetPopup(const OUString& nWindowId) GetLOKPopupsMap().erase(it); } +void JSInstanceBuilder::RememberMenu(const OUString& nWindowId, weld::Menu* pMenu) +{ + GetLOKMenusMap()[nWindowId] = pMenu; +} + +void JSInstanceBuilder::ForgetMenu(const OUString& nWindowId) +{ + auto it = GetLOKMenusMap().find(nWindowId); + if (it != GetLOKMenusMap().end()) + GetLOKMenusMap().erase(it); +} + +weld::Menu* JSInstanceBuilder::FindMenu(const OUString& nWindowId) +{ + const auto it = GetLOKMenusMap().find(nWindowId); + + if (it != GetLOKMenusMap().end()) + return it->second; + + return nullptr; +} + vcl::Window* JSInstanceBuilder::FindPopup(const OUString& nWindowId) { const auto it = GetLOKPopupsMap().find(nWindowId); @@ -1201,6 +1235,20 @@ std::unique_ptr<weld::MenuButton> JSInstanceBuilder::weld_menu_button(const OUSt return pWeldWidget; } +std::unique_ptr<weld::Menu> JSInstanceBuilder::weld_menu(const OUString& id) +{ + PopupMenu* pPopupMenu = m_xBuilder->get_menu(id); + + JSMenu* pMenu = pPopupMenu ? new JSMenu(this, pPopupMenu, this, false) : nullptr; + + std::unique_ptr<weld::Menu> pWeldWidget(pMenu); + + if (pWeldWidget) + RememberMenu(getMapIdFromWindowId(), pWeldWidget.get()); + + return pWeldWidget; +} + std::unique_ptr<weld::Popover> JSInstanceBuilder::weld_popover(const OUString& id) { DockingWindow* pDockingWindow = m_xBuilder->get<DockingWindow>(id); @@ -2348,6 +2396,22 @@ void JSMenuButton::set_active(bool bActive) } } +JSMenu::JSMenu(JSDialogSender* /*pSender*/, PopupMenu* pPopupMenu, SalInstanceBuilder* /*pBuilder*/, + bool bTakeOwnership) + : SalInstanceMenu(pPopupMenu, bTakeOwnership) +{ +} + +OUString JSMenu::popup_at_rect(weld::Widget* /*pParent*/, const tools::Rectangle& /*rRect*/, + weld::Placement /*ePlace*/) +{ + // TODO: send message + + // first only send menu and cancel menu + // no return SalInstanceMenu::popup_at_rect(pParent, rRect, ePlace); + return ""; +} + JSPopover::JSPopover(JSDialogSender* pSender, DockingWindow* pDockingWindow, SalInstanceBuilder* pBuilder, bool bTakeOwnership) : JSWidget<SalInstancePopover, DockingWindow>(pSender, pDockingWindow, pBuilder, bTakeOwnership)