LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / sidebar / FocusManager.cxx
blob42a75af4fa4e182d53181b6aa7300cc4e5a0000d
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/FocusManager.hxx>
21 #include <sfx2/sidebar/Deck.hxx>
22 #include <sfx2/sidebar/Panel.hxx>
23 #include <sidebar/DeckTitleBar.hxx>
24 #include <sidebar/PanelTitleBar.hxx>
25 #include <sidebar/TitleBar.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/weld.hxx>
29 namespace sfx2::sidebar {
31 FocusManager::FocusLocation::FocusLocation (const PanelComponent eComponent, const sal_Int32 nIndex)
32 : meComponent(eComponent),
33 mnIndex(nIndex)
37 FocusManager::FocusManager(const std::function<void(const Panel&)>& rShowPanelFunctor)
38 : mpDeckTitleBar(nullptr),
39 maShowPanelFunctor(rShowPanelFunctor)
43 FocusManager::~FocusManager()
45 Clear();
48 void FocusManager::GrabFocus()
50 FocusDeckTitle();
53 void FocusManager::GrabFocusPanel()
55 FocusPanel(0, false);
58 void FocusManager::Clear()
60 SetDeck(nullptr);
61 ClearPanels();
62 ClearButtons();
65 void FocusManager::ClearPanels()
67 SharedPanelContainer aPanels;
68 aPanels.swap(maPanels);
69 for (auto const& panel : aPanels)
71 if (panel->GetTitleBar())
73 UnregisterWindow(panel->GetTitleBar()->GetToolBox());
74 UnregisterWindow(panel->GetTitleBar()->GetExpander());
77 weld::Container* pContents = panel->GetContents();
78 UnregisterWindow(*pContents);
82 void FocusManager::ClearButtons()
84 std::vector<weld::Widget*> aButtons;
85 aButtons.swap(maButtons);
86 for (auto const& button : aButtons)
88 UnregisterWindow(*button);
92 void FocusManager::SetDeck(Deck* pDeck)
94 DeckTitleBar* pDeckTitleBar = pDeck ? pDeck->GetTitleBar() : nullptr;
95 if (mpDeckTitleBar != nullptr)
96 UnregisterWindow(mpDeckTitleBar->GetToolBox());
97 mxDeck = pDeck;
98 mpDeckTitleBar = pDeckTitleBar;
99 if (mpDeckTitleBar != nullptr)
100 RegisterWindow(mpDeckTitleBar->GetToolBox());
103 void FocusManager::SetPanels (const SharedPanelContainer& rPanels)
105 ClearPanels();
106 for (auto const& panel : rPanels)
108 if (panel->GetTitleBar())
110 RegisterWindow(panel->GetTitleBar()->GetToolBox());
111 RegisterWindow(panel->GetTitleBar()->GetExpander());
114 // Register also as key event listener at the panel.
115 weld::Container* pContents = panel->GetContents();
116 RegisterWindow(*pContents);
118 maPanels.emplace_back(panel);
122 void FocusManager::SetButtons(const std::vector<weld::Widget*>& rButtons)
124 ClearButtons();
125 for (auto const& button : rButtons)
127 RegisterWindow(*button);
128 maButtons.emplace_back(button);
132 void FocusManager::RegisterWindow(weld::Widget& rWidget)
134 UnregisterWindow(rWidget); // explicitly unset key press handler so we can reconnect without warnings
135 rWidget.connect_key_press(LINK(this, FocusManager, KeyInputHdl));
138 void FocusManager::UnregisterWindow(weld::Widget& rWidget)
140 rWidget.connect_key_press(Link<const KeyEvent&, bool>());
143 FocusManager::FocusLocation FocusManager::GetFocusLocation() const
145 // Check the deck title.
146 if (mpDeckTitleBar && mpDeckTitleBar->GetToolBox().has_focus())
147 return FocusLocation(PC_DeckToolBox, -1);
149 // Search the panels.
150 for (size_t nIndex = 0; nIndex < maPanels.size(); ++nIndex)
152 PanelTitleBar* pTitleBar = maPanels[nIndex]->GetTitleBar();
153 if (!pTitleBar)
154 continue;
155 if (pTitleBar->GetExpander().has_focus())
156 return FocusLocation(PC_PanelTitle, nIndex);
157 if (pTitleBar->GetToolBox().has_focus())
158 return FocusLocation(PC_PanelToolBox, nIndex);
159 weld::Container* pContents = maPanels[nIndex]->GetContents();
160 if (pContents->has_child_focus())
161 return FocusLocation(PC_PanelContent, nIndex);
164 // Search the buttons.
165 for (size_t nIndex=0; nIndex < maButtons.size(); ++nIndex)
167 if (maButtons[nIndex]->has_focus())
168 return FocusLocation(PC_TabBar, nIndex);
170 return FocusLocation(PC_None, -1);
173 void FocusManager::FocusDeckTitle()
175 if (mpDeckTitleBar != nullptr)
177 if (mpDeckTitleBar->GetToolBox().get_n_items() > 0)
179 weld::Toolbar& rToolBox = mpDeckTitleBar->GetToolBox();
180 rToolBox.grab_focus();
182 else
183 FocusPanel(0, false);
185 else
186 FocusPanel(0, false);
189 bool FocusManager::IsDeckTitleVisible() const
191 return mpDeckTitleBar != nullptr && mpDeckTitleBar->GetVisible();
194 bool FocusManager::IsPanelTitleVisible (const sal_Int32 nPanelIndex) const
196 if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size()))
197 return false;
199 TitleBar* pTitleBar = maPanels[nPanelIndex]->GetTitleBar();
200 if (!pTitleBar)
201 return false;
202 return pTitleBar->GetVisible();
205 void FocusManager::FocusPanel (
206 const sal_Int32 nPanelIndex,
207 const bool bFallbackToDeckTitle)
209 if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size()))
211 if (bFallbackToDeckTitle)
212 FocusDeckTitle();
213 return;
216 Panel& rPanel (*maPanels[nPanelIndex]);
217 PanelTitleBar* pTitleBar = rPanel.GetTitleBar();
218 if (pTitleBar && pTitleBar->GetVisible())
220 rPanel.SetExpanded(true);
221 pTitleBar->GetExpander().grab_focus();
223 else if (bFallbackToDeckTitle)
225 // The panel title is not visible, fall back to the deck
226 // title.
227 // Make sure that the desk title is visible here to prevent a
228 // loop when both the title of panel 0 and the deck title are
229 // not present.
230 if (IsDeckTitleVisible())
231 FocusDeckTitle();
232 else
233 FocusPanelContent(nPanelIndex);
235 else
236 FocusPanelContent(nPanelIndex);
238 if (maShowPanelFunctor)
239 maShowPanelFunctor(rPanel);
242 void FocusManager::FocusPanelContent(const sal_Int32 nPanelIndex)
244 if (!maPanels[nPanelIndex]->IsExpanded())
245 maPanels[nPanelIndex]->SetExpanded(true);
247 weld::Container* pContents = maPanels[nPanelIndex]->GetContents();
248 pContents->child_grab_focus();
251 void FocusManager::FocusButton (const sal_Int32 nButtonIndex)
253 maButtons[nButtonIndex]->grab_focus();
256 void FocusManager::MoveFocusInsidePanel (
257 const FocusLocation& rFocusLocation,
258 const sal_Int32 nDirection)
260 const bool bHasToolBoxItem (
261 maPanels[rFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().get_n_items() > 0);
262 switch (rFocusLocation.meComponent)
264 case PC_PanelTitle:
265 if (nDirection > 0 && bHasToolBoxItem)
266 maPanels[rFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().grab_focus();
267 else
268 FocusPanelContent(rFocusLocation.mnIndex);
269 break;
271 case PC_PanelToolBox:
272 if (nDirection < 0 && bHasToolBoxItem)
273 maPanels[rFocusLocation.mnIndex]->GetTitleBar()->GetExpander().grab_focus();
274 else
275 FocusPanelContent(rFocusLocation.mnIndex);
276 break;
278 default: break;
282 bool FocusManager::MoveFocusInsideDeckTitle (
283 const FocusLocation& rFocusLocation,
284 const sal_Int32 nDirection)
286 bool bConsumed = false;
287 // Note that when the title bar of the first (and only) panel is
288 // not visible then the deck title takes its place and the focus
289 // is moved between a) deck closer and b) content of panel 0.
290 switch (rFocusLocation.meComponent)
292 case PC_DeckToolBox:
293 if (nDirection>0 && ! IsPanelTitleVisible(0))
295 FocusPanelContent(0);
296 bConsumed = true;
298 break;
300 default: break;
302 return bConsumed;
305 bool FocusManager::HandleKeyEvent(
306 const vcl::KeyCode& rKeyCode,
307 const FocusLocation& aLocation)
309 bool bConsumed = false;
311 switch (rKeyCode.GetCode())
313 case KEY_ESCAPE:
314 switch (aLocation.meComponent)
316 case PC_TabBar:
317 case PC_DeckToolBox:
318 case PC_PanelTitle:
319 case PC_PanelToolBox:
321 if (mxDeck)
323 mxDeck->GrabFocusToDocument();
324 bConsumed = true;
326 break;
328 case PC_PanelContent:
329 // Return focus to tab bar sidebar settings button or panel title.
330 if (!IsDeckTitleVisible() && maPanels.size() == 1)
331 FocusButton(0);
332 else
333 FocusPanel(aLocation.mnIndex, true);
334 bConsumed = true;
335 break;
336 default:
337 break;
339 return bConsumed;
341 case KEY_RETURN:
342 switch (aLocation.meComponent)
344 case PC_DeckToolBox:
345 FocusButton(0);
346 bConsumed = true;
347 break;
349 case PC_PanelTitle:
350 // Enter the panel.
351 FocusPanelContent(aLocation.mnIndex);
352 bConsumed = true;
353 break;
355 default:
356 break;
358 return bConsumed;
360 case KEY_TAB:
362 const sal_Int32 nDirection (
363 rKeyCode.IsShift()
364 ? -1
365 : +1);
366 switch (aLocation.meComponent)
368 case PC_PanelTitle:
369 case PC_PanelToolBox:
370 MoveFocusInsidePanel(aLocation, nDirection);
371 bConsumed = true;
372 break;
374 case PC_DeckToolBox:
375 bConsumed = MoveFocusInsideDeckTitle(aLocation, nDirection);
376 break;
378 case PC_TabBar:
379 if (rKeyCode.IsShift())
380 FocusPanel(maPanels.size()-1, true);
381 else
383 if (IsDeckTitleVisible())
384 FocusDeckTitle();
385 else
386 FocusPanel(0, true);
388 bConsumed = true;
389 break;
391 default:
392 break;
394 break;
397 case KEY_LEFT:
398 case KEY_UP:
399 switch (aLocation.meComponent)
401 case PC_PanelTitle:
402 case PC_PanelToolBox:
403 // Go to previous panel or the deck title.
404 if (aLocation.mnIndex > 0)
405 FocusPanel(aLocation.mnIndex-1, true);
406 else if (IsDeckTitleVisible())
407 FocusDeckTitle();
408 else
410 // Focus the last button.
411 sal_Int32 nIndex(maButtons.size()-1);
412 while(!maButtons[nIndex]->get_visible() && --nIndex > 0);
413 FocusButton(nIndex);
415 bConsumed = true;
416 break;
418 case PC_DeckToolBox:
420 // Focus the last button.
421 sal_Int32 nIndex(maButtons.size()-1);
422 while(!maButtons[nIndex]->get_visible() && --nIndex > 0);
423 FocusButton(nIndex);
424 bConsumed = true;
425 break;
428 case PC_TabBar:
429 // Go to previous tab bar item.
430 if (aLocation.mnIndex == 0)
431 FocusPanel(maPanels.size()-1, true);
432 else
434 sal_Int32 nIndex((aLocation.mnIndex + maButtons.size() - 1) % maButtons.size());
435 while(!maButtons[nIndex]->get_visible() && --nIndex > 0);
436 FocusButton(nIndex);
438 bConsumed = true;
439 break;
441 default:
442 break;
444 break;
446 case KEY_RIGHT:
447 case KEY_DOWN:
448 switch(aLocation.meComponent)
450 case PC_PanelTitle:
451 case PC_PanelToolBox:
452 // Go to next panel.
453 if (aLocation.mnIndex < static_cast<sal_Int32>(maPanels.size())-1)
454 FocusPanel(aLocation.mnIndex+1, false);
455 else
456 FocusButton(0);
457 bConsumed = true;
458 break;
460 case PC_DeckToolBox:
461 // Focus the first panel.
462 if (IsPanelTitleVisible(0))
463 FocusPanel(0, false);
464 else
465 FocusButton(0);
466 bConsumed = true;
467 break;
469 case PC_TabBar:
470 // Go to next tab bar item.
471 if (aLocation.mnIndex < static_cast<sal_Int32>(maButtons.size())-1)
473 sal_Int32 nIndex(aLocation.mnIndex + 1);
474 while(!maButtons[nIndex]->get_visible() && ++nIndex < static_cast<sal_Int32>(maButtons.size()));
475 if (nIndex < static_cast<sal_Int32>(maButtons.size()))
477 FocusButton(nIndex);
478 bConsumed = true;
479 break;
482 if (IsDeckTitleVisible())
483 FocusDeckTitle();
484 else
485 FocusPanel(0, true);
486 bConsumed = true;
487 break;
489 default:
490 break;
492 break;
494 return bConsumed;
497 IMPL_LINK(FocusManager, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
499 return HandleKeyEvent(rKeyEvent.GetKeyCode(), GetFocusLocation());
502 } // end of namespace sfx2::sidebar
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */