include/vcl/menubtn.hxx | 3 vcl/inc/jsdialog/jsdialogbuilder.hxx | 35 ++++++++- vcl/inc/salvtables.hxx | 4 - vcl/jsdialog/enabled.cxx | 2 vcl/jsdialog/jsdialogbuilder.cxx | 132 ++++++++++++++++++++++++++++++++--- vcl/source/control/menubtn.cxx | 17 ---- vcl/source/window/toolbox2.cxx | 8 +- 7 files changed, 166 insertions(+), 35 deletions(-)
New commits: commit 59812ab6f584173596a4ec96cc29d5f0fa3b561f Author: Szymon Kłos <szymon.k...@collabora.com> AuthorDate: Thu Jun 24 14:31:45 2021 +0200 Commit: Szymon Kłos <szymon.k...@collabora.com> CommitDate: Mon Jun 28 10:12:48 2021 +0200 jsdialog: toolbox popups unify menubutton popups and toolbox dropdowns Change-Id: I61c0c33a17d96f03d6513507bda6d5c8edbc55dd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117786 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Szymon Kłos <szymon.k...@collabora.com> diff --git a/include/vcl/menubtn.hxx b/include/vcl/menubtn.hxx index 8e7c259221c5..ccbd23a041f8 100644 --- a/include/vcl/menubtn.hxx +++ b/include/vcl/menubtn.hxx @@ -79,6 +79,7 @@ public: PopupMenu* GetPopupMenu() const { return mpMenu; } void SetPopover(Window* pWindow); + Window* GetPopover() { return mpFloatingWindow.get(); } OString const & GetCurItemIdent() const { return msCurItemIdent; } @@ -89,8 +90,6 @@ public: void SetCurItemId(); - void DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) override; - }; #endif // INCLUDED_VCL_MENUBTN_HXX diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx b/vcl/inc/jsdialog/jsdialogbuilder.hxx index 4e6324a15fcb..fdd952f93968 100644 --- a/vcl/inc/jsdialog/jsdialogbuilder.hxx +++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx @@ -9,9 +9,10 @@ #pragma once +#include <comphelper/string.hxx> +#include <osl/mutex.hxx> #include <vcl/weld.hxx> #include <vcl/jsdialog/executor.hxx> -#include <comphelper/string.hxx> #include <vcl/sysdata.hxx> #include <vcl/virdev.hxx> #include <vcl/builder.hxx> @@ -28,6 +29,9 @@ #include <unordered_map> #define ACTION_TYPE "action_type" +#define PARENT_ID "parent_id" +#define WINDOW_ID "id" +#define CLOSE_ID "close_id" class ToolBox; class ComboBox; @@ -45,7 +49,8 @@ enum MessageType FullUpdate, WidgetUpdate, Close, - Action + Action, + Popup }; } @@ -101,6 +106,7 @@ class JSDialogNotifyIdle : public Idle bool m_bForce; std::deque<JSDialogMessageInfo> m_aMessageQueue; + osl::Mutex m_aQueueMutex; public: JSDialogNotifyIdle(VclPtr<vcl::Window> aNotifierWindow, VclPtr<vcl::Window> aContentWindow, @@ -120,6 +126,9 @@ private: std::unique_ptr<tools::JsonWriter> generateCloseMessage() const; std::unique_ptr<tools::JsonWriter> generateActionMessage(VclPtr<vcl::Window> pWindow, std::unique_ptr<ActionDataMap> pData) const; + std::unique_ptr<tools::JsonWriter> + generatePopupMessage(VclPtr<vcl::Window> pWindow, OUString sParentId, OUString sCloseId) const; + std::unique_ptr<tools::JsonWriter> generateClosePopupMessage(OUString sWindowId) const; }; class JSDialogSender @@ -140,6 +149,8 @@ public: void sendClose(); virtual void sendUpdate(VclPtr<vcl::Window> pWindow, bool bForce = false); virtual void sendAction(VclPtr<vcl::Window> pWindow, std::unique_ptr<ActionDataMap> pData); + virtual void sendPopup(VclPtr<vcl::Window> pWindow, OUString sParentId, OUString sCloseId); + virtual void sendClosePopup(vcl::LOKWindowId nWindowId); void flush() { mpIdleNotify->Invoke(); } protected: @@ -287,6 +298,10 @@ public: virtual void sendFullUpdate(bool bForce = false) = 0; virtual void sendAction(std::unique_ptr<ActionDataMap> pData) = 0; + + virtual void sendPopup(vcl::Window* pPopup, OUString sParentId, OUString sCloseId) = 0; + + virtual void sendClosePopup(vcl::LOKWindowId nWindowId) = 0; }; template <class BaseInstanceClass, class VclClass> @@ -394,6 +409,18 @@ public: if (!m_bIsFreezed && m_pSender && pData) m_pSender->sendAction(BaseInstanceClass::m_xWidget, std::move(pData)); } + + virtual void sendPopup(vcl::Window* pPopup, OUString sParentId, OUString sCloseId) override + { + if (!m_bIsFreezed && m_pSender) + m_pSender->sendPopup(pPopup, sParentId, sCloseId); + } + + virtual void sendClosePopup(vcl::LOKWindowId nWindowId) override + { + if (!m_bIsFreezed && m_pSender) + m_pSender->sendClosePopup(nWindowId); + } }; class JSDialog : public JSWidget<SalInstanceDialog, ::Dialog> @@ -530,9 +557,13 @@ public: class JSToolbar : public JSWidget<SalInstanceToolbar, ::ToolBox> { + std::map<sal_uInt16, weld::Widget*> m_pPopovers; + public: JSToolbar(JSDialogSender* pSender, ::ToolBox* pToolbox, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_menu_item_active(const OString& rIdent, bool bActive) override; }; class JSTextView : public JSWidget<SalInstanceTextView, ::VclMultiLineEdit> diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index 0a7299af56bf..bbe49cdc0dd4 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -1172,7 +1172,7 @@ public: class SalInstanceToolbar : public SalInstanceWidget, public virtual weld::Toolbar { -private: +protected: VclPtr<ToolBox> m_xToolBox; std::map<sal_uInt16, VclPtr<vcl::Window>> m_aFloats; std::map<sal_uInt16, VclPtr<PopupMenu>> m_aMenus; @@ -1815,7 +1815,7 @@ public: class SalInstanceMenuButton : public SalInstanceButton, public virtual weld::MenuButton { -private: +protected: VclPtr<::MenuButton> m_xMenuButton; sal_uInt16 m_nLastId; diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx index 92f29674d00e..fbb111f59289 100644 --- a/vcl/jsdialog/enabled.cxx +++ b/vcl/jsdialog/enabled.cxx @@ -62,7 +62,7 @@ bool isBuilderEnabled(const OUString& rUIFile, bool bMobile) bool isBuilderEnabledForPopup(const OUString& rUIFile) { - if (rUIFile == "svx/ui/colorwindow.ui") + if (rUIFile == "svx/ui/colorwindow.ui" || rUIFile == "modules/scalc/ui/floatinglinestyle.ui") return true; return false; diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx index 3dbbe8160976..c58eaf00e3fd 100644 --- a/vcl/jsdialog/jsdialogbuilder.cxx +++ b/vcl/jsdialog/jsdialogbuilder.cxx @@ -101,6 +101,8 @@ OUString extractActionType(const ActionDataMap& rData) void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType eType, VclPtr<vcl::Window> pWindow, std::unique_ptr<ActionDataMap> pData) { + m_aQueueMutex.acquire(); + // 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(); @@ -123,6 +125,8 @@ void JSDialogNotifyIdle::sendMessage(jsdialog::MessageType eType, VclPtr<vcl::Wi JSDialogMessageInfo aMessage(eType, pWindow, std::move(pData)); m_aMessageQueue.push_back(aMessage); + + m_aQueueMutex.release(); } std::unique_ptr<tools::JsonWriter> JSDialogNotifyIdle::generateFullUpdate() const @@ -210,9 +214,56 @@ JSDialogNotifyIdle::generateActionMessage(VclPtr<vcl::Window> pWindow, return aJsonWriter; } +std::unique_ptr<tools::JsonWriter> +JSDialogNotifyIdle::generatePopupMessage(VclPtr<vcl::Window> pWindow, OUString sParentId, + OUString sCloseId) const +{ + std::unique_ptr<tools::JsonWriter> aJsonWriter(new tools::JsonWriter()); + + if (!pWindow || !m_aNotifierWindow) + return aJsonWriter; + + pWindow->DumpAsPropertyTree(*aJsonWriter); + + aJsonWriter->put("jsontype", "dialog"); + aJsonWriter->put("type", "modalpopup"); + aJsonWriter->put("cancellable", true); + aJsonWriter->put("popupParent", sParentId); + aJsonWriter->put("clickToClose", sCloseId); + aJsonWriter->put("id", pWindow->GetLOKWindowId()); + + return aJsonWriter; +} + +std::unique_ptr<tools::JsonWriter> +JSDialogNotifyIdle::generateClosePopupMessage(OUString sWindowId) const +{ + std::unique_ptr<tools::JsonWriter> aJsonWriter(new tools::JsonWriter()); + + if (!m_aNotifierWindow) + return aJsonWriter; + + aJsonWriter->put("jsontype", "dialog"); + aJsonWriter->put("action", "close"); + aJsonWriter->put("id", sWindowId); + + return aJsonWriter; +} + void JSDialogNotifyIdle::Invoke() { - for (auto& rMessage : m_aMessageQueue) + bool bAcquired = m_aQueueMutex.acquire(); + + if (!bAcquired) + SAL_WARN("vcl", "JSDialogNotifyIdle::Invoke : mutex cannot be acquired"); + + std::deque<JSDialogMessageInfo> aMessageQueue(std::move(m_aMessageQueue)); + m_aMessageQueue = std::deque<JSDialogMessageInfo>(); + clearQueue(); + + m_aQueueMutex.release(); + + for (auto& rMessage : aMessageQueue) { jsdialog::MessageType eType = rMessage.m_eType; @@ -233,10 +284,21 @@ void JSDialogNotifyIdle::Invoke() case jsdialog::MessageType::Action: send(*generateActionMessage(rMessage.m_pWindow, std::move(rMessage.m_pData))); break; + + case jsdialog::MessageType::Popup: + { + OUString sParentId = (*rMessage.m_pData)[PARENT_ID]; + OUString sWindowId = (*rMessage.m_pData)[WINDOW_ID]; + OUString sCloseId = (*rMessage.m_pData)[CLOSE_ID]; + + if (!sParentId.isEmpty()) + send(*generatePopupMessage(rMessage.m_pWindow, sParentId, sCloseId)); + else if (!sWindowId.isEmpty()) + send(*generateClosePopupMessage(sWindowId)); + break; + } } } - - clearQueue(); } void JSDialogNotifyIdle::clearQueue() { m_aMessageQueue.clear(); } @@ -278,6 +340,23 @@ void JSDialogSender::sendAction(VclPtr<vcl::Window> pWindow, std::unique_ptr<Act mpIdleNotify->Start(); } +void JSDialogSender::sendPopup(VclPtr<vcl::Window> pWindow, OUString sParentId, OUString sCloseId) +{ + std::unique_ptr<ActionDataMap> pData = std::make_unique<ActionDataMap>(); + (*pData)[PARENT_ID] = sParentId; + (*pData)[CLOSE_ID] = sCloseId; + mpIdleNotify->sendMessage(jsdialog::MessageType::Popup, pWindow, std::move(pData)); + mpIdleNotify->Start(); +} + +void JSDialogSender::sendClosePopup(vcl::LOKWindowId nWindowId) +{ + std::unique_ptr<ActionDataMap> pData = std::make_unique<ActionDataMap>(); + (*pData)[WINDOW_ID] = OUString::number(nWindowId); + mpIdleNotify->sendMessage(jsdialog::MessageType::Popup, nullptr, std::move(pData)); + mpIdleNotify->Start(); +} + namespace { vcl::Window* extract_sal_widget(weld::Widget* pParent) @@ -919,9 +998,10 @@ std::unique_ptr<weld::Popover> JSInstanceBuilder::weld_popover(const OString& id if (VclPtr<vcl::Window> pWin = pDockingWindow->GetParentWithLOKNotifier()) { - pDockingWindow->SetLOKNotifier(pWin->GetLOKNotifier()); - m_aParentDialog = pDockingWindow; - m_aWindowToRelease = pDockingWindow; + vcl::Window* pPopupRoot = pDockingWindow->GetChild(0); + pPopupRoot->SetLOKNotifier(pWin->GetLOKNotifier()); + m_aParentDialog = pPopupRoot; + m_aWindowToRelease = pPopupRoot; m_nWindowId = m_aParentDialog->GetLOKWindowId(); InsertWindowToMap(m_nWindowId); initializeSender(GetNotifierWindow(), GetContentWindow(), GetTypeOfJSON()); @@ -1251,6 +1331,32 @@ JSToolbar::JSToolbar(JSDialogSender* pSender, ::ToolBox* pToolbox, SalInstanceBu { } +void JSToolbar::set_menu_item_active(const OString& rIdent, bool bActive) +{ + SalInstanceToolbar::set_menu_item_active(rIdent, bActive); + + sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)); + VclPtr<vcl::Window> pFloat = m_aFloats[nItemId]; + + if (pFloat) + { + // See WeldToolbarPopup : include/svtools/toolbarmenu.hxx + // TopLevel (Popover) -> Container -> main container of the popup + vcl::Window* pPopupRoot = pFloat->GetChild(0); + if (pPopupRoot) + pPopupRoot = pPopupRoot->GetChild(0); + + if (pPopupRoot) + { + if (bActive) + sendPopup(pPopupRoot, m_xToolBox->get_id(), + OStringToOUString(rIdent, RTL_TEXTENCODING_ASCII_US)); + else + sendClosePopup(pPopupRoot->GetLOKWindowId()); + } + } +} + JSTextView::JSTextView(JSDialogSender* pSender, ::VclMultiLineEdit* pTextView, SalInstanceBuilder* pBuilder, bool bTakeOwnership) : JSWidget<SalInstanceTextView, ::VclMultiLineEdit>(pSender, pTextView, pBuilder, @@ -1494,10 +1600,18 @@ void JSMenuButton::set_image(const css::uno::Reference<css::graphic::XGraphic>& sendUpdate(); } -void JSMenuButton::set_active(bool active) +void JSMenuButton::set_active(bool bActive) { - SalInstanceMenuButton::set_active(active); - sendUpdate(); + SalInstanceMenuButton::set_active(bActive); + + VclPtr<vcl::Window> pPopup = m_xMenuButton->GetPopover(); + if (pPopup) + { + if (bActive) + sendPopup(pPopup->GetChild(0), m_xMenuButton->get_id(), m_xMenuButton->get_id()); + else + sendClosePopup(pPopup->GetChild(0)->GetLOKWindowId()); + } } JSPopover::JSPopover(JSDialogSender* pSender, DockingWindow* pDockingWindow, diff --git a/vcl/source/control/menubtn.cxx b/vcl/source/control/menubtn.cxx index a6e809e558fe..bf59cad6c1d6 100644 --- a/vcl/source/control/menubtn.cxx +++ b/vcl/source/control/menubtn.cxx @@ -265,23 +265,6 @@ void MenuButton::SetCurItemId(){ msCurItemIdent = mpMenu->GetCurItemIdent(); } -void MenuButton::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) -{ - Button::DumpAsPropertyTree(rJsonWriter); - if (mpFloatingWindow) - { - auto aPopup = rJsonWriter.startNode("popup"); - if (InPopupMode()) - mpFloatingWindow->DumpAsPropertyTree(rJsonWriter); - else - rJsonWriter.put("action", "close"); - - VclPtr<vcl::Window> pParentWithNotifier = mpFloatingWindow->GetParentWithLOKNotifier(); - if (pParentWithNotifier) - rJsonWriter.put("id", pParentWithNotifier->GetLOKWindowId()); - } -} - //class MenuToggleButton ---------------------------------------------------- MenuToggleButton::MenuToggleButton( vcl::Window* pParent, WinBits nWinBits ) diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx index 2e442923899b..cee2d7dfadbf 100644 --- a/vcl/source/window/toolbox2.cxx +++ b/vcl/source/window/toolbox2.cxx @@ -1747,11 +1747,15 @@ void ToolBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) } else { - if (!IsItemVisible(nId)) - continue; rJsonWriter.put("type", "toolitem"); rJsonWriter.put("text", GetItemText(nId)); rJsonWriter.put("command", GetItemCommand(nId)); + if (!IsItemVisible(nId)) + rJsonWriter.put("visible", false); + if (GetItemBits(nId) & ToolBoxItemBits::DROPDOWN) + rJsonWriter.put("dropdown", true); + if (!IsItemEnabled(nId)) + rJsonWriter.put("enabled", false); } } } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits