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 
37 FocusManager::FocusLocation::FocusLocation (const PanelComponent eComponent, const sal_Int32 nIndex)
38     : meComponent(eComponent),
39       mnIndex(nIndex)
40 {
41 }
42 
43 
44 
45 
46 FocusManager::FocusManager (const ::boost::function<void(const Panel&)>& rShowPanelFunctor)
47     : mpDeckTitleBar(),
48       maPanels(),
49       maButtons(),
50       maShowPanelFunctor(rShowPanelFunctor)
51 {
52 }
53 
54 
55 
56 
57 FocusManager::~FocusManager (void)
58 {
59     Clear();
60 }
61 
62 
63 
64 
65 void FocusManager::GrabFocus (void)
66 {
67     FocusDeckTitle();
68 }
69 
70 
71 
72 
73 void FocusManager::Clear (void)
74 {
75     SetDeckTitle(NULL);
76     ClearPanels();
77     ClearButtons();
78 }
79 
80 
81 
82 
83 void FocusManager::ClearPanels (void)
84 {
85     ::std::vector<Panel*> aPanels;
86     aPanels.swap(maPanels);
87     for (::std::vector<Panel*>::iterator iPanel(aPanels.begin()),iEnd(aPanels.end());
88          iPanel!=iEnd;
89         ++iPanel)
90     {
91         UnregisterWindow(**iPanel);
92         if ((*iPanel)->GetTitleBar() != NULL)
93         {
94             UnregisterWindow(*(*iPanel)->GetTitleBar());
95             UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
96         }
97 
98         (*iPanel)->RemoveChildEventListener(LINK(this, FocusManager, ChildEventListener));
99     }
100 }
101 
102 
103 
104 
105 void FocusManager::ClearButtons (void)
106 {
107     ::std::vector<Button*> aButtons;
108     aButtons.swap(maButtons);
109     for (::std::vector<Button*>::iterator iButton(aButtons.begin()),iEnd(aButtons.end());
110          iButton!=iEnd;
111         ++iButton)
112     {
113         UnregisterWindow(**iButton);
114     }
115 }
116 
117 
118 
119 
120 void FocusManager::SetDeckTitle (DeckTitleBar* pDeckTitleBar)
121 {
122     if (mpDeckTitleBar != NULL)
123     {
124         UnregisterWindow(*mpDeckTitleBar);
125         UnregisterWindow(mpDeckTitleBar->GetToolBox());
126     }
127     mpDeckTitleBar = pDeckTitleBar;
128 
129     if (mpDeckTitleBar != NULL)
130     {
131         RegisterWindow(*mpDeckTitleBar);
132         RegisterWindow(mpDeckTitleBar->GetToolBox());
133     }
134 }
135 
136 
137 
138 
139 void FocusManager::SetPanels (const SharedPanelContainer& rPanels)
140 {
141     ClearPanels();
142     for(SharedPanelContainer::const_iterator iPanel(rPanels.begin()),iEnd(rPanels.end());
143         iPanel!=iEnd;
144         ++iPanel)
145     {
146         RegisterWindow(**iPanel);
147         if ((*iPanel)->GetTitleBar() != NULL)
148         {
149             RegisterWindow(*(*iPanel)->GetTitleBar());
150             RegisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
151         }
152 
153         // Register also as child event listener at the panel.
154         (*iPanel)->AddChildEventListener(LINK(this, FocusManager, ChildEventListener));
155 
156         maPanels.push_back(iPanel->get());
157     }
158 }
159 
160 
161 
162 
163 void FocusManager::SetButtons (const ::std::vector<Button*>& rButtons)
164 {
165     ClearButtons();
166     for (::std::vector<Button*>::const_iterator iButton(rButtons.begin()),iEnd(rButtons.end());
167          iButton!=iEnd;
168          ++iButton)
169     {
170         RegisterWindow(**iButton);
171         maButtons.push_back(*iButton);
172     }
173 }
174 
175 
176 
177 
178 void FocusManager::RegisterWindow (Window& rWindow)
179 {
180     rWindow.AddEventListener(LINK(this, FocusManager, WindowEventListener));
181 }
182 
183 
184 
185 
186 void FocusManager::UnregisterWindow (Window& rWindow)
187 {
188     rWindow.RemoveEventListener(LINK(this, FocusManager, WindowEventListener));
189 }
190 
191 
192 
193 
194 FocusManager::FocusLocation FocusManager::GetFocusLocation (const Window& rWindow) const
195 {
196     // Check the deck title.
197     if (mpDeckTitleBar != NULL)
198     {
199         if (mpDeckTitleBar == &rWindow)
200             return FocusLocation(PC_DeckTitle, -1);
201         else if (&mpDeckTitleBar->GetToolBox() == &rWindow)
202             return FocusLocation(PC_DeckToolBox, -1);
203     }
204 
205     // Search the panels.
206     for (sal_Int32 nIndex=0,nCount(maPanels.size()); nIndex<nCount; ++nIndex)
207     {
208         if (maPanels[nIndex] == &rWindow)
209             return FocusLocation(PC_PanelContent, nIndex);
210         TitleBar* pTitleBar = maPanels[nIndex]->GetTitleBar();
211         if (pTitleBar == &rWindow)
212             return FocusLocation(PC_PanelTitle, nIndex);
213         if (pTitleBar!=NULL && &pTitleBar->GetToolBox()==&rWindow)
214             return FocusLocation(PC_PanelToolBox, nIndex);
215     }
216 
217     // Search the buttons.
218     for (sal_Int32 nIndex=0,nCount(maButtons.size()); nIndex<nCount; ++nIndex)
219         if (maButtons[nIndex] == &rWindow)
220             return FocusLocation(PC_TabBar, nIndex);
221 
222     return FocusLocation(PC_None, -1);
223 }
224 
225 
226 
227 
228 bool FocusManager::IsAnyPanelFocused (void) const
229 {
230     for (::std::vector<Panel*>::const_iterator iPanel(maPanels.begin()),iEnd(maPanels.end());
231          iPanel!=iEnd;
232          ++iPanel)
233     {
234         if ((*iPanel)->HasFocus())
235             return true;
236         else if ((*iPanel)->HasChildPathFocus())
237             return true;
238     }
239     return false;
240 }
241 
242 
243 
244 
245 bool FocusManager::IsAnyButtonFocused (void) const
246 {
247     for (::std::vector<Button*>::const_iterator iButton(maButtons.begin()),iEnd(maButtons.end());
248          iButton!=iEnd;
249          ++iButton)
250     {
251         if ((*iButton)->HasFocus())
252             return true;
253     }
254     return false;
255 }
256 
257 
258 
259 
260 void FocusManager::FocusDeckTitle (void)
261 {
262     if (IsDeckTitleVisible())
263     {
264         ToolBox& rToolBox = mpDeckTitleBar->GetToolBox();
265         if (rToolBox.GetItemCount() > 0)
266         {
267             rToolBox.GrabFocus();
268             rToolBox.Invalidate();
269         }
270     }
271     else
272         FocusPanel(0);
273 }
274 
275 
276 
277 
278 bool FocusManager::IsDeckTitleVisible (void) const
279 {
280     return mpDeckTitleBar != NULL && mpDeckTitleBar->IsVisible();
281 }
282 
283 
284 
285 
286 void FocusManager::FocusPanel (const sal_Int32 nPanelIndex)
287 {
288     if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size()))
289         return;
290     Panel& rPanel (*maPanels[nPanelIndex]);
291     TitleBar* pTitleBar = rPanel.GetTitleBar();
292     if (pTitleBar!=NULL && pTitleBar->IsVisible())
293     {
294         rPanel.SetExpanded(true);
295         pTitleBar->GrabFocus();
296     }
297     else
298         FocusPanelContent(nPanelIndex);
299     if (maShowPanelFunctor)
300         maShowPanelFunctor(rPanel);
301 }
302 
303 
304 
305 
306 void FocusManager::FocusPanelContent (const sal_Int32 nPanelIndex)
307 {
308     Window* pWindow = VCLUnoHelper::GetWindow(maPanels[nPanelIndex]->GetElementWindow());
309     if (pWindow != NULL)
310         pWindow->GrabFocus();
311 }
312 
313 
314 
315 
316 void FocusManager::FocusButton (const sal_Int32 nButtonIndex)
317 {
318     maButtons[nButtonIndex]->GrabFocus();
319     maButtons[nButtonIndex]->Invalidate();
320 }
321 
322 
323 
324 
325 void FocusManager::ClickButton (const sal_Int32 nButtonIndex)
326 {
327     maButtons[nButtonIndex]->Click();
328     if (nButtonIndex > 0)
329         if ( ! maPanels.empty())
330             FocusPanel(0);
331     maButtons[nButtonIndex]->GetParent()->Invalidate();
332 }
333 
334 
335 
336 
337 void FocusManager::RemoveWindow (Window& rWindow)
338 {
339     ::std::vector<Panel*>::iterator iPanel (::std::find(maPanels.begin(), maPanels.end(), &rWindow));
340     if (iPanel != maPanels.end())
341     {
342         UnregisterWindow(rWindow);
343         if ((*iPanel)->GetTitleBar() != NULL)
344         {
345             UnregisterWindow(*(*iPanel)->GetTitleBar());
346             UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
347         }
348         maPanels.erase(iPanel);
349         return;
350     }
351 
352     ::std::vector<Button*>::iterator iButton (::std::find(maButtons.begin(), maButtons.end(), &rWindow));
353     if (iButton != maButtons.end())
354     {
355         UnregisterWindow(rWindow);
356         maButtons.erase(iButton);
357         return;
358     }
359 }
360 
361 
362 
363 
364 bool FocusManager::MoveFocusInsidePanel (
365     const FocusLocation aFocusLocation,
366     const sal_Int32 nDirection)
367 {
368     const bool bHasToolBoxItem (
369         maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GetItemCount() > 0);
370     switch (aFocusLocation.meComponent)
371     {
372         case  PC_PanelTitle:
373             if (nDirection > 0 && bHasToolBoxItem)
374                 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GrabFocus();
375             else
376                 FocusPanelContent(aFocusLocation.mnIndex);
377             return true;
378 
379         case PC_PanelToolBox:
380             if (nDirection < 0 && bHasToolBoxItem)
381                 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GrabFocus();
382             else
383                 FocusPanelContent(aFocusLocation.mnIndex);
384             return true;
385 
386         default:
387             return false;
388     }
389 }
390 
391 
392 
393 
394 void FocusManager::HandleKeyEvent (
395     const KeyCode& rKeyCode,
396     const Window& rWindow)
397 {
398     const FocusLocation aLocation (GetFocusLocation(rWindow));
399 
400     switch (rKeyCode.GetCode())
401     {
402         case KEY_SPACE:
403             switch (aLocation.meComponent)
404             {
405                 case PC_PanelTitle:
406                     // Toggle panel between expanded and collapsed.
407                     maPanels[aLocation.mnIndex]->SetExpanded( ! maPanels[aLocation.mnIndex]->IsExpanded());
408                     break;
409 
410                 case PC_TabBar:
411                     // Activate the button.
412                     ClickButton(aLocation.mnIndex);
413                     break;
414 
415                 default:
416                     break;
417             }
418             return;
419 
420         case KEY_RETURN:
421             switch (aLocation.meComponent)
422             {
423                 case PC_DeckToolBox:
424                     FocusButton(0);
425                     break;
426 
427                 case PC_PanelTitle:
428                     // Enter the panel.
429                     FocusPanelContent(aLocation.mnIndex);
430                     break;
431 
432                 case PC_TabBar:
433                     // Activate the button.
434                     ClickButton(aLocation.mnIndex);
435                     break;
436 
437                 default:
438                     break;
439             }
440             return;
441 
442         case KEY_TAB:
443             switch (aLocation.meComponent)
444             {
445                 case PC_PanelTitle:
446                 case PC_PanelToolBox:
447                 case PC_PanelContent:
448                     if (rKeyCode.IsShift())
449                         MoveFocusInsidePanel(aLocation, -1);
450                     else
451                         MoveFocusInsidePanel(aLocation, +1);
452                     break;
453 
454                 default:
455                     break;
456             }
457             break;
458 
459         case KEY_LEFT:
460         case KEY_UP:
461             switch (aLocation.meComponent)
462             {
463                 case PC_PanelTitle:
464                 case PC_PanelToolBox:
465                 case PC_PanelContent:
466                     // Go to previous panel or the deck title.
467                     if (aLocation.mnIndex > 0)
468                         FocusPanel(aLocation.mnIndex-1);
469                     else if (IsDeckTitleVisible())
470                         FocusDeckTitle();
471                     else
472                         FocusButton(maButtons.size()-1);
473                     break;
474 
475                 case PC_DeckTitle:
476                 case PC_DeckToolBox:
477                     // Focus the last button.
478                     FocusButton(maButtons.size()-1);
479                     break;
480 
481                 case PC_TabBar:
482                     // Go to previous tab bar item.
483                     if (aLocation.mnIndex == 0)
484                         FocusPanel(maPanels.size()-1);
485                     else
486                         FocusButton((aLocation.mnIndex + maButtons.size() - 1) % maButtons.size());
487                     break;
488 
489                 default:
490                     break;
491             }
492             break;
493 
494         case KEY_RIGHT:
495         case KEY_DOWN:
496             switch(aLocation.meComponent)
497             {
498                 case PC_PanelTitle:
499                 case PC_PanelToolBox:
500                 case PC_PanelContent:
501                     // Go to next panel.
502                     if (aLocation.mnIndex < static_cast<sal_Int32>(maPanels.size())-1)
503                         FocusPanel(aLocation.mnIndex+1);
504                     else
505                         FocusButton(0);
506                     break;
507 
508                 case PC_DeckTitle:
509                 case PC_DeckToolBox:
510                     // Focus the first panel.
511                     FocusPanel(0);
512                     break;
513 
514                 case PC_TabBar:
515                     // Go to next tab bar item.
516                     if (aLocation.mnIndex < static_cast<sal_Int32>(maButtons.size())-1)
517                         FocusButton(aLocation.mnIndex + 1);
518                     else if (IsDeckTitleVisible())
519                         FocusDeckTitle();
520                     else
521                         FocusPanel(0);
522                     break;
523 
524                 default:
525                     break;
526             }
527             break;
528     }
529 }
530 
531 
532 
533 
534 IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent)
535 {
536     if (pEvent == NULL)
537         return 0;
538 
539     if ( ! pEvent->ISA(VclWindowEvent))
540         return 0;
541 
542     VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
543     Window* pSource = pWindowEvent->GetWindow();
544     if (pSource == NULL)
545         return 0;
546 
547     switch (pWindowEvent->GetId())
548     {
549         case VCLEVENT_WINDOW_KEYINPUT:
550         {
551             KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
552             HandleKeyEvent(pKeyEvent->GetKeyCode(), *pSource);
553             return 1;
554         }
555 
556         case VCLEVENT_OBJECT_DYING:
557             RemoveWindow(*pSource);
558             return 1;
559 
560         case VCLEVENT_WINDOW_GETFOCUS:
561         case VCLEVENT_WINDOW_LOSEFOCUS:
562             pSource->Invalidate();
563             return 1;
564 
565         default:
566             break;
567     }
568 
569     return 0;
570 }
571 
572 
573 
574 
575 IMPL_LINK(FocusManager, ChildEventListener, VclSimpleEvent*, pEvent)
576 {
577     if (pEvent == NULL)
578         return 0;
579 
580     if ( ! pEvent->ISA(VclWindowEvent))
581         return 0;
582 
583     VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
584     Window* pSource = pWindowEvent->GetWindow();
585     if (pSource == NULL)
586         return 0;
587 
588     switch (pWindowEvent->GetId())
589     {
590         case VCLEVENT_WINDOW_KEYINPUT:
591         {
592             KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
593 
594             // Go up the window hierarchy to find the parent of the
595             // event source which is known to us.
596             Window* pWindow = pSource;
597             FocusLocation aLocation (PC_None, -1);
598             while (true)
599             {
600                 if (pWindow == NULL)
601                     break;
602                 aLocation = GetFocusLocation(*pWindow);
603                 if (aLocation.meComponent != PC_None)
604                     break;
605                 pWindow = pWindow->GetParent();
606             }
607 
608             if (aLocation.meComponent != PC_None)
609             {
610                 switch (pKeyEvent->GetKeyCode().GetCode())
611                 {
612                     case KEY_ESCAPE:
613                         // Return focus back to the panel title.
614                         FocusPanel(aLocation.mnIndex);
615                         break;
616 
617                     default:
618                         break;
619                 }
620             }
621             return 1;
622         }
623 
624         default:
625             break;
626     }
627 
628     return 0;
629 }
630 
631 
632 } } // end of namespace sfx2::sidebar
633