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