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 "FocusManager.hxx"
22 #include "DeckTitleBar.hxx"
23 #include "PanelTitleBar.hxx"
24 #include <sfx2/sidebar/Tools.hxx>
25 #include "TitleBar.hxx"
26 #include <vcl/button.hxx>
27 #include <vcl/toolbox.hxx>
28 #include <toolkit/helper/vclunohelper.hxx>
30 namespace sfx2
{ namespace sidebar
{
32 FocusManager::FocusLocation::FocusLocation (const PanelComponent eComponent
, const sal_Int32 nIndex
)
33 : meComponent(eComponent
),
38 FocusManager::FocusManager(const std::function
<void(const Panel
&)>& rShowPanelFunctor
)
42 maShowPanelFunctor(rShowPanelFunctor
),
43 mbObservingContentControlFocus(false),
44 mpFirstFocusedContentControl(NULL
),
45 mpLastFocusedWindow(NULL
)
49 FocusManager::~FocusManager()
54 void FocusManager::GrabFocus()
59 void FocusManager::Clear()
66 void FocusManager::ClearPanels()
68 std::vector
<VclPtr
<Panel
> > aPanels
;
69 aPanels
.swap(maPanels
);
70 for (auto iPanel(aPanels
.begin()),iEnd(aPanels
.end()); iPanel
!= iEnd
; ++iPanel
)
72 UnregisterWindow(**iPanel
);
73 if ((*iPanel
)->GetTitleBar() != NULL
)
75 UnregisterWindow(*(*iPanel
)->GetTitleBar());
76 UnregisterWindow((*iPanel
)->GetTitleBar()->GetToolBox());
79 (*iPanel
)->RemoveChildEventListener(LINK(this, FocusManager
, ChildEventListener
));
83 void FocusManager::ClearButtons()
85 std::vector
<VclPtr
<Button
> > aButtons
;
86 aButtons
.swap(maButtons
);
87 for (auto iButton
= aButtons
.begin(); iButton
!= aButtons
.end(); ++iButton
)
89 UnregisterWindow(**iButton
);
93 void FocusManager::SetDeckTitle (DeckTitleBar
* pDeckTitleBar
)
95 if (mpDeckTitleBar
!= nullptr)
97 UnregisterWindow(*mpDeckTitleBar
);
98 UnregisterWindow(mpDeckTitleBar
->GetToolBox());
100 mpDeckTitleBar
= pDeckTitleBar
;
102 if (mpDeckTitleBar
!= nullptr)
104 RegisterWindow(*mpDeckTitleBar
);
105 RegisterWindow(mpDeckTitleBar
->GetToolBox());
109 void FocusManager::SetPanels (const SharedPanelContainer
& rPanels
)
112 for (auto iPanel
= rPanels
.begin(); iPanel
!= rPanels
.end(); ++iPanel
)
114 RegisterWindow(**iPanel
);
115 if ((*iPanel
)->GetTitleBar() != NULL
)
117 RegisterWindow(*(*iPanel
)->GetTitleBar());
118 RegisterWindow((*iPanel
)->GetTitleBar()->GetToolBox());
121 // Register also as child event listener at the panel.
122 (*iPanel
)->AddChildEventListener(LINK(this, FocusManager
, ChildEventListener
));
124 maPanels
.push_back(iPanel
->get());
128 void FocusManager::SetButtons (const ::std::vector
<Button
*>& rButtons
)
131 for (auto iButton
= rButtons
.begin(); iButton
!= rButtons
.end(); ++iButton
)
133 RegisterWindow(**iButton
);
134 maButtons
.push_back(*iButton
);
138 void FocusManager::RegisterWindow (vcl::Window
& rWindow
)
140 rWindow
.AddEventListener(LINK(this, FocusManager
, WindowEventListener
));
143 void FocusManager::UnregisterWindow (vcl::Window
& rWindow
)
145 rWindow
.RemoveEventListener(LINK(this, FocusManager
, WindowEventListener
));
148 FocusManager::FocusLocation
FocusManager::GetFocusLocation (const vcl::Window
& rWindow
) const
150 // Check the deck title.
151 if (mpDeckTitleBar
!= nullptr)
153 if (mpDeckTitleBar
== &rWindow
)
154 return FocusLocation(PC_DeckTitle
, -1);
155 else if (&mpDeckTitleBar
->GetToolBox() == &rWindow
)
156 return FocusLocation(PC_DeckToolBox
, -1);
159 // Search the panels.
160 for (size_t nIndex
= 0; nIndex
< maPanels
.size(); ++nIndex
)
162 if (maPanels
[nIndex
] == &rWindow
)
163 return FocusLocation(PC_PanelContent
, nIndex
);
164 TitleBar
* pTitleBar
= maPanels
[nIndex
]->GetTitleBar();
165 if (pTitleBar
== &rWindow
)
166 return FocusLocation(PC_PanelTitle
, nIndex
);
167 if (pTitleBar
!=NULL
&& &pTitleBar
->GetToolBox()==&rWindow
)
168 return FocusLocation(PC_PanelToolBox
, nIndex
);
171 // Search the buttons.
172 for (size_t nIndex
=0; nIndex
< maButtons
.size(); ++nIndex
)
174 if (maButtons
[nIndex
] == &rWindow
)
175 return FocusLocation(PC_TabBar
, nIndex
);
177 return FocusLocation(PC_None
, -1);
180 void FocusManager::FocusDeckTitle()
182 if (mpDeckTitleBar
!= nullptr)
184 if (IsDeckTitleVisible())
186 mpDeckTitleBar
->GrabFocus();
188 else if (mpDeckTitleBar
->GetToolBox().GetItemCount() > 0)
190 ToolBox
& rToolBox
= mpDeckTitleBar
->GetToolBox();
191 rToolBox
.GrabFocus();
192 rToolBox
.Invalidate();
195 FocusPanel(0, false);
198 FocusPanel(0, false);
201 bool FocusManager::IsDeckTitleVisible() const
203 return mpDeckTitleBar
!= nullptr && mpDeckTitleBar
->IsVisible();
206 bool FocusManager::IsPanelTitleVisible (const sal_Int32 nPanelIndex
) const
208 if (nPanelIndex
<0 || nPanelIndex
>=static_cast<sal_Int32
>(maPanels
.size()))
211 TitleBar
* pTitleBar
= maPanels
[nPanelIndex
]->GetTitleBar();
214 return pTitleBar
->IsVisible();
217 void FocusManager::FocusPanel (
218 const sal_Int32 nPanelIndex
,
219 const bool bFallbackToDeckTitle
)
221 if (nPanelIndex
<0 || nPanelIndex
>=static_cast<sal_Int32
>(maPanels
.size()))
223 if (bFallbackToDeckTitle
)
228 Panel
& rPanel (*maPanels
[nPanelIndex
]);
229 TitleBar
* pTitleBar
= rPanel
.GetTitleBar();
230 if (pTitleBar
!=NULL
&& pTitleBar
->IsVisible())
232 rPanel
.SetExpanded(true);
233 pTitleBar
->GrabFocus();
235 else if (bFallbackToDeckTitle
)
237 // The panel title is not visible, fall back to the deck
239 // Make sure that the desk title is visible here to prevent a
240 // loop when both the title of panel 0 and the deck title are
242 if (IsDeckTitleVisible())
245 FocusPanelContent(nPanelIndex
);
248 FocusPanelContent(nPanelIndex
);
250 if (maShowPanelFunctor
)
251 maShowPanelFunctor(rPanel
);
254 void FocusManager::FocusPanelContent (const sal_Int32 nPanelIndex
)
256 vcl::Window
* pWindow
= VCLUnoHelper::GetWindow(maPanels
[nPanelIndex
]->GetElementWindow());
259 mbObservingContentControlFocus
= true;
260 pWindow
->GrabFocus();
261 mbObservingContentControlFocus
= false;
265 void FocusManager::FocusButton (const sal_Int32 nButtonIndex
)
267 maButtons
[nButtonIndex
]->GrabFocus();
268 maButtons
[nButtonIndex
]->Invalidate();
271 void FocusManager::ClickButton (const sal_Int32 nButtonIndex
)
273 maButtons
[nButtonIndex
]->Click();
274 if (nButtonIndex
> 0)
275 if ( ! maPanels
.empty())
277 maButtons
[nButtonIndex
]->GetParent()->Invalidate();
280 void FocusManager::RemoveWindow (vcl::Window
& rWindow
)
282 auto iPanel (::std::find(maPanels
.begin(), maPanels
.end(), &rWindow
));
283 if (iPanel
!= maPanels
.end())
285 UnregisterWindow(rWindow
);
286 if ((*iPanel
)->GetTitleBar() != NULL
)
288 UnregisterWindow(*(*iPanel
)->GetTitleBar());
289 UnregisterWindow((*iPanel
)->GetTitleBar()->GetToolBox());
291 maPanels
.erase(iPanel
);
295 auto iButton (::std::find(maButtons
.begin(), maButtons
.end(), &rWindow
));
296 if (iButton
!= maButtons
.end())
298 UnregisterWindow(rWindow
);
299 maButtons
.erase(iButton
);
304 bool FocusManager::MoveFocusInsidePanel (
305 const FocusLocation
& rFocusLocation
,
306 const sal_Int32 nDirection
)
308 const bool bHasToolBoxItem (
309 maPanels
[rFocusLocation
.mnIndex
]->GetTitleBar()->GetToolBox().GetItemCount() > 0);
310 switch (rFocusLocation
.meComponent
)
313 if (nDirection
> 0 && bHasToolBoxItem
)
314 maPanels
[rFocusLocation
.mnIndex
]->GetTitleBar()->GetToolBox().GrabFocus();
316 FocusPanelContent(rFocusLocation
.mnIndex
);
319 case PC_PanelToolBox
:
320 if (nDirection
< 0 && bHasToolBoxItem
)
321 maPanels
[rFocusLocation
.mnIndex
]->GetTitleBar()->GrabFocus();
323 FocusPanelContent(rFocusLocation
.mnIndex
);
331 bool FocusManager::MoveFocusInsideDeckTitle (
332 const FocusLocation
& rFocusLocation
,
333 const sal_Int32 nDirection
)
335 // Note that when the title bar of the first (and only) panel is
336 // not visible then the deck title takes its place and the focus
337 // is moved between a) deck title, b) deck closer and c) content
339 const bool bHasToolBoxItem (
340 mpDeckTitleBar
->GetToolBox().GetItemCount() > 0);
341 switch (rFocusLocation
.meComponent
)
344 if (nDirection
<0 && ! IsPanelTitleVisible(0))
345 FocusPanelContent(0);
346 else if (bHasToolBoxItem
)
347 mpDeckTitleBar
->GetToolBox().GrabFocus();
351 if (nDirection
>0 && ! IsPanelTitleVisible(0))
352 FocusPanelContent(0);
354 mpDeckTitleBar
->GrabFocus();
362 void FocusManager::HandleKeyEvent (
363 const vcl::KeyCode
& rKeyCode
,
364 const vcl::Window
& rWindow
)
366 const FocusLocation
aLocation (GetFocusLocation(rWindow
));
367 mpLastFocusedWindow
= NULL
;
369 switch (rKeyCode
.GetCode())
372 switch (aLocation
.meComponent
)
375 // Toggle panel between expanded and collapsed.
376 maPanels
[aLocation
.mnIndex
]->SetExpanded( ! maPanels
[aLocation
.mnIndex
]->IsExpanded());
380 // Activate the button.
381 ClickButton(aLocation
.mnIndex
);
390 switch (aLocation
.meComponent
)
398 FocusPanelContent(aLocation
.mnIndex
);
402 // Activate the button.
403 ClickButton(aLocation
.mnIndex
);
413 const sal_Int32
nDirection (
417 switch (aLocation
.meComponent
)
420 case PC_PanelToolBox
:
421 case PC_PanelContent
:
422 MoveFocusInsidePanel(aLocation
, nDirection
);
427 MoveFocusInsideDeckTitle(aLocation
, nDirection
);
438 switch (aLocation
.meComponent
)
441 case PC_PanelToolBox
:
442 case PC_PanelContent
:
443 // Go to previous panel or the deck title.
444 if (aLocation
.mnIndex
> 0)
445 FocusPanel(aLocation
.mnIndex
-1, true);
446 else if (IsDeckTitleVisible())
449 FocusButton(maButtons
.size()-1);
454 // Focus the last button.
455 FocusButton(maButtons
.size()-1);
459 // Go to previous tab bar item.
460 if (aLocation
.mnIndex
== 0)
461 FocusPanel(maPanels
.size()-1, true);
463 FocusButton((aLocation
.mnIndex
+ maButtons
.size() - 1) % maButtons
.size());
473 switch(aLocation
.meComponent
)
476 case PC_PanelToolBox
:
477 case PC_PanelContent
:
479 if (aLocation
.mnIndex
< static_cast<sal_Int32
>(maPanels
.size())-1)
480 FocusPanel(aLocation
.mnIndex
+1, false);
487 // Focus the first panel.
488 if (IsPanelTitleVisible(0))
489 FocusPanel(0, false);
495 // Go to next tab bar item.
496 if (aLocation
.mnIndex
< static_cast<sal_Int32
>(maButtons
.size())-1)
497 FocusButton(aLocation
.mnIndex
+ 1);
498 else if (IsDeckTitleVisible())
511 IMPL_LINK(FocusManager
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
516 if ( ! pEvent
->ISA(VclWindowEvent
))
519 VclWindowEvent
* pWindowEvent
= static_cast<VclWindowEvent
*>(pEvent
);
520 vcl::Window
* pSource
= pWindowEvent
->GetWindow();
524 switch (pWindowEvent
->GetId())
526 case VCLEVENT_WINDOW_KEYINPUT
:
528 KeyEvent
* pKeyEvent
= static_cast<KeyEvent
*>(pWindowEvent
->GetData());
529 HandleKeyEvent(pKeyEvent
->GetKeyCode(), *pSource
);
533 case VCLEVENT_OBJECT_DYING
:
534 RemoveWindow(*pSource
);
537 case VCLEVENT_WINDOW_GETFOCUS
:
538 case VCLEVENT_WINDOW_LOSEFOCUS
:
539 pSource
->Invalidate();
549 IMPL_LINK(FocusManager
, ChildEventListener
, VclSimpleEvent
*, pEvent
)
554 if (!pEvent
->ISA(VclWindowEvent
))
557 VclWindowEvent
* pWindowEvent
= static_cast<VclWindowEvent
*>(pEvent
);
558 vcl::Window
* pSource
= pWindowEvent
->GetWindow();
562 switch (pWindowEvent
->GetId())
564 case VCLEVENT_WINDOW_KEYINPUT
:
566 KeyEvent
* pKeyEvent
= static_cast<KeyEvent
*>(pWindowEvent
->GetData());
568 // Go up the window hierarchy to find out whether the
569 // parent of the event source is known to us.
570 vcl::Window
* pWindow
= pSource
;
571 FocusLocation
aLocation (PC_None
, -1);
576 aLocation
= GetFocusLocation(*pWindow
);
577 if (aLocation
.meComponent
!= PC_None
)
579 pWindow
= pWindow
->GetParent();
582 if (aLocation
.meComponent
!= PC_None
)
584 switch (pKeyEvent
->GetKeyCode().GetCode())
587 // Return focus back to the panel title.
588 FocusPanel(aLocation
.mnIndex
, true);
592 if (mpFirstFocusedContentControl
!=nullptr
593 && mpLastFocusedWindow
== mpFirstFocusedContentControl
)
595 // Move focus back to panel (or deck)
597 FocusPanel(aLocation
.mnIndex
, true);
608 case VCLEVENT_WINDOW_GETFOCUS
:
609 // Keep track of focused controls in panel content.
610 // Remember the first focused control. When it is later
611 // focused again due to pressing the TAB key then the
612 // focus is moved to the panel or deck title.
613 mpLastFocusedWindow
= pSource
;
614 if (mbObservingContentControlFocus
)
615 mpFirstFocusedContentControl
= pSource
;
625 } } // end of namespace sfx2::sidebar
627 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */