1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 #include "precompiled_sfx2.hxx"
23
24 #include "FocusManager.hxx"
25 #include "Panel.hxx"
26 #include "DeckTitleBar.hxx"
27 #include "PanelTitleBar.hxx"
28 #include "sfx2/sidebar/Tools.hxx"
29 #include "TitleBar.hxx"
30 #include <vcl/button.hxx>
31 #include <vcl/toolbox.hxx>
32 #include <toolkit/helper/vclunohelper.hxx>
33
34
35 namespace sfx2 { namespace sidebar {
36
FocusLocation(const PanelComponent eComponent,const sal_Int32 nIndex)37 FocusManager::FocusLocation::FocusLocation (const PanelComponent eComponent, const sal_Int32 nIndex)
38 : meComponent(eComponent),
39 mnIndex(nIndex)
40 {
41 }
42
43
44
45
FocusManager(const::boost::function<void (const Panel &)> & rShowPanelFunctor)46 FocusManager::FocusManager (const ::boost::function<void(const Panel&)>& rShowPanelFunctor)
47 : mpDeckTitleBar(),
48 maPanels(),
49 maButtons(),
50 maShowPanelFunctor(rShowPanelFunctor),
51 mbObservingContentControlFocus(false),
52 mpFirstFocusedContentControl(NULL)
53 {
54 }
55
56
57
58
~FocusManager(void)59 FocusManager::~FocusManager (void)
60 {
61 Clear();
62 }
63
64
65
66
GrabFocus(void)67 void FocusManager::GrabFocus (void)
68 {
69 FocusDeckTitle();
70 }
71
72
73
74
Clear(void)75 void FocusManager::Clear (void)
76 {
77 SetDeckTitle(NULL);
78 ClearPanels();
79 ClearButtons();
80 }
81
82
83
84
ClearPanels(void)85 void FocusManager::ClearPanels (void)
86 {
87 ::std::vector<Panel*> aPanels;
88 aPanels.swap(maPanels);
89 for (::std::vector<Panel*>::iterator iPanel(aPanels.begin()),iEnd(aPanels.end());
90 iPanel!=iEnd;
91 ++iPanel)
92 {
93 UnregisterWindow(**iPanel);
94 if ((*iPanel)->GetTitleBar() != NULL)
95 {
96 UnregisterWindow(*(*iPanel)->GetTitleBar());
97 UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
98 }
99
100 (*iPanel)->RemoveChildEventListener(LINK(this, FocusManager, ChildEventListener));
101 }
102 }
103
104
105
106
ClearButtons(void)107 void FocusManager::ClearButtons (void)
108 {
109 ::std::vector<Button*> aButtons;
110 aButtons.swap(maButtons);
111 for (::std::vector<Button*>::iterator iButton(aButtons.begin()),iEnd(aButtons.end());
112 iButton!=iEnd;
113 ++iButton)
114 {
115 UnregisterWindow(**iButton);
116 }
117 }
118
119
120
121
SetDeckTitle(DeckTitleBar * pDeckTitleBar)122 void FocusManager::SetDeckTitle (DeckTitleBar* pDeckTitleBar)
123 {
124 if (mpDeckTitleBar != NULL)
125 {
126 UnregisterWindow(*mpDeckTitleBar);
127 UnregisterWindow(mpDeckTitleBar->GetToolBox());
128 }
129 mpDeckTitleBar = pDeckTitleBar;
130
131 if (mpDeckTitleBar != NULL)
132 {
133 RegisterWindow(*mpDeckTitleBar);
134 RegisterWindow(mpDeckTitleBar->GetToolBox());
135 }
136 }
137
138
139
140
SetPanels(const SharedPanelContainer & rPanels)141 void FocusManager::SetPanels (const SharedPanelContainer& rPanels)
142 {
143 ClearPanels();
144 for(SharedPanelContainer::const_iterator iPanel(rPanels.begin()),iEnd(rPanels.end());
145 iPanel!=iEnd;
146 ++iPanel)
147 {
148 RegisterWindow(**iPanel);
149 if ((*iPanel)->GetTitleBar() != NULL)
150 {
151 RegisterWindow(*(*iPanel)->GetTitleBar());
152 RegisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
153 }
154
155 // Register also as child event listener at the panel.
156 (*iPanel)->AddChildEventListener(LINK(this, FocusManager, ChildEventListener));
157
158 maPanels.push_back(iPanel->get());
159 }
160 }
161
162
163
164
SetButtons(const::std::vector<Button * > & rButtons)165 void FocusManager::SetButtons (const ::std::vector<Button*>& rButtons)
166 {
167 ClearButtons();
168 for (::std::vector<Button*>::const_iterator iButton(rButtons.begin()),iEnd(rButtons.end());
169 iButton!=iEnd;
170 ++iButton)
171 {
172 RegisterWindow(**iButton);
173 maButtons.push_back(*iButton);
174 }
175 }
176
177
178
179
RegisterWindow(Window & rWindow)180 void FocusManager::RegisterWindow (Window& rWindow)
181 {
182 rWindow.AddEventListener(LINK(this, FocusManager, WindowEventListener));
183 }
184
185
186
187
UnregisterWindow(Window & rWindow)188 void FocusManager::UnregisterWindow (Window& rWindow)
189 {
190 rWindow.RemoveEventListener(LINK(this, FocusManager, WindowEventListener));
191 }
192
193
194
195
GetFocusLocation(const Window & rWindow) const196 FocusManager::FocusLocation FocusManager::GetFocusLocation (const Window& rWindow) const
197 {
198 // Check the deck title.
199 if (mpDeckTitleBar != NULL)
200 {
201 if (mpDeckTitleBar == &rWindow)
202 return FocusLocation(PC_DeckTitle, -1);
203 else if (&mpDeckTitleBar->GetToolBox() == &rWindow)
204 return FocusLocation(PC_DeckToolBox, -1);
205 }
206
207 // Search the panels.
208 for (sal_Int32 nIndex=0,nCount(maPanels.size()); nIndex<nCount; ++nIndex)
209 {
210 if (maPanels[nIndex] == &rWindow)
211 return FocusLocation(PC_PanelContent, nIndex);
212 TitleBar* pTitleBar = maPanels[nIndex]->GetTitleBar();
213 if (pTitleBar == &rWindow)
214 return FocusLocation(PC_PanelTitle, nIndex);
215 if (pTitleBar!=NULL && &pTitleBar->GetToolBox()==&rWindow)
216 return FocusLocation(PC_PanelToolBox, nIndex);
217 }
218
219 // Search the buttons.
220 for (sal_Int32 nIndex=0,nCount(maButtons.size()); nIndex<nCount; ++nIndex)
221 if (maButtons[nIndex] == &rWindow)
222 return FocusLocation(PC_TabBar, nIndex);
223
224 return FocusLocation(PC_None, -1);
225 }
226
227
228
229
IsAnyPanelFocused(void) const230 bool FocusManager::IsAnyPanelFocused (void) const
231 {
232 for (::std::vector<Panel*>::const_iterator iPanel(maPanels.begin()),iEnd(maPanels.end());
233 iPanel!=iEnd;
234 ++iPanel)
235 {
236 if ((*iPanel)->HasFocus())
237 return true;
238 else if ((*iPanel)->HasChildPathFocus())
239 return true;
240 }
241 return false;
242 }
243
244
245
246
IsAnyButtonFocused(void) const247 bool FocusManager::IsAnyButtonFocused (void) const
248 {
249 for (::std::vector<Button*>::const_iterator iButton(maButtons.begin()),iEnd(maButtons.end());
250 iButton!=iEnd;
251 ++iButton)
252 {
253 if ((*iButton)->HasFocus())
254 return true;
255 }
256 return false;
257 }
258
259
260
261
FocusDeckTitle(void)262 void FocusManager::FocusDeckTitle (void)
263 {
264 if (mpDeckTitleBar != NULL)
265 {
266 if (IsDeckTitleVisible())
267 {
268 mpDeckTitleBar->GrabFocus();
269 }
270 else if (mpDeckTitleBar->GetToolBox().GetItemCount() > 0)
271 {
272 ToolBox& rToolBox = mpDeckTitleBar->GetToolBox();
273 rToolBox.GrabFocus();
274 rToolBox.Invalidate();
275 }
276 else
277 FocusPanel(0, false);
278 }
279 else
280 FocusPanel(0, false);
281 }
282
283
284
285
IsDeckTitleVisible(void) const286 bool FocusManager::IsDeckTitleVisible (void) const
287 {
288 return mpDeckTitleBar != NULL && mpDeckTitleBar->IsVisible();
289 }
290
291
292
293
IsPanelTitleVisible(const sal_Int32 nPanelIndex) const294 bool FocusManager::IsPanelTitleVisible (const sal_Int32 nPanelIndex) const
295 {
296 if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size()))
297 return false;
298
299 TitleBar* pTitleBar = maPanels[nPanelIndex]->GetTitleBar();
300 if (pTitleBar==NULL)
301 return false;
302 return pTitleBar->IsVisible();
303 }
304
305
306
307
FocusPanel(const sal_Int32 nPanelIndex,const bool bFallbackToDeckTitle)308 void FocusManager::FocusPanel (
309 const sal_Int32 nPanelIndex,
310 const bool bFallbackToDeckTitle)
311 {
312 if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size()))
313 {
314 if (bFallbackToDeckTitle)
315 FocusDeckTitle();
316 return;
317 }
318
319 Panel& rPanel (*maPanels[nPanelIndex]);
320 TitleBar* pTitleBar = rPanel.GetTitleBar();
321 if (pTitleBar!=NULL && pTitleBar->IsVisible())
322 {
323 rPanel.SetExpanded(true);
324 pTitleBar->GrabFocus();
325 }
326 else if (bFallbackToDeckTitle)
327 {
328 // The panel title is not visible, fall back to the deck
329 // title.
330 // Make sure that the desk title is visible here to prevent a
331 // loop when both the title of panel 0 and the deck title are
332 // not present.
333 if (IsDeckTitleVisible())
334 FocusDeckTitle();
335 else
336 FocusPanelContent(nPanelIndex);
337 }
338 else
339 FocusPanelContent(nPanelIndex);
340
341 if (maShowPanelFunctor)
342 maShowPanelFunctor(rPanel);
343 }
344
345
346
347
FocusPanelContent(const sal_Int32 nPanelIndex)348 void FocusManager::FocusPanelContent (const sal_Int32 nPanelIndex)
349 {
350 Window* pWindow = VCLUnoHelper::GetWindow(maPanels[nPanelIndex]->GetElementWindow());
351 if (pWindow != NULL)
352 {
353 mbObservingContentControlFocus = true;
354 pWindow->GrabFocus();
355 mbObservingContentControlFocus = false;
356 }
357 }
358
359
360
361
FocusButton(const sal_Int32 nButtonIndex)362 void FocusManager::FocusButton (const sal_Int32 nButtonIndex)
363 {
364 maButtons[nButtonIndex]->GrabFocus();
365 maButtons[nButtonIndex]->Invalidate();
366 }
367
368
369
370
ClickButton(const sal_Int32 nButtonIndex)371 void FocusManager::ClickButton (const sal_Int32 nButtonIndex)
372 {
373 maButtons[nButtonIndex]->Click();
374 if (nButtonIndex > 0)
375 if ( ! maPanels.empty())
376 FocusPanel(0, true);
377 maButtons[nButtonIndex]->GetParent()->Invalidate();
378 }
379
380
381
382
RemoveWindow(Window & rWindow)383 void FocusManager::RemoveWindow (Window& rWindow)
384 {
385 ::std::vector<Panel*>::iterator iPanel (::std::find(maPanels.begin(), maPanels.end(), &rWindow));
386 if (iPanel != maPanels.end())
387 {
388 UnregisterWindow(rWindow);
389 if ((*iPanel)->GetTitleBar() != NULL)
390 {
391 UnregisterWindow(*(*iPanel)->GetTitleBar());
392 UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
393 }
394 maPanels.erase(iPanel);
395 return;
396 }
397
398 ::std::vector<Button*>::iterator iButton (::std::find(maButtons.begin(), maButtons.end(), &rWindow));
399 if (iButton != maButtons.end())
400 {
401 UnregisterWindow(rWindow);
402 maButtons.erase(iButton);
403 return;
404 }
405 }
406
407
408
409
MoveFocusInsidePanel(const FocusLocation aFocusLocation,const sal_Int32 nDirection)410 bool FocusManager::MoveFocusInsidePanel (
411 const FocusLocation aFocusLocation,
412 const sal_Int32 nDirection)
413 {
414 const bool bHasToolBoxItem (
415 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GetItemCount() > 0);
416 switch (aFocusLocation.meComponent)
417 {
418 case PC_PanelTitle:
419 if (nDirection > 0 && bHasToolBoxItem)
420 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GrabFocus();
421 else
422 FocusPanelContent(aFocusLocation.mnIndex);
423 return true;
424
425 case PC_PanelToolBox:
426 if (nDirection < 0 && bHasToolBoxItem)
427 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GrabFocus();
428 else
429 FocusPanelContent(aFocusLocation.mnIndex);
430 return true;
431
432 default:
433 return false;
434 }
435 }
436
437
438
439
MoveFocusInsideDeckTitle(const FocusLocation aFocusLocation,const sal_Int32 nDirection)440 bool FocusManager::MoveFocusInsideDeckTitle (
441 const FocusLocation aFocusLocation,
442 const sal_Int32 nDirection)
443 {
444 // Note that when the title bar of the first (and only) panel is
445 // not visible then the deck title takes its place and the focus
446 // is moved between a) deck title, b) deck closer and c) content
447 // of panel 0.
448 const bool bHasToolBoxItem (
449 mpDeckTitleBar->GetToolBox().GetItemCount() > 0);
450 switch (aFocusLocation.meComponent)
451 {
452 case PC_DeckTitle:
453 if (nDirection<0 && ! IsPanelTitleVisible(0))
454 FocusPanelContent(0);
455 else if (bHasToolBoxItem)
456 mpDeckTitleBar->GetToolBox().GrabFocus();
457 return true;
458
459 case PC_DeckToolBox:
460 if (nDirection>0 && ! IsPanelTitleVisible(0))
461 FocusPanelContent(0);
462 else
463 mpDeckTitleBar->GrabFocus();
464 return true;
465
466 default:
467 return false;
468 }
469 }
470
471
472
473
HandleKeyEvent(const KeyCode & rKeyCode,const Window & rWindow)474 void FocusManager::HandleKeyEvent (
475 const KeyCode& rKeyCode,
476 const Window& rWindow)
477 {
478 const FocusLocation aLocation (GetFocusLocation(rWindow));
479 mpLastFocusedWindow = NULL;
480
481 switch (rKeyCode.GetCode())
482 {
483 case KEY_SPACE:
484 switch (aLocation.meComponent)
485 {
486 case PC_PanelTitle:
487 // Toggle panel between expanded and collapsed.
488 maPanels[aLocation.mnIndex]->SetExpanded( ! maPanels[aLocation.mnIndex]->IsExpanded());
489 break;
490
491 case PC_TabBar:
492 // Activate the button.
493 ClickButton(aLocation.mnIndex);
494 break;
495
496 default:
497 break;
498 }
499 return;
500
501 case KEY_RETURN:
502 switch (aLocation.meComponent)
503 {
504 case PC_DeckToolBox:
505 FocusButton(0);
506 break;
507
508 case PC_PanelTitle:
509 // Enter the panel.
510 FocusPanelContent(aLocation.mnIndex);
511 break;
512
513 case PC_TabBar:
514 // Activate the button.
515 ClickButton(aLocation.mnIndex);
516 break;
517
518 default:
519 break;
520 }
521 return;
522
523 case KEY_TAB:
524 {
525 const sal_Int32 nDirection (
526 rKeyCode.IsShift()
527 ? -1
528 : +1);
529 switch (aLocation.meComponent)
530 {
531 case PC_PanelTitle:
532 case PC_PanelToolBox:
533 case PC_PanelContent:
534 MoveFocusInsidePanel(aLocation, nDirection);
535 break;
536
537 case PC_DeckTitle:
538 case PC_DeckToolBox:
539 MoveFocusInsideDeckTitle(aLocation, nDirection);
540 break;
541
542 default:
543 break;
544 }
545 break;
546 }
547
548 case KEY_LEFT:
549 case KEY_UP:
550 switch (aLocation.meComponent)
551 {
552 case PC_PanelTitle:
553 case PC_PanelToolBox:
554 case PC_PanelContent:
555 // Go to previous panel or the deck title.
556 if (aLocation.mnIndex > 0)
557 FocusPanel(aLocation.mnIndex-1, true);
558 else if (IsDeckTitleVisible())
559 FocusDeckTitle();
560 else
561 FocusButton(maButtons.size()-1);
562 break;
563
564 case PC_DeckTitle:
565 case PC_DeckToolBox:
566 // Focus the last button.
567 FocusButton(maButtons.size()-1);
568 break;
569
570 case PC_TabBar:
571 // Go to previous tab bar item.
572 if (aLocation.mnIndex == 0)
573 FocusPanel(maPanels.size()-1, true);
574 else
575 FocusButton((aLocation.mnIndex + maButtons.size() - 1) % maButtons.size());
576 break;
577
578 default:
579 break;
580 }
581 break;
582
583 case KEY_RIGHT:
584 case KEY_DOWN:
585 switch(aLocation.meComponent)
586 {
587 case PC_PanelTitle:
588 case PC_PanelToolBox:
589 case PC_PanelContent:
590 // Go to next panel.
591 if (aLocation.mnIndex < static_cast<sal_Int32>(maPanels.size())-1)
592 FocusPanel(aLocation.mnIndex+1, false);
593 else
594 FocusButton(0);
595 break;
596
597 case PC_DeckTitle:
598 case PC_DeckToolBox:
599 // Focus the first panel.
600 if (IsPanelTitleVisible(0))
601 FocusPanel(0, false);
602 else
603 FocusButton(0);
604 break;
605
606 case PC_TabBar:
607 // Go to next tab bar item.
608 if (aLocation.mnIndex < static_cast<sal_Int32>(maButtons.size())-1)
609 FocusButton(aLocation.mnIndex + 1);
610 else if (IsDeckTitleVisible())
611 FocusDeckTitle();
612 else
613 FocusPanel(0, true);
614 break;
615
616 default:
617 break;
618 }
619 break;
620 }
621 }
622
623
624
625
IMPL_LINK(FocusManager,WindowEventListener,VclSimpleEvent *,pEvent)626 IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent)
627 {
628 if (pEvent == NULL)
629 return 0;
630
631 if ( ! pEvent->ISA(VclWindowEvent))
632 return 0;
633
634 VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
635 Window* pSource = pWindowEvent->GetWindow();
636 if (pSource == NULL)
637 return 0;
638
639 switch (pWindowEvent->GetId())
640 {
641 case VCLEVENT_WINDOW_KEYINPUT:
642 {
643 KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
644 HandleKeyEvent(pKeyEvent->GetKeyCode(), *pSource);
645 return 1;
646 }
647
648 case VCLEVENT_OBJECT_DYING:
649 RemoveWindow(*pSource);
650 return 1;
651
652 case VCLEVENT_WINDOW_GETFOCUS:
653 case VCLEVENT_WINDOW_LOSEFOCUS:
654 pSource->Invalidate();
655 return 1;
656
657 default:
658 break;
659 }
660
661 return 0;
662 }
663
664
665
666
IMPL_LINK(FocusManager,ChildEventListener,VclSimpleEvent *,pEvent)667 IMPL_LINK(FocusManager, ChildEventListener, VclSimpleEvent*, pEvent)
668 {
669 if (pEvent == NULL)
670 return 0;
671
672 if ( ! pEvent->ISA(VclWindowEvent))
673 return 0;
674
675 VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
676 Window* pSource = pWindowEvent->GetWindow();
677 if (pSource == NULL)
678 return 0;
679
680 switch (pWindowEvent->GetId())
681 {
682 case VCLEVENT_WINDOW_KEYINPUT:
683 {
684 KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
685
686 // Go up the window hierarchy to find out whether the
687 // parent of the event source is known to us.
688 Window* pWindow = pSource;
689 FocusLocation aLocation (PC_None, -1);
690 while (true)
691 {
692 if (pWindow == NULL)
693 break;
694 aLocation = GetFocusLocation(*pWindow);
695 if (aLocation.meComponent != PC_None)
696 break;
697 pWindow = pWindow->GetParent();
698 }
699
700 if (aLocation.meComponent != PC_None)
701 {
702 switch (pKeyEvent->GetKeyCode().GetCode())
703 {
704 case KEY_ESCAPE:
705 // Return focus back to the panel title.
706 FocusPanel(aLocation.mnIndex, true);
707 break;
708
709 case KEY_TAB:
710 if (mpFirstFocusedContentControl!=NULL
711 && mpLastFocusedWindow == mpFirstFocusedContentControl)
712 {
713 // Move focus back to panel (or deck)
714 // title.
715 FocusPanel(aLocation.mnIndex, true);
716 }
717 break;
718
719 default:
720 break;
721 }
722 }
723 return 1;
724 }
725
726 case VCLEVENT_WINDOW_GETFOCUS:
727 // Keep track of focused controls in panel content.
728 // Remember the first focused control. When it is later
729 // focused again due to pressing the TAB key then the
730 // focus is moved to the panel or deck title.
731 mpLastFocusedWindow = pSource;
732 if (mbObservingContentControlFocus)
733 mpFirstFocusedContentControl = pSource;
734 break;
735
736 default:
737 break;
738 }
739
740 return 0;
741 }
742
743
744 } } // end of namespace sfx2::sidebar
745