LibreOffice Module sfx2 (master) 1
TabBar.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
23#include <sidebar/Tools.hxx>
26
27#include <comphelper/lok.hxx>
29#include <o3tl/safeint.hxx>
30#include <utility>
31#include <vcl/commandevent.hxx>
33#include <vcl/event.hxx>
34#include <vcl/svapp.hxx>
36#include <osl/diagnose.h>
37
38#include "uiobject.hxx"
39
40using namespace css;
41using namespace css::uno;
42
43static int gDefaultWidth;
44
45namespace sfx2::sidebar {
46
47TabBar::TabBar(vcl::Window* pParentWindow,
48 const Reference<frame::XFrame>& rxFrame,
49 std::function<void (const OUString&)> aDeckActivationFunctor,
50 PopupMenuProvider aPopupMenuProvider,
51 SidebarController* rParentSidebarController
52 )
53 : InterimItemWindow(pParentWindow, "sfx/ui/tabbar.ui", "TabBar")
54 , mxFrame(rxFrame)
55 , mxAuxBuilder(Application::CreateBuilder(m_xContainer.get(), "sfx/ui/tabbarcontents.ui"))
56 , mxTempToplevel(mxAuxBuilder->weld_box("toplevel"))
57 , mxContents(mxAuxBuilder->weld_widget("TabBarContents"))
58 , mxMeasureBox(mxAuxBuilder->weld_widget("measure"))
59 , maDeckActivationFunctor(std::move(aDeckActivationFunctor))
60 , maPopupMenuProvider(std::move(aPopupMenuProvider))
61 , pParentSidebarController(rParentSidebarController)
62{
63 set_id("TabBar"); // for uitest
64
65 InitControlBase(mxMenuButton.get());
66
67 mxTempToplevel->move(mxContents.get(), m_xContainer.get());
68
69 // For Gtk4 defer menu_button until after the contents have been
70 // transferred to its final home (where the old parent is a GtkWindow to
71 // support loading the accelerators in the menu for Gtk3)
72 mxMenuButton = mxAuxBuilder->weld_menu_button("menubutton");
73 mxMainMenu = mxAuxBuilder->weld_menu("mainmenu");
74 mxSubMenu = mxAuxBuilder->weld_menu("submenu");
75
76 gDefaultWidth = m_xContainer->get_preferred_size().Width();
77
78 // we have this widget just so we can measure best width for static TabBar::GetDefaultWidth
79 mxMeasureBox->hide();
80
82
83 mxMenuButton->connect_toggled(LINK(this, TabBar, OnToolboxClicked));
84
85#ifdef DEBUG
86 SetText(OUString("TabBar"));
87#endif
88}
89
91{
93}
94
96{
97 maItems.clear();
98 mxMeasureBox.reset();
99 mxSubMenu.reset();
100 mxMainMenu.reset();
101 mxMenuButton.reset();
102 m_xContainer->move(mxContents.get(), mxTempToplevel.get());
103 mxContents.reset();
104 mxTempToplevel.reset();
105 mxAuxBuilder.reset();
107}
108
110{
111 if (!gDefaultWidth)
112 {
113 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "sfx/ui/tabbarcontents.ui"));
114 std::unique_ptr<weld::Widget> xContainer(xBuilder->weld_widget("TabBarContents"));
115 gDefaultWidth = xContainer->get_preferred_size().Width();
116 }
117 return gDefaultWidth;
118}
119
121{
122 // invisible with LOK, so keep empty to avoid invalidations
124 return;
125
126 // Remove the current buttons.
127 maItems.clear();
128 for (auto const& deck : rDecks)
129 {
130 std::shared_ptr<DeckDescriptor> xDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(deck.msId);
131 if (xDescriptor == nullptr)
132 {
133 OSL_ASSERT(xDescriptor!=nullptr);
134 continue;
135 }
136
137 maItems.emplace_back(std::make_unique<Item>(*this));
138 auto& xItem(maItems.back());
139 xItem->msDeckId = xDescriptor->msId;
140 CreateTabItem(*xItem->mxButton, *xDescriptor);
141 xItem->mxButton->connect_clicked(LINK(xItem.get(), TabBar::Item, HandleClick));
142 xItem->maDeckActivationFunctor = maDeckActivationFunctor;
143 xItem->mbIsHidden = !xDescriptor->mbIsEnabled;
144 xItem->mbIsHiddenByDefault = xItem->mbIsHidden; // the default is the state while creating
145
146 xItem->mxButton->set_sensitive(deck.mbIsEnabled);
147 }
148
150}
151
153{
154 for (auto const& item : maItems)
155 {
156 std::shared_ptr<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item->msDeckId);
157 if (!xDeckDescriptor)
158 continue;
159 item->mxButton->set_item_image("toggle", GetItemImage(*xDeckDescriptor));
160 }
161}
162
163void TabBar::HighlightDeck(std::u16string_view rsDeckId)
164{
165 for (auto const& item : maItems)
166 item->mxButton->set_item_active("toggle", item->msDeckId == rsDeckId);
167}
168
170{
171 for (auto const& item : maItems)
172 item->mxButton->set_item_active("toggle", false);
173}
174
175void TabBar::DataChanged(const DataChangedEvent& rDataChangedEvent)
176{
179
180 InterimItemWindow::DataChanged(rDataChangedEvent);
181}
182
184{
185 NotifyEventType nType = rEvent.GetType();
186 if(NotifyEventType::KEYINPUT == nType)
187 {
188 const vcl::KeyCode& rKeyCode = rEvent.GetKeyEvent()->GetKeyCode();
189 if (!mpAccel)
190 {
193 }
194 const OUString aCommand(mpAccel->findCommand(svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyCode)));
195 if (".uno:Sidebar" == aCommand ||
196 (rKeyCode.IsMod1() && rKeyCode.IsShift() && rKeyCode.GetCode() == KEY_F10))
197 return InterimItemWindow::EventNotify(rEvent);
198 return true;
199 }
200 else if(NotifyEventType::COMMAND == nType)
201 {
202 const CommandEvent& rCommandEvent = *rEvent.GetCommandEvent();
203 if(rCommandEvent.GetCommand() == CommandEventId::Wheel)
204 {
205 const CommandWheelData* pData = rCommandEvent.GetWheelData();
206 if(!pData->GetModifier() && (pData->GetMode() == CommandWheelMode::SCROLL))
207 {
208 auto pItem = std::find_if(maItems.begin(), maItems.end(),
209 [] (const auto& item) { return item->mxButton->get_item_active("toggle"); });
210 if(pItem == maItems.end())
211 return true;
212 if(pData->GetNotchDelta()<0)
213 {
214 if(pItem+1 == maItems.end())
215 return true;
216 ++pItem;
217 }
218 else
219 {
220 if(pItem == maItems.begin())
221 return true;
222 --pItem;
223 }
224 try
225 {
226 (*pItem)->maDeckActivationFunctor((*pItem)->msDeckId);
227 }
228 catch(const css::uno::Exception&) {};
229 return true;
230 }
231 }
232 }
233 return false;
234}
235
236void TabBar::CreateTabItem(weld::Toolbar& rItem, const DeckDescriptor& rDeckDescriptor)
237{
238 rItem.set_accessible_name(rDeckDescriptor.msTitle);
239 rItem.set_accessible_description(rDeckDescriptor.msHelpText);
240 rItem.set_tooltip_text(rDeckDescriptor.msHelpText);
241 const OUString sCommand = ".uno:SidebarDeck." + rDeckDescriptor.msId;
242 OUString sShortcut = vcl::CommandInfoProvider::GetCommandShortcut(sCommand, mxFrame);
243 if (!sShortcut.isEmpty())
244 sShortcut = u" (" + sShortcut + u")";
245 rItem.set_item_tooltip_text("toggle", rDeckDescriptor.msHelpText + sShortcut);
246}
247
248css::uno::Reference<css::graphic::XGraphic> TabBar::GetItemImage(const DeckDescriptor& rDeckDescriptor) const
249{
250 return Tools::GetImage(
251 rDeckDescriptor.msIconURL,
252 rDeckDescriptor.msHighContrastIconURL,
253 mxFrame);
254}
255
257 : mrTabBar(rTabBar)
258 , mxBuilder(Application::CreateBuilder(rTabBar.GetContainer(), "sfx/ui/tabbutton.ui"))
259 , mxButton(mxBuilder->weld_toolbar("button"))
260 , mbIsHidden(false)
261 , mbIsHiddenByDefault(false)
262{
263}
264
266{
267 mrTabBar.GetContainer()->move(mxButton.get(), nullptr);
268}
269
270IMPL_LINK_NOARG(TabBar::Item, HandleClick, const OUString&, void)
271{
272 // tdf#143146 copy the functor and arg before calling
273 // GrabFocusToDocument which may destroy this object
274 auto aDeckActivationFunctor = maDeckActivationFunctor;
275 auto sDeckId = msDeckId;
276
277 mrTabBar.GrabFocusToDocument();
278 try
279 {
280 aDeckActivationFunctor(sDeckId);
281 }
282 catch(const css::uno::Exception&)
283 {} // workaround for #i123198#
284}
285
286OUString const & TabBar::GetDeckIdForIndex (const sal_Int32 nIndex) const
287{
288 if (nIndex<0 || o3tl::make_unsigned(nIndex)>=maItems.size())
289 throw RuntimeException();
290 return maItems[nIndex]->msDeckId;
291}
292
293void TabBar::ToggleHideFlag (const sal_Int32 nIndex)
294{
295 if (nIndex<0 || o3tl::make_unsigned(nIndex) >= maItems.size())
296 throw RuntimeException();
297
298 maItems[nIndex]->mbIsHidden = ! maItems[nIndex]->mbIsHidden;
299
300 std::shared_ptr<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(maItems[nIndex]->msDeckId);
301 if (xDeckDescriptor)
302 {
303 xDeckDescriptor->mbIsEnabled = ! maItems[nIndex]->mbIsHidden;
304
305 Context aContext;
307 // leave aContext.msContext on default 'any' ... this func is used only for decks
308 // and we don't have context-sensitive decks anyway
309
310 xDeckDescriptor->maContextList.ToggleVisibilityForContext(
311 aContext, xDeckDescriptor->mbIsEnabled );
312 }
313}
314
316{
317 for (auto & item : maItems)
318 {
319 if (item->mbIsHidden != item->mbIsHiddenByDefault)
320 {
321 item->mbIsHidden = item->mbIsHiddenByDefault;
322 std::shared_ptr<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item->msDeckId);
323 if (xDeckDescriptor)
324 xDeckDescriptor->mbIsEnabled = !item->mbIsHidden;
325
326 }
327 }
328}
329
331{
332 std::vector<weld::Widget*> aButtons;
333 aButtons.reserve(maItems.size()+1);
334 aButtons.push_back(mxMenuButton.get());
335 for (auto const& item : maItems)
336 {
337 aButtons.push_back(item->mxButton.get());
338 }
339 rFocusManager.SetButtons(aButtons);
340}
341
342IMPL_LINK_NOARG(TabBar, OnToolboxClicked, weld::Toggleable&, void)
343{
344 if (!mxMenuButton->get_active())
345 return;
346
347 std::vector<DeckMenuData> aMenuData;
348
349 for (auto const& item : maItems)
350 {
351 std::shared_ptr<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item->msDeckId);
352
353 if (!xDeckDescriptor)
354 continue;
355
356 DeckMenuData aData;
357 aData.msDisplayName = xDeckDescriptor->msTitle;
358 aData.mbIsCurrentDeck = item->mxButton->get_item_active("toggle");
359 aData.mbIsActive = !item->mbIsHidden;
360 aData.mbIsEnabled = item->mxButton->get_sensitive();
361 aMenuData.push_back(aData);
362 }
363
364 for (int i = mxMainMenu->n_children() - 1; i >= 0; --i)
365 {
366 OUString sIdent = mxMainMenu->get_id(i);
367 if (sIdent.startsWith("select"))
368 mxMainMenu->remove(sIdent);
369 }
370 for (int i = mxSubMenu->n_children() - 1; i >= 0; --i)
371 {
372 OUString sIdent = mxSubMenu->get_id(i);
373 if (sIdent.indexOf("customize") != -1)
374 mxSubMenu->remove(sIdent);
375 }
376
378}
379
380void TabBar::EnableMenuButton(const bool bEnable)
381{
382 mxMenuButton->set_sensitive(bEnable);
383}
384
386{
388}
389
390} // end of namespace sfx2::sidebar
391
392/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static int gDefaultWidth
Definition: TabBar.cxx:43
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
CommandEventId GetCommand() const
const CommandWheelData * GetWheelData() const
virtual bool EventNotify(NotifyEvent &rNEvt) override
virtual void dispose() override
std::unique_ptr< weld::Container > m_xContainer
const vcl::KeyCode & GetKeyCode() const
const KeyEvent * GetKeyEvent() const
const CommandEvent * GetCommandEvent() const
NotifyEventType GetType() const
OUString msApplication
Definition: Context.hxx:30
Concentrate all focus handling in this class.
void SetButtons(const std::vector< weld::Widget * > &rButtons)
std::shared_ptr< DeckDescriptor > GetDeckDescriptor(std::u16string_view rsDeckId) const
std::vector< DeckContextDescriptor > DeckContextDescriptorContainer
const Context & GetCurrentContext() const
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
Definition: uiobject.cxx:50
Item(TabBar &rTabBar)
Definition: TabBar.cxx:256
The tab bar is the container for the individual tabs.
Definition: TabBar.hxx:41
std::unique_ptr< weld::Menu > mxSubMenu
Definition: TabBar.hxx:102
std::unique_ptr< weld::Widget > mxContents
Definition: TabBar.hxx:98
std::unique_ptr< weld::Menu > mxMainMenu
Definition: TabBar.hxx:101
virtual bool EventNotify(NotifyEvent &rEvent) override
Definition: TabBar.cxx:183
void UpdateFocusManager(FocusManager &rFocusManager)
Definition: TabBar.cxx:330
void SetDecks(const ResourceManager::DeckContextDescriptorContainer &rDecks)
Definition: TabBar.cxx:120
virtual FactoryFunction GetUITestFactory() const override
Definition: TabBar.cxx:385
void RemoveDeckHighlight()
Definition: TabBar.cxx:169
SidebarController * pParentSidebarController
Definition: TabBar.hxx:130
void HighlightDeck(std::u16string_view rsDeckId)
Definition: TabBar.cxx:163
virtual void DataChanged(const DataChangedEvent &rDataChangedEvent) override
Definition: TabBar.cxx:175
std::unique_ptr< weld::Widget > mxMeasureBox
Definition: TabBar.hxx:103
std::unique_ptr< weld::MenuButton > mxMenuButton
Definition: TabBar.hxx:100
void CreateTabItem(weld::Toolbar &rButton, const DeckDescriptor &rDeckDescriptor)
Definition: TabBar.cxx:236
css::uno::Reference< css::frame::XFrame > mxFrame
Definition: TabBar.hxx:91
void EnableMenuButton(const bool bEnable)
Enables/Disables the menu button. Used by LoKit.
Definition: TabBar.cxx:380
PopupMenuProvider maPopupMenuProvider
Definition: TabBar.hxx:122
void UpdateButtonIcons()
Definition: TabBar.cxx:152
std::unique_ptr< svt::AcceleratorExecute > mpAccel
Definition: TabBar.hxx:131
ItemContainer maItems
Definition: TabBar.hxx:120
const ::std::function< void(const OUString &rsDeckId)> maDeckActivationFunctor
Definition: TabBar.hxx:121
TabBar(vcl::Window *pParentWindow, const css::uno::Reference< css::frame::XFrame > &rxFrame, ::std::function< void(const OUString &rsDeckId)> aDeckActivationFunctor, PopupMenuProvider aPopupMenuProvider, SidebarController *rParentSidebarController)
OUString const & GetDeckIdForIndex(const sal_Int32 nIndex) const
Definition: TabBar.cxx:286
virtual ~TabBar() override
Definition: TabBar.cxx:90
css::uno::Reference< css::graphic::XGraphic > GetItemImage(const DeckDescriptor &rDeskDescriptor) const
Definition: TabBar.cxx:248
static sal_Int32 GetDefaultWidth()
Definition: TabBar.cxx:109
void ToggleHideFlag(const sal_Int32 nIndex)
Definition: TabBar.cxx:293
virtual void dispose() override
Definition: TabBar.cxx:95
std::unique_ptr< weld::Builder > mxAuxBuilder
Definition: TabBar.hxx:96
std::unique_ptr< weld::Box > mxTempToplevel
Definition: TabBar.hxx:97
static Color GetColor(const ThemeItem eItem)
Definition: Theme.cxx:49
static css::uno::Reference< css::graphic::XGraphic > GetImage(const OUString &rsImageURL, const OUString &rsHighContrastImageURL, const css::uno::Reference< css::frame::XFrame > &rxFrame)
static css::awt::KeyEvent st_VCLKey2AWTKey(const vcl::KeyCode &aKey)
static std::unique_ptr< AcceleratorExecute > createAcceleratorHelper()
bool IsMod1() const
sal_uInt16 GetCode() const
bool IsShift() const
virtual void DataChanged(const DataChangedEvent &rDCEvt)
void SetBackground()
virtual void set_item_tooltip_text(const OUString &rIdent, const OUString &rTip)=0
virtual void set_accessible_name(const OUString &rName)=0
virtual void set_tooltip_text(const OUString &rTip)=0
virtual void set_accessible_description(const OUString &rDescription)=0
virtual void SetText(const OUString &rStr) override
float u
NotifyEventType
std::function< std::unique_ptr< UIObject >(vcl::Window *)> FactoryFunction
sal_Int32 nIndex
constexpr sal_uInt16 KEY_F10
DdeData aData
Definition: lnkbase2.cxx:82
std::unique_ptr< sal_Int32[]> pData
Reference< XComponentContext > getProcessComponentContext()
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
IMPL_LINK_NOARG(AsynchronousCall, HandleUserCall, void *, void)
OUString GetCommandShortcut(const OUString &rsCommandName, const Reference< frame::XFrame > &rxFrame)
Reference< XNameAccess > m_xContainer
QPRO_FUNC_TYPE nType
OUString aCommand