LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / sidebar / TabBar.cxx
blob878c87c673605bbfd7fd311529879c50f4e2848b
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>
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>
35 using namespace css;
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")
49 , mxFrame(rxFrame)
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
68 mxMeasureBox->hide();
70 SetBackground(Wallpaper(Theme::GetColor(Theme::Color_TabBarBackground)));
72 mxMenuButton->connect_toggled(LINK(this, TabBar, OnToolboxClicked));
74 #ifdef DEBUG
75 SetText(OUString("TabBar"));
76 #endif
79 TabBar::~TabBar()
81 disposeOnce();
84 void TabBar::dispose()
86 m_xContainer->move(mxContents.get(), mxTempToplevel.get());
87 maItems.clear();
88 mxMeasureBox.reset();
89 mxSubMenu.reset();
90 mxMainMenu.reset();
91 mxMenuButton.reset();
92 mxAuxBuilder.reset();
93 InterimItemWindow::dispose();
96 sal_Int32 TabBar::GetDefaultWidth()
98 if (!gDefaultWidth)
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())
111 return;
113 // Remove the current buttons.
114 maItems.clear();
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);
121 continue;
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);
136 UpdateButtonIcons();
139 void TabBar::UpdateButtonIcons()
141 for (auto const& item : maItems)
143 std::shared_ptr<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item->msDeckId);
144 if (!xDeckDescriptor)
145 continue;
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));
165 UpdateButtonIcons();
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();
176 if (!mpAccel)
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);
185 return true;
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())
198 return true;
199 if(pData->GetNotchDelta()<0)
201 if(pItem+1 == maItems.end())
202 return true;
203 ++pItem;
205 else
207 if(pItem == maItems.begin())
208 return true;
209 --pItem;
213 (*pItem)->maDeckActivationFunctor((*pItem)->msDeckId);
215 catch(const css::uno::Exception&) {};
216 return true;
220 return false;
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,
236 mxFrame);
239 TabBar::Item::Item(TabBar& rTabBar)
240 : mrTabBar(rTabBar)
241 , mxBuilder(Application::CreateBuilder(rTabBar.GetContainer(), "sfx/ui/tabbutton.ui"))
242 , mxButton(mxBuilder->weld_toolbar("button"))
243 , mbIsHidden(false)
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);
284 if (xDeckDescriptor)
286 xDeckDescriptor->mbIsEnabled = ! maItems[nIndex]->mbIsHidden;
288 Context aContext;
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);
306 if (xDeckDescriptor)
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())
328 return;
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)
337 continue;
339 DeckMenuData aData;
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: */