1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/sidebar/TabBar.hxx>
21 #include <sidebar/DeckDescriptor.hxx>
22 #include <sfx2/sidebar/Theme.hxx>
23 #include <sidebar/Tools.hxx>
24 #include <sfx2/sidebar/FocusManager.hxx>
25 #include <sfx2/sidebar/SidebarController.hxx>
27 #include <comphelper/lok.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <o3tl/safeint.hxx>
30 #include <vcl/commandevent.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/svapp.hxx>
33 #include <svtools/acceleratorexecute.hxx>
36 using namespace css::uno
;
38 static int gDefaultWidth
;
40 namespace sfx2::sidebar
{
42 TabBar::TabBar(vcl::Window
* pParentWindow
,
43 const Reference
<frame::XFrame
>& rxFrame
,
44 const std::function
<void (const OUString
&)>& rDeckActivationFunctor
,
45 const PopupMenuProvider
& rPopupMenuProvider
,
46 SidebarController
* rParentSidebarController
48 : InterimItemWindow(pParentWindow
, "sfx/ui/tabbar.ui", "TabBar")
50 , mxAuxBuilder(Application::CreateBuilder(m_xContainer
.get(), "sfx/ui/tabbarcontents.ui"))
51 , mxTempToplevel(mxAuxBuilder
->weld_box("toplevel"))
52 , mxContents(mxAuxBuilder
->weld_widget("TabBarContents"))
53 , mxMenuButton(mxAuxBuilder
->weld_menu_button("menubutton"))
54 , mxMainMenu(mxAuxBuilder
->weld_menu("mainmenu"))
55 , mxSubMenu(mxAuxBuilder
->weld_menu("submenu"))
56 , mxMeasureBox(mxAuxBuilder
->weld_widget("measure"))
57 , maDeckActivationFunctor(rDeckActivationFunctor
)
58 , maPopupMenuProvider(rPopupMenuProvider
)
59 , pParentSidebarController(rParentSidebarController
)
61 InitControlBase(mxMenuButton
.get());
63 mxTempToplevel
->move(mxContents
.get(), m_xContainer
.get());
65 gDefaultWidth
= m_xContainer
->get_preferred_size().Width();
67 // we have this widget just so we can measure best width for static TabBar::GetDefaultWidth
70 SetBackground(Wallpaper(Theme::GetColor(Theme::Color_TabBarBackground
)));
72 mxMenuButton
->connect_toggled(LINK(this, TabBar
, OnToolboxClicked
));
75 SetText(OUString("TabBar"));
84 void TabBar::dispose()
86 m_xContainer
->move(mxContents
.get(), mxTempToplevel
.get());
93 InterimItemWindow::dispose();
96 sal_Int32
TabBar::GetDefaultWidth()
100 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(nullptr, "sfx/ui/tabbarcontents.ui"));
101 std::unique_ptr
<weld::Widget
> xContainer(xBuilder
->weld_widget("TabBarContents"));
102 gDefaultWidth
= xContainer
->get_preferred_size().Width();
104 return gDefaultWidth
;
107 void TabBar::SetDecks(const ResourceManager::DeckContextDescriptorContainer
& rDecks
)
109 // invisible with LOK, so keep empty to avoid invalidations
110 if (comphelper::LibreOfficeKit::isActive())
113 // Remove the current buttons.
115 for (auto const& deck
: rDecks
)
117 std::shared_ptr
<DeckDescriptor
> xDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(deck
.msId
);
118 if (xDescriptor
== nullptr)
120 OSL_ASSERT(xDescriptor
!=nullptr);
124 maItems
.emplace_back(std::make_unique
<Item
>(*this));
125 auto& xItem(maItems
.back());
126 xItem
->msDeckId
= xDescriptor
->msId
;
127 CreateTabItem(*xItem
->mxButton
, *xDescriptor
);
128 xItem
->mxButton
->connect_clicked(LINK(xItem
.get(), TabBar::Item
, HandleClick
));
129 xItem
->maDeckActivationFunctor
= maDeckActivationFunctor
;
130 xItem
->mbIsHidden
= !xDescriptor
->mbIsEnabled
;
131 xItem
->mbIsHiddenByDefault
= xItem
->mbIsHidden
; // the default is the state while creating
133 xItem
->mxButton
->set_sensitive(deck
.mbIsEnabled
);
139 void TabBar::UpdateButtonIcons()
141 for (auto const& item
: maItems
)
143 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(item
->msDeckId
);
144 if (!xDeckDescriptor
)
146 item
->mxButton
->set_item_image("toggle", GetItemImage(*xDeckDescriptor
));
150 void TabBar::HighlightDeck(std::u16string_view rsDeckId
)
152 for (auto const& item
: maItems
)
153 item
->mxButton
->set_item_active("toggle", item
->msDeckId
== rsDeckId
);
156 void TabBar::RemoveDeckHighlight()
158 for (auto const& item
: maItems
)
159 item
->mxButton
->set_item_active("toggle", false);
162 void TabBar::DataChanged(const DataChangedEvent
& rDataChangedEvent
)
164 SetBackground(Theme::GetColor(Theme::Color_TabBarBackground
));
167 InterimItemWindow::DataChanged(rDataChangedEvent
);
170 bool TabBar::EventNotify(NotifyEvent
& rEvent
)
172 MouseNotifyEvent nType
= rEvent
.GetType();
173 if(MouseNotifyEvent::KEYINPUT
== nType
)
175 const vcl::KeyCode
& rKeyCode
= rEvent
.GetKeyEvent()->GetKeyCode();
178 mpAccel
= svt::AcceleratorExecute::createAcceleratorHelper();
179 mpAccel
->init(comphelper::getProcessComponentContext(), mxFrame
);
181 const OUString
aCommand(mpAccel
->findCommand(svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyCode
)));
182 if (".uno:Sidebar" == aCommand
||
183 (rKeyCode
.IsMod1() && rKeyCode
.IsShift() && rKeyCode
.GetCode() == KEY_F10
))
184 return InterimItemWindow::EventNotify(rEvent
);
187 else if(MouseNotifyEvent::COMMAND
== nType
)
189 const CommandEvent
& rCommandEvent
= *rEvent
.GetCommandEvent();
190 if(rCommandEvent
.GetCommand() == CommandEventId::Wheel
)
192 const CommandWheelData
* pData
= rCommandEvent
.GetWheelData();
193 if(!pData
->GetModifier() && (pData
->GetMode() == CommandWheelMode::SCROLL
))
195 auto pItem
= std::find_if(maItems
.begin(), maItems
.end(),
196 [] (const auto& item
) { return item
->mxButton
->get_item_active("toggle"); });
197 if(pItem
== maItems
.end())
199 if(pData
->GetNotchDelta()<0)
201 if(pItem
+1 == maItems
.end())
207 if(pItem
== maItems
.begin())
213 (*pItem
)->maDeckActivationFunctor((*pItem
)->msDeckId
);
215 catch(const css::uno::Exception
&) {};
223 void TabBar::CreateTabItem(weld::Toolbar
& rItem
, const DeckDescriptor
& rDeckDescriptor
)
225 rItem
.set_accessible_name(rDeckDescriptor
.msTitle
);
226 rItem
.set_accessible_description(rDeckDescriptor
.msHelpText
);
227 rItem
.set_tooltip_text(rDeckDescriptor
.msHelpText
);
228 rItem
.set_item_tooltip_text("toggle", rDeckDescriptor
.msHelpText
);
231 css::uno::Reference
<css::graphic::XGraphic
> TabBar::GetItemImage(const DeckDescriptor
& rDeckDescriptor
) const
233 return Tools::GetImage(
234 rDeckDescriptor
.msIconURL
,
235 rDeckDescriptor
.msHighContrastIconURL
,
239 TabBar::Item::Item(TabBar
& rTabBar
)
241 , mxBuilder(Application::CreateBuilder(rTabBar
.GetContainer(), "sfx/ui/tabbutton.ui"))
242 , mxButton(mxBuilder
->weld_toolbar("button"))
244 , mbIsHiddenByDefault(false)
248 TabBar::Item::~Item()
250 mrTabBar
.GetContainer()->move(mxButton
.get(), nullptr);
253 IMPL_LINK_NOARG(TabBar::Item
, HandleClick
, const OString
&, void)
255 // tdf#143146 copy the functor and arg before calling
256 // GrabFocusToDocument which may destroy this object
257 auto aDeckActivationFunctor
= maDeckActivationFunctor
;
258 auto sDeckId
= msDeckId
;
260 mrTabBar
.GrabFocusToDocument();
263 aDeckActivationFunctor(sDeckId
);
265 catch(const css::uno::Exception
&)
266 {} // workaround for #i123198#
269 OUString
const & TabBar::GetDeckIdForIndex (const sal_Int32 nIndex
) const
271 if (nIndex
<0 || o3tl::make_unsigned(nIndex
)>=maItems
.size())
272 throw RuntimeException();
273 return maItems
[nIndex
]->msDeckId
;
276 void TabBar::ToggleHideFlag (const sal_Int32 nIndex
)
278 if (nIndex
<0 || o3tl::make_unsigned(nIndex
) >= maItems
.size())
279 throw RuntimeException();
281 maItems
[nIndex
]->mbIsHidden
= ! maItems
[nIndex
]->mbIsHidden
;
283 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(maItems
[nIndex
]->msDeckId
);
286 xDeckDescriptor
->mbIsEnabled
= ! maItems
[nIndex
]->mbIsHidden
;
289 aContext
.msApplication
= pParentSidebarController
->GetCurrentContext().msApplication
;
290 // leave aContext.msContext on default 'any' ... this func is used only for decks
291 // and we don't have context-sensitive decks anyway
293 xDeckDescriptor
->maContextList
.ToggleVisibilityForContext(
294 aContext
, xDeckDescriptor
->mbIsEnabled
);
298 void TabBar::RestoreHideFlags()
300 for (auto & item
: maItems
)
302 if (item
->mbIsHidden
!= item
->mbIsHiddenByDefault
)
304 item
->mbIsHidden
= item
->mbIsHiddenByDefault
;
305 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(item
->msDeckId
);
307 xDeckDescriptor
->mbIsEnabled
= !item
->mbIsHidden
;
313 void TabBar::UpdateFocusManager(FocusManager
& rFocusManager
)
315 std::vector
<weld::Widget
*> aButtons
;
316 aButtons
.reserve(maItems
.size()+1);
317 aButtons
.push_back(mxMenuButton
.get());
318 for (auto const& item
: maItems
)
320 aButtons
.push_back(item
->mxButton
.get());
322 rFocusManager
.SetButtons(aButtons
);
325 IMPL_LINK_NOARG(TabBar
, OnToolboxClicked
, weld::Toggleable
&, void)
327 if (!mxMenuButton
->get_active())
330 std::vector
<DeckMenuData
> aMenuData
;
332 for (auto const& item
: maItems
)
334 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(item
->msDeckId
);
336 if (!xDeckDescriptor
)
340 aData
.msDisplayName
= xDeckDescriptor
->msTitle
;
341 aData
.mbIsCurrentDeck
= item
->mxButton
->get_item_active("toggle");
342 aData
.mbIsActive
= !item
->mbIsHidden
;
343 aData
.mbIsEnabled
= item
->mxButton
->get_sensitive();
344 aMenuData
.push_back(aData
);
347 for (int i
= mxMainMenu
->n_children() - 1; i
>= 0; --i
)
349 OString sIdent
= mxMainMenu
->get_id(i
);
350 if (sIdent
.startsWith("select"))
351 mxMainMenu
->remove(sIdent
);
353 for (int i
= mxSubMenu
->n_children() - 1; i
>= 0; --i
)
355 OString sIdent
= mxSubMenu
->get_id(i
);
356 if (sIdent
.indexOf("customize") != -1)
357 mxSubMenu
->remove(sIdent
);
360 maPopupMenuProvider(*mxMainMenu
, *mxSubMenu
, aMenuData
);
363 void TabBar::EnableMenuButton(const bool bEnable
)
365 mxMenuButton
->set_sensitive(bEnable
);
368 } // end of namespace sfx2::sidebar
370 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */