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