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>
26 #include <sfx2/strings.hrc>
28 #include <sfx2/sfxresid.hxx>
30 #include <comphelper/processfactory.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <vcl/commandevent.hxx>
33 #include <vcl/event.hxx>
34 #include <vcl/svapp.hxx>
35 #include <tools/svborder.hxx>
36 #include <svtools/acceleratorexecute.hxx>
39 using namespace css::uno
;
41 static int gDefaultWidth
;
43 namespace sfx2::sidebar
{
45 TabBar::TabBar(vcl::Window
* pParentWindow
,
46 const Reference
<frame::XFrame
>& rxFrame
,
47 const std::function
<void (const OUString
&)>& rDeckActivationFunctor
,
48 const PopupMenuProvider
& rPopupMenuProvider
,
49 SidebarController
* rParentSidebarController
51 : InterimItemWindow(pParentWindow
, "sfx/ui/tabbar.ui", "TabBar")
53 , mxAuxBuilder(Application::CreateBuilder(m_xContainer
.get(), "sfx/ui/tabbarcontents.ui"))
54 , mxTempToplevel(mxAuxBuilder
->weld_container("toplevel"))
55 , mxContents(mxAuxBuilder
->weld_widget("TabBarContents"))
56 , mxMenuButton(mxAuxBuilder
->weld_menu_button("menubutton"))
57 , mxMainMenu(mxAuxBuilder
->weld_menu("mainmenu"))
58 , mxSubMenu(mxAuxBuilder
->weld_menu("submenu"))
59 , mxMeasureBox(mxAuxBuilder
->weld_widget("measure"))
61 , maDeckActivationFunctor(rDeckActivationFunctor
)
62 , maPopupMenuProvider(rPopupMenuProvider
)
63 , pParentSidebarController(rParentSidebarController
)
65 mxTempToplevel
->move(mxContents
.get(), m_xContainer
.get());
67 gDefaultWidth
= m_xContainer
->get_preferred_size().Width();
69 // we have this widget just so we can measure best width for static TabBar::GetDefaultWidth
72 SetBackground(Wallpaper(Theme::GetColor(Theme::Color_TabBarBackground
)));
74 mxMenuButton
->connect_toggled(LINK(this, TabBar
, OnToolboxClicked
));
77 SetText(OUString("TabBar"));
86 void TabBar::dispose()
88 m_xContainer
->move(mxContents
.get(), mxTempToplevel
.get());
95 InterimItemWindow::dispose();
98 sal_Int32
TabBar::GetDefaultWidth()
102 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(nullptr, "sfx/ui/tabbarcontents.ui"));
103 std::unique_ptr
<weld::Widget
> xContainer(xBuilder
->weld_widget("TabBarContents"));
104 gDefaultWidth
= xContainer
->get_preferred_size().Width();
106 return gDefaultWidth
;
109 void TabBar::SetDecks(const ResourceManager::DeckContextDescriptorContainer
& rDecks
)
111 // Remove the current buttons.
113 for (auto const& deck
: rDecks
)
115 std::shared_ptr
<DeckDescriptor
> xDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(deck
.msId
);
116 if (xDescriptor
== nullptr)
118 OSL_ASSERT(xDescriptor
!=nullptr);
122 maItems
.emplace_back(std::make_unique
<Item
>(*this));
123 auto& xItem(maItems
.back());
124 xItem
->msDeckId
= xDescriptor
->msId
;
125 CreateTabItem(*xItem
->mxButton
, *xDescriptor
);
126 xItem
->mxButton
->connect_clicked(LINK(xItem
.get(), TabBar::Item
, HandleClick
));
127 xItem
->maDeckActivationFunctor
= maDeckActivationFunctor
;
128 xItem
->mbIsHidden
= !xDescriptor
->mbIsEnabled
;
129 xItem
->mbIsHiddenByDefault
= xItem
->mbIsHidden
; // the default is the state while creating
131 xItem
->mxButton
->set_sensitive(deck
.mbIsEnabled
);
137 void TabBar::UpdateButtonIcons()
139 for (auto const& item
: maItems
)
141 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(item
->msDeckId
);
142 if (!xDeckDescriptor
)
144 item
->mxButton
->set_item_image("toggle", GetItemImage(*xDeckDescriptor
));
148 void TabBar::HighlightDeck(const OUString
& rsDeckId
)
150 for (auto const& item
: maItems
)
151 item
->mxButton
->set_item_active("toggle", item
->msDeckId
== rsDeckId
);
154 void TabBar::RemoveDeckHighlight()
156 for (auto const& item
: maItems
)
157 item
->mxButton
->set_item_active("toggle", false);
160 void TabBar::DataChanged(const DataChangedEvent
& rDataChangedEvent
)
162 SetBackground(Theme::GetColor(Theme::Color_TabBarBackground
));
165 InterimItemWindow::DataChanged(rDataChangedEvent
);
168 bool TabBar::EventNotify(NotifyEvent
& rEvent
)
170 MouseNotifyEvent nType
= rEvent
.GetType();
171 if(MouseNotifyEvent::KEYINPUT
== nType
)
173 const vcl::KeyCode
& rKeyCode
= rEvent
.GetKeyEvent()->GetKeyCode();
176 mpAccel
= svt::AcceleratorExecute::createAcceleratorHelper();
177 mpAccel
->init(comphelper::getProcessComponentContext(), mxFrame
);
179 const OUString
aCommand(mpAccel
->findCommand(svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyCode
)));
180 if (".uno:Sidebar" == aCommand
||
181 (rKeyCode
.IsMod1() && rKeyCode
.IsShift() && rKeyCode
.GetCode() == KEY_F10
))
182 return InterimItemWindow::EventNotify(rEvent
);
185 else if(MouseNotifyEvent::COMMAND
== nType
)
187 const CommandEvent
& rCommandEvent
= *rEvent
.GetCommandEvent();
188 if(rCommandEvent
.GetCommand() == CommandEventId::Wheel
)
190 const CommandWheelData
* pData
= rCommandEvent
.GetWheelData();
191 if(!pData
->GetModifier() && (pData
->GetMode() == CommandWheelMode::SCROLL
))
193 auto pItem
= std::find_if(maItems
.begin(), maItems
.end(),
194 [] (const auto& item
) { return item
->mxButton
->get_item_active("toggle"); });
195 if(pItem
== maItems
.end())
197 if(pData
->GetNotchDelta()<0)
199 if(pItem
+1 == maItems
.end())
205 if(pItem
== maItems
.begin())
211 (*pItem
)->maDeckActivationFunctor((*pItem
)->msDeckId
);
213 catch(const css::uno::Exception
&) {};
221 void TabBar::CreateTabItem(weld::Toolbar
& rItem
, const DeckDescriptor
& rDeckDescriptor
)
223 rItem
.set_accessible_name(rDeckDescriptor
.msTitle
);
224 rItem
.set_accessible_description(rDeckDescriptor
.msHelpText
);
225 rItem
.set_tooltip_text(rDeckDescriptor
.msHelpText
);
226 rItem
.set_item_tooltip_text("toggle", rDeckDescriptor
.msHelpText
);
229 css::uno::Reference
<css::graphic::XGraphic
> TabBar::GetItemImage(const DeckDescriptor
& rDeckDescriptor
) const
231 return Tools::GetImage(
232 rDeckDescriptor
.msIconURL
,
233 rDeckDescriptor
.msHighContrastIconURL
,
237 TabBar::Item::Item(TabBar
& rTabBar
)
239 , mxBuilder(Application::CreateBuilder(rTabBar
.GetContainer(), "sfx/ui/tabbutton.ui"))
240 , mxButton(mxBuilder
->weld_toolbar("button"))
242 , mbIsHiddenByDefault(false)
246 TabBar::Item::~Item()
248 mrTabBar
.GetContainer()->move(mxButton
.get(), nullptr);
251 IMPL_LINK_NOARG(TabBar::Item
, HandleClick
, const OString
&, void)
253 // tdf#143146 copy the functor and arg before calling
254 // GrabFocusToDocument which may destroy this object
255 auto aDeckActivationFunctor
= maDeckActivationFunctor
;
256 auto sDeckId
= msDeckId
;
258 mrTabBar
.GrabFocusToDocument();
261 aDeckActivationFunctor(sDeckId
);
263 catch(const css::uno::Exception
&)
264 {} // workaround for #i123198#
267 OUString
const & TabBar::GetDeckIdForIndex (const sal_Int32 nIndex
) const
269 if (nIndex
<0 || o3tl::make_unsigned(nIndex
)>=maItems
.size())
270 throw RuntimeException();
271 return maItems
[nIndex
]->msDeckId
;
274 void TabBar::ToggleHideFlag (const sal_Int32 nIndex
)
276 if (nIndex
<0 || o3tl::make_unsigned(nIndex
) >= maItems
.size())
277 throw RuntimeException();
279 maItems
[nIndex
]->mbIsHidden
= ! maItems
[nIndex
]->mbIsHidden
;
281 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(maItems
[nIndex
]->msDeckId
);
284 xDeckDescriptor
->mbIsEnabled
= ! maItems
[nIndex
]->mbIsHidden
;
287 aContext
.msApplication
= pParentSidebarController
->GetCurrentContext().msApplication
;
288 // leave aContext.msContext on default 'any' ... this func is used only for decks
289 // and we don't have context-sensitive decks anyway
291 xDeckDescriptor
->maContextList
.ToggleVisibilityForContext(
292 aContext
, xDeckDescriptor
->mbIsEnabled
);
296 void TabBar::RestoreHideFlags()
298 for (auto & item
: maItems
)
300 if (item
->mbIsHidden
!= item
->mbIsHiddenByDefault
)
302 item
->mbIsHidden
= item
->mbIsHiddenByDefault
;
303 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(item
->msDeckId
);
305 xDeckDescriptor
->mbIsEnabled
= !item
->mbIsHidden
;
311 void TabBar::UpdateFocusManager(FocusManager
& rFocusManager
)
313 std::vector
<weld::Widget
*> aButtons
;
314 aButtons
.reserve(maItems
.size()+1);
315 aButtons
.push_back(mxMenuButton
.get());
316 for (auto const& item
: maItems
)
318 aButtons
.push_back(item
->mxButton
.get());
320 rFocusManager
.SetButtons(aButtons
);
323 IMPL_LINK_NOARG(TabBar
, OnToolboxClicked
, weld::ToggleButton
&, void)
325 if (!mxMenuButton
->get_active())
328 std::vector
<DeckMenuData
> aMenuData
;
330 for (auto const& item
: maItems
)
332 std::shared_ptr
<DeckDescriptor
> xDeckDescriptor
= pParentSidebarController
->GetResourceManager()->GetDeckDescriptor(item
->msDeckId
);
334 if (!xDeckDescriptor
)
338 aData
.msDisplayName
= xDeckDescriptor
->msTitle
;
339 aData
.mbIsCurrentDeck
= item
->mxButton
->get_item_active("toggle");
340 aData
.mbIsActive
= !item
->mbIsHidden
;
341 aData
.mbIsEnabled
= item
->mxButton
->get_sensitive();
342 aMenuData
.push_back(aData
);
345 for (int i
= mxMainMenu
->n_children() - 1; i
>= 0; --i
)
347 OString sIdent
= mxMainMenu
->get_id(i
);
348 if (sIdent
.startsWith("select"))
349 mxMainMenu
->remove(sIdent
);
351 for (int i
= mxSubMenu
->n_children() - 1; i
>= 0; --i
)
353 OString sIdent
= mxSubMenu
->get_id(i
);
354 if (sIdent
.indexOf("customize") != -1)
355 mxSubMenu
->remove(sIdent
);
358 maPopupMenuProvider(*mxMainMenu
, *mxSubMenu
, aMenuData
);
361 void TabBar::EnableMenuButton(const bool bEnable
)
363 mxMenuButton
->set_sensitive(bEnable
);
366 } // end of namespace sfx2::sidebar
368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */