sfx2/inc/sidebar/DeckDescriptor.hxx | 1 sfx2/inc/sidebar/DeckTitleBar.hxx | 3 - sfx2/inc/sidebar/TitleBar.hxx | 2 sfx2/source/sidebar/Deck.cxx | 3 - sfx2/source/sidebar/DeckDescriptor.cxx | 1 sfx2/source/sidebar/DeckTitleBar.cxx | 16 +++++- sfx2/source/sidebar/FocusManager.cxx | 84 +++++++++++++------------------- sfx2/source/sidebar/ResourceManager.cxx | 1 sfx2/source/sidebar/TitleBar.cxx | 13 ++++ sfx2/uiconfig/ui/deck.ui | 26 ++++++++- sw/qa/uitest/sidebar/tdf152921.py | 6 +- 11 files changed, 97 insertions(+), 59 deletions(-)
New commits: commit 9ca60dc90958001c078ed6331bd432c36961a425 Author: Rafael Lima <[email protected]> AuthorDate: Wed Jul 26 02:00:40 2023 +0200 Commit: Rafael Lima <[email protected]> CommitDate: Sat Aug 5 00:05:56 2023 +0200 tdf#156156 Add Help button to sidebar decks This patch adds a Help button to the sidebar deck, so that each deck has its own Help ID, which can later be used as reference to write help pages. The Help IDs of each sidebar deck is a combination of the string "SIDEBAR_" + the deck ID (as defined in Sidebar.xcu). Change-Id: Ib7f106ff917e41130bde136e1e6f04bb2af40daf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154918 Tested-by: Jenkins Reviewed-by: Stéphane Guillou <[email protected]> Reviewed-by: Olivier Hallot <[email protected]> diff --git a/sfx2/inc/sidebar/DeckDescriptor.hxx b/sfx2/inc/sidebar/DeckDescriptor.hxx index 5381b4ea2cd7..8fde0c0330f7 100644 --- a/sfx2/inc/sidebar/DeckDescriptor.hxx +++ b/sfx2/inc/sidebar/DeckDescriptor.hxx @@ -34,6 +34,7 @@ public: OUString msTitleBarIconURL; OUString msHighContrastTitleBarIconURL; OUString msHelpText; + OUString msHelpId; ContextList maContextList; bool mbIsEnabled; sal_Int32 mnOrderIndex; diff --git a/sfx2/inc/sidebar/DeckTitleBar.hxx b/sfx2/inc/sidebar/DeckTitleBar.hxx index 72eda5cb7d7b..2834dda1e350 100644 --- a/sfx2/inc/sidebar/DeckTitleBar.hxx +++ b/sfx2/inc/sidebar/DeckTitleBar.hxx @@ -29,7 +29,7 @@ class GripWidget; class DeckTitleBar final : public TitleBar { public: - DeckTitleBar(const OUString& rsTitle, weld::Builder& rBuilder, + DeckTitleBar(const OUString& rsTitle, weld::Builder& rBuilder, const OUString& rsHelpId, std::function<void()> aCloserAction); virtual ~DeckTitleBar() override; @@ -48,6 +48,7 @@ private: std::unique_ptr<weld::CustomWeld> mxGripWeld; std::unique_ptr<weld::Label> mxLabel; + OUString msHelpId; const std::function<void()> maCloserAction; bool mbIsCloserVisible; }; diff --git a/sfx2/inc/sidebar/TitleBar.hxx b/sfx2/inc/sidebar/TitleBar.hxx index 2cd7224bda12..7836a57be17a 100644 --- a/sfx2/inc/sidebar/TitleBar.hxx +++ b/sfx2/inc/sidebar/TitleBar.hxx @@ -56,10 +56,12 @@ protected: std::unique_ptr<weld::Image> mxAddonImage; std::unique_ptr<weld::Toolbar> mxToolBox; Theme::ThemeItem meThemeItem; + OUString msToolBoxRId; virtual void HandleToolBoxItemClick() = 0; DECL_LINK(SelectionHandler, const OUString&, void); + static void ShowHelp(const OUString& rHelpId); private: void SetBackground(); diff --git a/sfx2/source/sidebar/Deck.cxx b/sfx2/source/sidebar/Deck.cxx index 629a1d76d3d0..c45ab52e574e 100644 --- a/sfx2/source/sidebar/Deck.cxx +++ b/sfx2/source/sidebar/Deck.cxx @@ -55,7 +55,8 @@ Deck::Deck(const DeckDescriptor& rDeckDescriptor, SidebarDockingWindow* pParentW , mnMinimalHeight(0) , maPanels() , mxParentWindow(pParentWindow) - , mxTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, *m_xBuilder, rCloserAction)) + , mxTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, *m_xBuilder, + rDeckDescriptor.msHelpId, rCloserAction)) , mxVerticalScrollBar(m_xBuilder->weld_scrolled_window("scrolledwindow")) , mxContents(m_xBuilder->weld_box("contents")) { diff --git a/sfx2/source/sidebar/DeckDescriptor.cxx b/sfx2/source/sidebar/DeckDescriptor.cxx index fee839f08ad0..29af33e33f22 100644 --- a/sfx2/source/sidebar/DeckDescriptor.cxx +++ b/sfx2/source/sidebar/DeckDescriptor.cxx @@ -36,6 +36,7 @@ DeckDescriptor::DeckDescriptor (const DeckDescriptor& rOther) msTitleBarIconURL(rOther.msTitleBarIconURL), msHighContrastTitleBarIconURL(rOther.msHighContrastTitleBarIconURL), msHelpText(rOther.msHelpText), + msHelpId(rOther.msHelpId), maContextList(rOther.maContextList), mbIsEnabled(rOther.mbIsEnabled), mnOrderIndex(rOther.mnOrderIndex), diff --git a/sfx2/source/sidebar/DeckTitleBar.cxx b/sfx2/source/sidebar/DeckTitleBar.cxx index 44b9387dc14d..9e12fd15c6ab 100644 --- a/sfx2/source/sidebar/DeckTitleBar.cxx +++ b/sfx2/source/sidebar/DeckTitleBar.cxx @@ -61,11 +61,13 @@ public: DeckTitleBar::DeckTitleBar (const OUString& rsTitle, weld::Builder& rBuilder, + const OUString& rsHelpId, std::function<void()> aCloserAction) : TitleBar(rBuilder, Theme::Color_DeckTitleBarBackground) , mxGripWidget(new GripWidget) , mxGripWeld(new weld::CustomWeld(rBuilder, "grip", *mxGripWidget)) , mxLabel(rBuilder.weld_label("label")) + , msHelpId(rsHelpId) , maCloserAction(std::move(aCloserAction)) , mbIsCloserVisible(false) { @@ -110,8 +112,18 @@ void DeckTitleBar::SetCloserVisible (const bool bIsCloserVisible) void DeckTitleBar::HandleToolBoxItemClick() { - if (maCloserAction) - maCloserAction(); + if (msToolBoxRId == "btn_help") + { + // Help toolbox button was clicked + DeckTitleBar::ShowHelp(msHelpId); + } + else if ((msToolBoxRId.isEmpty()) || (msToolBoxRId == "btn_close")) + { + if (maCloserAction) + maCloserAction(); + } + // Reset the toolbox response id + msToolBoxRId = ""; } void DeckTitleBar::DataChanged() diff --git a/sfx2/source/sidebar/FocusManager.cxx b/sfx2/source/sidebar/FocusManager.cxx index b77d30a75ba3..75622cde0ae3 100644 --- a/sfx2/source/sidebar/FocusManager.cxx +++ b/sfx2/source/sidebar/FocusManager.cxx @@ -222,7 +222,10 @@ void FocusManager::FocusPanel ( rPanel.SetExpanded(true); pTitleBar->GetExpander().grab_focus(); } - else if (bFallbackToDeckTitle) + // Fallback to deck title should only be applicable when there is more than one panel, + // or else it will never be possible to enter the panel contents when there's a single panel + // withouth a titlebar and expander + else if (bFallbackToDeckTitle && maPanels.size() > 1) { // The panel title is not visible, fall back to the deck // title. @@ -348,11 +351,6 @@ bool FocusManager::HandleKeyEvent( case KEY_RETURN: switch (aLocation.meComponent) { - case PC_DeckToolBox: - FocusButton(0); - bConsumed = true; - break; - case PC_PanelTitle: // Enter the panel. FocusPanelContent(aLocation.mnIndex); @@ -381,19 +379,25 @@ bool FocusManager::HandleKeyEvent( break; case PC_DeckToolBox: - bConsumed = MoveFocusInsideDeckTitle(aLocation, nDirection); + { + // Moves to the first deck activation button that is visible + sal_Int32 nIndex(1); + while(!maButtons[nIndex]->get_visible() && ++nIndex > 0); + FocusButton(nIndex); + bConsumed = true; + } break; case PC_TabBar: if (rKeyCode.IsShift()) - FocusPanel(maPanels.size()-1, true); - else { if (IsDeckTitleVisible()) FocusDeckTitle(); else FocusPanel(0, true); } + else + FocusPanel(0, true); bConsumed = true; break; @@ -424,27 +428,22 @@ bool FocusManager::HandleKeyEvent( bConsumed = true; break; - case PC_DeckToolBox: - { - // Focus the last button. - sal_Int32 nIndex(maButtons.size()-1); - while(!maButtons[nIndex]->get_visible() && --nIndex > 0); - FocusButton(nIndex); - bConsumed = true; - break; - } - case PC_TabBar: - // Go to previous tab bar item. - if (aLocation.mnIndex == 0) - FocusPanel(maPanels.size()-1, true); - else { - sal_Int32 nIndex((aLocation.mnIndex + maButtons.size() - 1) % maButtons.size()); + if (rKeyCode.GetCode() == KEY_LEFT) + break; + + sal_Int32 nIndex; + if (aLocation.mnIndex <= 0) + nIndex = maButtons.size() - 1; + else + nIndex = aLocation.mnIndex - 1; + + // Finds the previous visible button while(!maButtons[nIndex]->get_visible() && --nIndex > 0); FocusButton(nIndex); + bConsumed = true; } - bConsumed = true; break; default: @@ -466,33 +465,22 @@ bool FocusManager::HandleKeyEvent( bConsumed = true; break; - case PC_DeckToolBox: - // Focus the first panel. - if (IsPanelTitleVisible(0)) - FocusPanel(0, false); - else - FocusButton(0); - bConsumed = true; - break; - case PC_TabBar: - // Go to next tab bar item. - if (aLocation.mnIndex < static_cast<sal_Int32>(maButtons.size())-1) { - sal_Int32 nIndex(aLocation.mnIndex + 1); - while(!maButtons[nIndex]->get_visible() && ++nIndex < static_cast<sal_Int32>(maButtons.size())); - if (nIndex < static_cast<sal_Int32>(maButtons.size())) - { - FocusButton(nIndex); - bConsumed = true; + if (rKeyCode.GetCode() == KEY_RIGHT) break; - } + + sal_Int32 nIndex; + if (o3tl::make_unsigned(aLocation.mnIndex) >= maButtons.size() - 1) + nIndex = 0; + else + nIndex = aLocation.mnIndex + 1; + + // Finds the next visible button + while(!maButtons[nIndex]->get_visible() && ++nIndex > 0); + FocusButton(nIndex); + bConsumed = true; } - if (IsDeckTitleVisible()) - FocusDeckTitle(); - else - FocusPanel(0, true); - bConsumed = true; break; default: diff --git a/sfx2/source/sidebar/ResourceManager.cxx b/sfx2/source/sidebar/ResourceManager.cxx index 7989d2820263..d4e5b9722815 100644 --- a/sfx2/source/sidebar/ResourceManager.cxx +++ b/sfx2/source/sidebar/ResourceManager.cxx @@ -278,6 +278,7 @@ void ResourceManager::ReadDeckList() rDeckDescriptor.msTitleBarIconURL = getString(aDeckNode, "TitleBarIconURL"); rDeckDescriptor.msHighContrastTitleBarIconURL = getString(aDeckNode, "HighContrastTitleBarIconURL"); rDeckDescriptor.msHelpText = rDeckDescriptor.msTitle; + rDeckDescriptor.msHelpId = "SIDEBAR_" + rDeckDescriptor.msId.toAsciiUpperCase(); rDeckDescriptor.mnOrderIndex = getInt32(aDeckNode, "OrderIndex"); rDeckDescriptor.mbExperimental = getBool(aDeckNode, "IsExperimental"); diff --git a/sfx2/source/sidebar/TitleBar.cxx b/sfx2/source/sidebar/TitleBar.cxx index edab6d58b811..5bcf712dcf16 100644 --- a/sfx2/source/sidebar/TitleBar.cxx +++ b/sfx2/source/sidebar/TitleBar.cxx @@ -18,6 +18,8 @@ */ #include <sidebar/TitleBar.hxx> +#include <vcl/help.hxx> +#include <vcl/svapp.hxx> namespace sfx2::sidebar { @@ -27,6 +29,7 @@ TitleBar::TitleBar(weld::Builder& rBuilder, Theme::ThemeItem eThemeItem) , mxAddonImage(rBuilder.weld_image("addonimage")) , mxToolBox(rBuilder.weld_toolbar("toolbar")) , meThemeItem(eThemeItem) + , msToolBoxRId("") { SetBackground(); @@ -70,8 +73,16 @@ void TitleBar::SetIcon(const css::uno::Reference<css::graphic::XGraphic>& rIcon) mxAddonImage->set_visible(rIcon.is()); } -IMPL_LINK_NOARG(TitleBar, SelectionHandler, const OUString&, void) +void TitleBar::ShowHelp(const OUString& rHelpId) { + Help* pHelp = Application::GetHelp(); + if (pHelp) + pHelp->Start(rHelpId); +} + +IMPL_LINK(TitleBar, SelectionHandler, const OUString&, rId, void) +{ + msToolBoxRId = rId; HandleToolBoxItemClick(); } diff --git a/sfx2/uiconfig/ui/deck.ui b/sfx2/uiconfig/ui/deck.ui index ca3c96dcfc7f..b4854579b77b 100644 --- a/sfx2/uiconfig/ui/deck.ui +++ b/sfx2/uiconfig/ui/deck.ui @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.38.2 --> +<!-- Generated with glade 3.40.0 --> <interface domain="sfx"> <requires lib="gtk+" version="3.20"/> <!-- n-columns=1 n-rows=2 --> @@ -96,13 +96,33 @@ <property name="show-arrow">False</property> <property name="icon_size">2</property> <child> - <object class="GtkToolButton" id="button"> + <object class="GtkToolButton" id="btn_help"> <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="tooltip-text" translatable="yes" context="deck|SFX_STR_SIDEBAR_HELP_DECK">Help about this sidebar deck</property> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="label">?</property> + <child internal-child="accessible"> + <object class="AtkObject" id="btn_help-atkobject"> + <property name="AtkObject::accessible-name" translatable="yes" context="deck|SFX_STR_SIDEBAR_HELP_DECK">Sidebar Deck Help</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="btn_close"> + <property name="visible">True</property> + <property name="can-focus">False</property> <property name="tooltip-text" translatable="yes" context="deck|SFX_STR_SIDEBAR_CLOSE_DECK">Close Sidebar Deck</property> <property name="use-underline">True</property> <property name="icon-name">window-close-symbolic</property> <child internal-child="accessible"> - <object class="AtkObject" id="button-atkobject"> + <object class="AtkObject" id="btn_close-atkobject"> <property name="AtkObject::accessible-name" translatable="yes" context="deck|SFX_STR_SIDEBAR_CLOSE_DECK">Close Sidebar Deck</property> </object> </child> diff --git a/sw/qa/uitest/sidebar/tdf152921.py b/sw/qa/uitest/sidebar/tdf152921.py index a313343f5690..77f0370e2de1 100644 --- a/sw/qa/uitest/sidebar/tdf152921.py +++ b/sw/qa/uitest/sidebar/tdf152921.py @@ -25,7 +25,7 @@ class tdf152921(UITestCase): # make sure only the tabbar is visible, no deck xDeckTitleToolBar = xWriterEdit.getChild('toolbar') - xDeckTitleToolBar.executeAction("CLICK", mkPropertyValues({"POS": "0"})) + xDeckTitleToolBar.executeAction("CLICK", mkPropertyValues({"POS": "1"})) # tabbar is visible, deck is not # without the patch this assert would fail, a tab would be highlighted self.assertFalse(len(get_state_as_dict(xTabBar)['HighlightedTabsIds'])) @@ -37,7 +37,7 @@ class tdf152921(UITestCase): self.assertEqual(len(get_state_as_dict(xTabBar)['HighlightedTabsIds'].split(",")), 1) # click on the 'Close Sidebar Deck' button in the deck title tool bar - xDeckTitleToolBar.executeAction("CLICK", mkPropertyValues({"POS": "0"})) + xDeckTitleToolBar.executeAction("CLICK", mkPropertyValues({"POS": "1"})) # without the patch this assert would fail, a tab would be highlighted self.assertFalse(len(get_state_as_dict(xTabBar)['HighlightedTabsIds'])) @@ -63,7 +63,7 @@ class tdf152921(UITestCase): self.assertEqual(len(get_state_as_dict(xTabBar)['HighlightedTabsIds'].split(",")), 1) # click on the 'Close Sidebar Deck' button - xDeckTitleToolBar.executeAction("CLICK", mkPropertyValues({"POS": "0"})) + xDeckTitleToolBar.executeAction("CLICK", mkPropertyValues({"POS": "1"})) # without the patch this assert would fail, a tab would be highlighted self.assertFalse(len(get_state_as_dict(xTabBar)['HighlightedTabsIds']))
