Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / sidebar / TabBar.cxx
blob881ec8f78fc2ffcbe6a5c0df0400103e217eb0ea
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
38 using namespace css;
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")
52 , mxFrame(rxFrame)
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"))
60 , maItems()
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
70 mxMeasureBox->hide();
72 SetBackground(Wallpaper(Theme::GetColor(Theme::Color_TabBarBackground)));
74 mxMenuButton->connect_toggled(LINK(this, TabBar, OnToolboxClicked));
76 #ifdef DEBUG
77 SetText(OUString("TabBar"));
78 #endif
81 TabBar::~TabBar()
83 disposeOnce();
86 void TabBar::dispose()
88 m_xContainer->move(mxContents.get(), mxTempToplevel.get());
89 maItems.clear();
90 mxMeasureBox.reset();
91 mxSubMenu.reset();
92 mxMainMenu.reset();
93 mxMenuButton.reset();
94 mxAuxBuilder.reset();
95 InterimItemWindow::dispose();
98 sal_Int32 TabBar::GetDefaultWidth()
100 if (!gDefaultWidth)
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.
112 maItems.clear();
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);
119 continue;
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);
134 UpdateButtonIcons();
137 void TabBar::UpdateButtonIcons()
139 for (auto const& item : maItems)
141 std::shared_ptr<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item->msDeckId);
142 if (!xDeckDescriptor)
143 continue;
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));
163 UpdateButtonIcons();
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();
174 if (!mpAccel)
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);
183 return true;
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())
196 return true;
197 if(pData->GetNotchDelta()<0)
199 if(pItem+1 == maItems.end())
200 return true;
201 ++pItem;
203 else
205 if(pItem == maItems.begin())
206 return true;
207 --pItem;
211 (*pItem)->maDeckActivationFunctor((*pItem)->msDeckId);
213 catch(const css::uno::Exception&) {};
214 return true;
218 return false;
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,
234 mxFrame);
237 TabBar::Item::Item(TabBar& rTabBar)
238 : mrTabBar(rTabBar)
239 , mxBuilder(Application::CreateBuilder(rTabBar.GetContainer(), "sfx/ui/tabbutton.ui"))
240 , mxButton(mxBuilder->weld_toolbar("button"))
241 , mbIsHidden(false)
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);
282 if (xDeckDescriptor)
284 xDeckDescriptor->mbIsEnabled = ! maItems[nIndex]->mbIsHidden;
286 Context aContext;
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);
304 if (xDeckDescriptor)
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())
326 return;
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)
335 continue;
337 DeckMenuData aData;
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: */