diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2018-05-22 14:44:39 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2021-05-11 16:08:36 +0200 |
commit | 83d91ebbbda2204af9a09a921055a850a16911e0 (patch) | |
tree | d18f2aca19fbc9d14e8c82392fdd61cef86276c8 | |
parent | 0409c4f5de99a125865af0323036516eb62c5a73 (diff) |
tdf#91874 Command Popup - HUD to search and run LO commands
This adds Command Popup functionality, which is a HUD like pop-up
window, which can be used to search and run commands presented in
the main menu (but not limited to that only).
This is the initial version, which has limitation in searching
and running the command (doesn't work for some currently).
Change-Id: I92cdd3130b8de42ee0863c9e7154e7c7246d9377
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115380
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | include/sfx2/sfxsids.hrc | 2 | ||||
-rw-r--r-- | include/sfx2/viewfrm.hxx | 3 | ||||
-rw-r--r-- | officecfg/registry/data/org/openoffice/Office/Accelerators.xcu | 6 | ||||
-rw-r--r-- | officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu | 8 | ||||
-rw-r--r-- | sc/uiconfig/scalc/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sd/uiconfig/sdraw/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sd/uiconfig/simpress/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sfx2/Library_sfx.mk | 1 | ||||
-rw-r--r-- | sfx2/UIConfig_sfx.mk | 1 | ||||
-rw-r--r-- | sfx2/inc/commandpopup/CommandPopup.hxx | 104 | ||||
-rw-r--r-- | sfx2/sdi/frmslots.sdi | 6 | ||||
-rw-r--r-- | sfx2/sdi/sfx.sdi | 17 | ||||
-rw-r--r-- | sfx2/source/commandpopup/CommandPopup.cxx | 258 | ||||
-rw-r--r-- | sfx2/source/view/viewfrm.cxx | 15 | ||||
-rw-r--r-- | sfx2/uiconfig/ui/commandpopup.ui | 92 | ||||
-rw-r--r-- | sw/uiconfig/sglobal/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sw/uiconfig/sweb/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sw/uiconfig/swform/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sw/uiconfig/swriter/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sw/uiconfig/swxform/menubar/menubar.xml | 1 |
20 files changed, 518 insertions, 3 deletions
diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc index d72bddf3100b..6a420c13b095 100644 --- a/include/sfx2/sfxsids.hrc +++ b/include/sfx2/sfxsids.hrc @@ -387,7 +387,7 @@ class SvxSearchItem; // default-ids for windows -// free (SID_SFX_START + 610) +#define SID_COMMAND_POPUP (SID_SFX_START + 610) #define SID_NEWWINDOW (SID_SFX_START + 620) #define SID_CLOSEWIN (SID_SFX_START + 621) #define SID_VIEWSHELL (SID_SFX_START + 623) diff --git a/include/sfx2/viewfrm.hxx b/include/sfx2/viewfrm.hxx index c01da176b847..4585b722e487 100644 --- a/include/sfx2/viewfrm.hxx +++ b/include/sfx2/viewfrm.hxx @@ -44,6 +44,7 @@ class Size; class SfxChildWindow; class SfxInfoBarWindow; enum class InfobarType; +class CommandPopupHandler; class SFX2_DLLPUBLIC SfxViewFrame: public SfxShell, public SfxListener { @@ -56,6 +57,8 @@ class SFX2_DLLPUBLIC SfxViewFrame: public SfxShell, public SfxListener ImplSVWinData* m_pWinData; sal_uInt16 m_nAdjustPosPixelLock; + std::unique_ptr<CommandPopupHandler> m_pCommandPopupHandler; + private: SAL_DLLPRIVATE void Construct_Impl( SfxObjectShell *pObjSh ); diff --git a/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu b/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu index 5cbde0e93d8f..63c1ad0515e9 100644 --- a/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu +++ b/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu @@ -313,6 +313,12 @@ Ctrl+Shift+e aka E_SHIFT_MOD1 under GTK/IBUS is for some emoji thing <value xml:lang="en-US" install:module="unxwnt">.uno:OptionsTreeDialog</value> </prop> </node> + <node oor:name="F1_MOD1" oor:op="replace"> + <prop oor:name="Command"> + <value xml:lang="x-no-translate">I10N SHORTCUTS - NO TRANSLATE</value> + <value xml:lang="en-US">.uno:CommandPopup</value> + </prop> + </node> <node oor:name="1_MOD1_MOD2" oor:op="replace"> <prop oor:name="Command"> <value xml:lang="x-no-translate">I10N SHORTCUTS - NO TRANSLATE</value> diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index c2088e58db7e..3d9420e76587 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu @@ -6532,6 +6532,14 @@ bit 3 (0x8): #define UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON 8 <value>1</value> </prop> </node> + <node oor:name=".uno:CommandPopup" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Search Commands</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:DevelopmentToolsDockingWindow" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Development Tools</value> diff --git a/sc/uiconfig/scalc/menubar/menubar.xml b/sc/uiconfig/scalc/menubar/menubar.xml index 17916a541c63..eeb746de8432 100644 --- a/sc/uiconfig/scalc/menubar/menubar.xml +++ b/sc/uiconfig/scalc/menubar/menubar.xml @@ -766,6 +766,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sd/uiconfig/sdraw/menubar/menubar.xml b/sd/uiconfig/sdraw/menubar/menubar.xml index 082e9e277929..544155d33f04 100644 --- a/sd/uiconfig/sdraw/menubar/menubar.xml +++ b/sd/uiconfig/sdraw/menubar/menubar.xml @@ -643,6 +643,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sd/uiconfig/simpress/menubar/menubar.xml b/sd/uiconfig/simpress/menubar/menubar.xml index a6efad8be128..fc64d6050e6e 100644 --- a/sd/uiconfig/simpress/menubar/menubar.xml +++ b/sd/uiconfig/simpress/menubar/menubar.xml @@ -674,6 +674,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk index f2fe7c708da7..cab55c2a3335 100644 --- a/sfx2/Library_sfx.mk +++ b/sfx2/Library_sfx.mk @@ -130,6 +130,7 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\ sfx2/source/bastyp/progress \ sfx2/source/bastyp/sfxhtml \ sfx2/source/bastyp/sfxresid \ + sfx2/source/commandpopup/CommandPopup \ sfx2/source/config/evntconf \ sfx2/source/control/asyncfunc \ sfx2/source/control/bindings \ diff --git a/sfx2/UIConfig_sfx.mk b/sfx2/UIConfig_sfx.mk index a9eacafe4c7b..0ba3a5700a7c 100644 --- a/sfx2/UIConfig_sfx.mk +++ b/sfx2/UIConfig_sfx.mk @@ -21,6 +21,7 @@ $(eval $(call gb_UIConfig_add_uifiles,sfx,\ sfx2/uiconfig/ui/classificationbox \ sfx2/uiconfig/ui/cmisinfopage \ sfx2/uiconfig/ui/cmisline \ + sfx2/uiconfig/ui/commandpopup \ sfx2/uiconfig/ui/custominfopage \ sfx2/uiconfig/ui/deck \ sfx2/uiconfig/ui/descriptioninfopage \ diff --git a/sfx2/inc/commandpopup/CommandPopup.hxx b/sfx2/inc/commandpopup/CommandPopup.hxx new file mode 100644 index 000000000000..6344f9253b94 --- /dev/null +++ b/sfx2/inc/commandpopup/CommandPopup.hxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <vcl/layout.hxx> + +#include <sfx2/dllapi.h> +#include <sfx2/viewfrm.hxx> + +#include <vcl/weld.hxx> +#include <vcl/window.hxx> + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/frame/XFrame.hpp> + +struct CurrentEntry final +{ + OUString m_aCommandURL; + OUString m_aTooltip; + + CurrentEntry(OUString const& rCommandURL, OUString const& rTooltip) + : m_aCommandURL(rCommandURL) + , m_aTooltip(rTooltip) + { + } +}; + +struct MenuContent final +{ + OUString m_aCommandURL; + OUString m_aMenuLabel; + OUString m_aFullLabelWithPath; + OUString m_aTooltip; + std::vector<MenuContent> m_aSubMenuContent; +}; + +class MenuContentHandler final +{ +private: + css::uno::Reference<css::frame::XFrame> m_xFrame; + MenuContent m_aMenuContent; + OUString m_sModuleLongName; + +public: + MenuContentHandler(css::uno::Reference<css::frame::XFrame> const& xFrame); + + void gatherMenuContent(css::uno::Reference<css::container::XIndexAccess> const& xIndexAccess, + MenuContent& rMenuContent); + + void findInMenu(OUString const& rText, std::unique_ptr<weld::TreeView>& rpCommandTreeView, + std::vector<CurrentEntry>& rCommandList); + +private: + void findInMenuRecursive(MenuContent const& rMenuContent, OUString const& rText, + std::unique_ptr<weld::TreeView>& rpCommandTreeView, + std::vector<CurrentEntry>& rCommandList); +}; + +class SFX2_DLLPUBLIC CommandListBox final +{ +private: + std::unique_ptr<weld::Builder> mxBuilder; + std::unique_ptr<weld::Popover> mxPopover; + std::unique_ptr<weld::Entry> mpEntry; + std::unique_ptr<weld::TreeView> mpCommandTreeView; + + std::vector<CurrentEntry> maCommandList; + OUString m_PreviousText; + std::unique_ptr<MenuContentHandler> mpMenuContentHandler; + + DECL_LINK(QueryTooltip, const weld::TreeIter&, OUString); + DECL_LINK(RowActivated, weld::TreeView&, bool); + DECL_LINK(ModifyHdl, weld::Entry&, void); + DECL_LINK(SelectionChanged, weld::TreeView&, void); + DECL_LINK(TreeViewKeyPress, const KeyEvent&, bool); + + void dispatchCommandAndClose(OUString const& rCommand); + +public: + CommandListBox(weld::Window* pParent, css::uno::Reference<css::frame::XFrame> const& xFrame); + void connect_closed(const Link<weld::Popover&, void>& rLink) + { + mxPopover->connect_closed(rLink); + } +}; + +class SFX2_DLLPUBLIC CommandPopupHandler final +{ +private: + std::unique_ptr<CommandListBox> mpListBox; + +public: + void showPopup(weld::Window* pParent, css::uno::Reference<css::frame::XFrame> const& xFrame); + DECL_LINK(PopupModeEnd, weld::Popover&, void); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/sdi/frmslots.sdi b/sfx2/sdi/frmslots.sdi index 1e60d092d373..1126a0f195a0 100644 --- a/sfx2/sdi/frmslots.sdi +++ b/sfx2/sdi/frmslots.sdi @@ -266,6 +266,11 @@ interface TopWindow : BrowseWindow ExecMethod = MiscExec_Impl ; StateMethod = MiscState_Impl ; ] + SID_COMMAND_POPUP + [ + ExecMethod = MiscExec_Impl ; + StateMethod = MiscState_Impl ; + ] SID_CLOSEWIN // ole(no) api(final/play/rec) [ ExecMethod = Exec_Impl ; @@ -311,4 +316,3 @@ shell SfxViewFrame StateMethod = GetState_Impl ; ] } - diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index eb588217d940..7ce13e9f7b50 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -1269,6 +1269,23 @@ SfxStringItem FullName SID_DOCFULLNAME GroupId = ; ] +SfxVoidItem CommandPopup SID_COMMAND_POPUP +[ + AutoUpdate = TRUE, + FastCall = FALSE, + ReadOnlyDoc = TRUE, + Toggle = FALSE, + Container = TRUE, + RecordAbsolute = FALSE, + RecordPerSet; + Asynchron; + + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::View; +] SfxBoolItem FullScreen SID_WIN_FULLSCREEN diff --git a/sfx2/source/commandpopup/CommandPopup.cxx b/sfx2/source/commandpopup/CommandPopup.cxx new file mode 100644 index 000000000000..aa2555252b26 --- /dev/null +++ b/sfx2/source/commandpopup/CommandPopup.cxx @@ -0,0 +1,258 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <commandpopup/CommandPopup.hxx> + +#include <workwin.hxx> + +#include <sfx2/msgpool.hxx> +#include <sfx2/bindings.hxx> + +#include <comphelper/processfactory.hxx> +#include <comphelper/dispatchcommand.hxx> + +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/theUICommandDescription.hpp> +#include <com/sun/star/ui/theUICategoryDescription.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/util/URLTransformer.hpp> + +#include <vcl/commandinfoprovider.hxx> + +using namespace css; + +MenuContentHandler::MenuContentHandler(uno::Reference<frame::XFrame> const& xFrame) + : m_xFrame(xFrame) + , m_sModuleLongName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame)) +{ + auto xComponentContext = comphelper::getProcessComponentContext(); + + uno::Reference<ui::XModuleUIConfigurationManagerSupplier> xModuleConfigSupplier; + xModuleConfigSupplier.set(ui::theModuleUIConfigurationManagerSupplier::get(xComponentContext)); + + uno::Reference<ui::XUIConfigurationManager> xConfigurationManager; + xConfigurationManager = xModuleConfigSupplier->getUIConfigurationManager(m_sModuleLongName); + + uno::Reference<container::XIndexAccess> xConfigData; + xConfigData = xConfigurationManager->getSettings("private:resource/menubar/menubar", false); + + gatherMenuContent(xConfigData, m_aMenuContent); +} + +void MenuContentHandler::gatherMenuContent( + uno::Reference<container::XIndexAccess> const& xIndexAccess, MenuContent& rMenuContent) +{ + for (sal_Int32 n = 0; n < xIndexAccess->getCount(); n++) + { + MenuContent aNewContent; + uno::Sequence<beans::PropertyValue> aProperties; + uno::Reference<container::XIndexAccess> xIndexContainer; + + if (!(xIndexAccess->getByIndex(n) >>= aProperties)) + continue; + + bool bIsVisible = true; + bool bIsEnabled = true; + + for (auto const& rProperty : std::as_const(aProperties)) + { + OUString aPropertyName = rProperty.Name; + if (aPropertyName == "CommandURL") + rProperty.Value >>= aNewContent.m_aCommandURL; + else if (aPropertyName == "ItemDescriptorContainer") + rProperty.Value >>= xIndexContainer; + else if (aPropertyName == "IsVisible") + rProperty.Value >>= bIsVisible; + else if (aPropertyName == "Enabled") + rProperty.Value >>= bIsEnabled; + } + + if (!bIsEnabled || !bIsVisible) + continue; + + auto aCommandProperties = vcl::CommandInfoProvider::GetCommandProperties( + aNewContent.m_aCommandURL, m_sModuleLongName); + OUString aLabel = vcl::CommandInfoProvider::GetLabelForCommand(aCommandProperties); + aNewContent.m_aMenuLabel = aLabel; + + if (!rMenuContent.m_aFullLabelWithPath.isEmpty()) + aNewContent.m_aFullLabelWithPath = rMenuContent.m_aFullLabelWithPath + " / "; + aNewContent.m_aFullLabelWithPath += aNewContent.m_aMenuLabel; + + aNewContent.m_aTooltip = vcl::CommandInfoProvider::GetTooltipForCommand( + aNewContent.m_aCommandURL, aCommandProperties, m_xFrame); + + if (xIndexContainer.is()) + gatherMenuContent(xIndexContainer, aNewContent); + + rMenuContent.m_aSubMenuContent.push_back(aNewContent); + } +} + +void MenuContentHandler::findInMenu(OUString const& rText, + std::unique_ptr<weld::TreeView>& rpCommandTreeView, + std::vector<CurrentEntry>& rCommandList) +{ + findInMenuRecursive(m_aMenuContent, rText, rpCommandTreeView, rCommandList); +} + +void MenuContentHandler::findInMenuRecursive(MenuContent const& rMenuContent, OUString const& rText, + std::unique_ptr<weld::TreeView>& rpCommandTreeView, + std::vector<CurrentEntry>& rCommandList) +{ + for (MenuContent const& aSubContent : rMenuContent.m_aSubMenuContent) + { + if (aSubContent.m_aMenuLabel.toAsciiLowerCase().startsWith(rText)) + { + OUString sCommandURL = aSubContent.m_aCommandURL; + util::URL aCommandURL; + aCommandURL.Complete = sCommandURL; + uno::Reference<uno::XComponentContext> xContext + = comphelper::getProcessComponentContext(); + uno::Reference<util::XURLTransformer> xParser = util::URLTransformer::create(xContext); + xParser->parseStrict(aCommandURL); + + auto* pViewFrame = SfxViewFrame::Current(); + + SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool(pViewFrame); + const SfxSlot* pSlot = rSlotPool.GetUnoSlot(aCommandURL.Path); + if (pSlot) + { + std::unique_ptr<SfxPoolItem> pState; + SfxItemState eState + = pViewFrame->GetBindings().QueryState(pSlot->GetSlotId(), pState); + + if (eState != SfxItemState::DISABLED) + { + auto xGraphic + = vcl::CommandInfoProvider::GetXGraphicForCommand(sCommandURL, m_xFrame); + rCommandList.emplace_back(sCommandURL, aSubContent.m_aTooltip); + + auto pIter = rpCommandTreeView->make_iterator(); + rpCommandTreeView->insert(nullptr, -1, &aSubContent.m_aFullLabelWithPath, + nullptr, nullptr, nullptr, false, pIter.get()); + rpCommandTreeView->set_image(*pIter, xGraphic); + } + } + } + findInMenuRecursive(aSubContent, rText, rpCommandTreeView, rCommandList); + } +} + +CommandListBox::CommandListBox(weld::Window* pParent, uno::Reference<frame::XFrame> const& xFrame) + : mxBuilder(Application::CreateBuilder(pParent, "sfx/ui/commandpopup.ui")) + , mxPopover(mxBuilder->weld_popover("CommandPopup")) + , mpEntry(mxBuilder->weld_entry("command_entry")) + , mpCommandTreeView(mxBuilder->weld_tree_view("command_treeview")) + , mpMenuContentHandler(std::make_unique<MenuContentHandler>(xFrame)) +{ + mpEntry->connect_changed(LINK(this, CommandListBox, ModifyHdl)); + mpEntry->connect_key_press(LINK(this, CommandListBox, TreeViewKeyPress)); + mpCommandTreeView->connect_query_tooltip(LINK(this, CommandListBox, QueryTooltip)); + mpCommandTreeView->connect_row_activated(LINK(this, CommandListBox, RowActivated)); + + Size aFrameSize = pParent->get_size(); + + // Set size of the pop-over window + tools::Long nWidth = std::max(tools::Long(400), aFrameSize.Width() / 3); + mpCommandTreeView->set_size_request(nWidth, 400); + + // Set the location of the pop-over window + tools::Rectangle aRect(Point(aFrameSize.Width() / 2, 0), Size(0, 0)); + mxPopover->popup_at_rect(pParent, aRect); + mpEntry->grab_focus(); +} + +IMPL_LINK_NOARG(CommandListBox, QueryTooltip, const weld::TreeIter&, OUString) +{ + size_t nSelected = mpCommandTreeView->get_selected_index(); + if (nSelected < maCommandList.size()) + { + auto const& rCurrent = maCommandList[nSelected]; + return rCurrent.m_aTooltip; + } + return OUString(); +} + +IMPL_LINK_NOARG(CommandListBox, RowActivated, weld::TreeView&, bool) +{ + OUString aCommandURL; + int nSelected = mpCommandTreeView->get_selected_index(); + if (nSelected < int(maCommandList.size())) + { + auto const& rCurrent = maCommandList[nSelected]; + aCommandURL = rCurrent.m_aCommandURL; + } + dispatchCommandAndClose(aCommandURL); + return true; +} + +IMPL_LINK(CommandListBox, TreeViewKeyPress, const KeyEvent&, rKeyEvent, bool) +{ + if (rKeyEvent.GetKeyCode().GetCode() == KEY_DOWN || rKeyEvent.GetKeyCode().GetCode() == KEY_UP) + { + int nDirection = rKeyEvent.GetKeyCode().GetCode() == KEY_DOWN ? 1 : -1; + int nNewIndex = mpCommandTreeView->get_selected_index() + nDirection; + nNewIndex = std::clamp(nNewIndex, 0, mpCommandTreeView->n_children() - 1); + mpCommandTreeView->select(nNewIndex); + mpCommandTreeView->set_cursor(nNewIndex); + return true; + } + else if (rKeyEvent.GetKeyCode().GetCode() == KEY_RETURN) + { + RowActivated(*mpCommandTreeView); + } + + return false; +} + +IMPL_LINK_NOARG(CommandListBox, ModifyHdl, weld::Entry&, void) +{ + mpCommandTreeView->clear(); + maCommandList.clear(); + + OUString sText = mpEntry->get_text(); + if (sText.isEmpty()) + return; + + mpCommandTreeView->freeze(); + mpMenuContentHandler->findInMenu(sText.toAsciiLowerCase(), mpCommandTreeView, maCommandList); + mpCommandTreeView->thaw(); + + if (mpCommandTreeView->n_children() > 0) + { + mpCommandTreeView->set_cursor(0); + mpCommandTreeView->select(0); + } + + mpEntry->grab_focus(); +} + +void CommandListBox::dispatchCommandAndClose(OUString const& rCommand) +{ + mxPopover->popdown(); + + if (!rCommand.isEmpty()) + comphelper::dispatchCommand(rCommand, uno::Sequence<beans::PropertyValue>()); +} + +void CommandPopupHandler::showPopup(weld::Window* pParent, + css::uno::Reference<css::frame::XFrame> const& xFrame) +{ + auto pCommandListBox = std::make_unique<CommandListBox>(pParent, xFrame); + pCommandListBox->connect_closed(LINK(this, CommandPopupHandler, PopupModeEnd)); + mpListBox = std::move(pCommandListBox); +} + +IMPL_LINK_NOARG(CommandPopupHandler, PopupModeEnd, weld::Popover&, void) { mpListBox.reset(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx index 7ffca943cb9b..d8d5bf69465a 100644 --- a/sfx2/source/view/viewfrm.cxx +++ b/sfx2/source/view/viewfrm.cxx @@ -25,6 +25,7 @@ #include <sfx2/viewfrm.hxx> #include <sfx2/classificationhelper.hxx> #include <sfx2/notebookbar/SfxNotebookBar.hxx> +#include <svx/svdview.hxx> #include <com/sun/star/document/MacroExecMode.hpp> #include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/frame/DispatchRecorder.hpp> @@ -45,6 +46,7 @@ #include <svl/undo.hxx> #include <vcl/stdtext.hxx> #include <vcl/weld.hxx> +#include <vcl/weldutils.hxx> #include <svtools/miscopt.hxx> #include <tools/diagnose_ex.h> #include <com/sun/star/container/XIndexAccess.hpp> @@ -91,6 +93,9 @@ #include <unotools/configmgr.hxx> #include <comphelper/sequenceashashmap.hxx> +#include <commandpopup/CommandPopup.hxx> + + using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::ucb; @@ -1693,6 +1698,7 @@ SfxViewFrame::SfxViewFrame , m_pHelpData(CreateSVHelpData()) , m_pWinData(CreateSVWinData()) , m_nAdjustPosPixelLock( 0 ) + , m_pCommandPopupHandler(new CommandPopupHandler) { rFrame.SetCurrentViewFrame_Impl( this ); @@ -2972,8 +2978,15 @@ void SfxViewFrame::MiscExec_Impl( SfxRequest& rReq ) rReq.Done(); break; } + case SID_COMMAND_POPUP: + { + tools::Rectangle aRectangle(Point(0,0), GetWindow().GetSizePixel()); + weld::Window* pParent = weld::GetPopupParent(GetWindow(), aRectangle); + m_pCommandPopupHandler->showPopup(pParent, GetFrame().GetFrameInterface()); - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + rReq.Done(); + break; + } case SID_WIN_FULLSCREEN: { const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot()); diff --git a/sfx2/uiconfig/ui/commandpopup.ui b/sfx2/uiconfig/ui/commandpopup.ui new file mode 100644 index 000000000000..b329d64c6f1e --- /dev/null +++ b/sfx2/uiconfig/ui/commandpopup.ui @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface domain="sfx"> + <requires lib="gtk+" version="3.18"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name icon --> + <column type="GdkPixbuf"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name tooltip --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkPopover" id="CommandPopup"> + <property name="can-focus">False</property> + <property name="position">bottom</property> + <child> + <object class="GtkBox" id="container"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border-width">6</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkEntry" id="command_entry"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="caps-lock-warning">False</property> + <property name="placeholder-text" translatable="yes" context="commandpopup|entry">Search command</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkTreeView" id="command_treeview"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="model">liststore1</property> + <property name="headers-visible">False</property> + <property name="headers-clickable">False</property> + <property name="enable-search">False</property> + <property name="search-column">0</property> + <property name="hover-selection">True</property> + <property name="show-expanders">False</property> + <property name="tooltip-column">2</property> + <property name="activate-on-single-click">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="column"> + <property name="sizing">fixed</property> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderericon"/> + <attributes> + <attribute name="pixbuf">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml b/sw/uiconfig/sglobal/menubar/menubar.xml index 9c8f61f03d28..b8dafe715afe 100644 --- a/sw/uiconfig/sglobal/menubar/menubar.xml +++ b/sw/uiconfig/sglobal/menubar/menubar.xml @@ -787,6 +787,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sw/uiconfig/sweb/menubar/menubar.xml b/sw/uiconfig/sweb/menubar/menubar.xml index 46c1a22f32fc..b8d6bc1b711a 100644 --- a/sw/uiconfig/sweb/menubar/menubar.xml +++ b/sw/uiconfig/sweb/menubar/menubar.xml @@ -653,6 +653,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sw/uiconfig/swform/menubar/menubar.xml b/sw/uiconfig/swform/menubar/menubar.xml index 0e64a2315124..652ea24bfbb4 100644 --- a/sw/uiconfig/swform/menubar/menubar.xml +++ b/sw/uiconfig/swform/menubar/menubar.xml @@ -734,6 +734,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml index afc744f1b415..e71db98f06f7 100644 --- a/sw/uiconfig/swriter/menubar/menubar.xml +++ b/sw/uiconfig/swriter/menubar/menubar.xml @@ -807,6 +807,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> diff --git a/sw/uiconfig/swxform/menubar/menubar.xml b/sw/uiconfig/swxform/menubar/menubar.xml index 7fb669089632..e70d8b7e60de 100644 --- a/sw/uiconfig/swxform/menubar/menubar.xml +++ b/sw/uiconfig/swxform/menubar/menubar.xml @@ -781,6 +781,7 @@ <menu:menuitem menu:id=".uno:ExtendedHelp"/> <menu:menuitem menu:id=".uno:Documentation"/> <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuitem menu:id=".uno:CommandPopup"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:QuestionAnswers"/> <menu:menuitem menu:id=".uno:SendFeedback"/> |