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     {
198         if (mpDeckTitleBar == &rWindow)
199             return FocusLocation(PC_DeckTitle, -1);
200         else if (&mpDeckTitleBar->GetToolBox() == &rWindow)
201             return FocusLocation(PC_DeckToolBox, -1);
202     }
203 
204     // Search the panels.
205     for (sal_Int32 nIndex=0,nCount(maPanels.size()); nIndex<nCount; ++nIndex)
206     {
207         if (maPanels[nIndex] == &rWindow)
208             return FocusLocation(PC_PanelContent, nIndex);
209         TitleBar* pTitleBar = maPanels[nIndex]->GetTitleBar();
210         if (pTitleBar == &rWindow)
211             return FocusLocation(PC_PanelTitle, nIndex);
212         if (pTitleBar!=NULL && &pTitleBar->GetToolBox()==&rWindow)
213             return FocusLocation(PC_PanelToolBox, nIndex);
214     }
215 
216     // Search the buttons.
217     for (sal_Int32 nIndex=0,nCount(maButtons.size()); nIndex<nCount; ++nIndex)
218         if (maButtons[nIndex] == &rWindow)
219             return FocusLocation(PC_TabBar, nIndex);
220 
221     return FocusLocation(PC_None, -1);
222 }
223 
224 
225 
226 
227 bool FocusManager::IsAnyPanelFocused (void) const
228 {
229     for (::std::vector<Panel*>::const_iterator iPanel(maPanels.begin()),iEnd(maPanels.end());
230          iPanel!=iEnd;
231          ++iPanel)
232     {
233         if ((*iPanel)->HasFocus())
234             return true;
235         else if ((*iPanel)->HasChildPathFocus())
236             return true;
237     }
238     return false;
239 }
240 
241 
242 
243 
244 bool FocusManager::IsAnyButtonFocused (void) const
245 {
246     for (::std::vector<Button*>::const_iterator iButton(maButtons.begin()),iEnd(maButtons.end());
247          iButton!=iEnd;
248          ++iButton)
249     {
250         if ((*iButton)->HasFocus())
251             return true;
252     }
253     return false;
254 }
255 
256 
257 
258 
259 void FocusManager::FocusDeckTitle (void)
260 {
261     if (IsDeckTitleVisible())
262     {
263         ToolBox& rToolBox = mpDeckTitleBar->GetToolBox();
264         if (rToolBox.GetItemCount() > 0)
265         {
266             rToolBox.GrabFocus();
267             rToolBox.Invalidate();
268         }
269     }
270     else
271         FocusPanel(0);
272 }
273 
274 
275 
276 
277 bool FocusManager::IsDeckTitleVisible (void) const
278 {
279     return mpDeckTitleBar != NULL && mpDeckTitleBar->IsVisible();
280 }
281 
282 
283 
284 
285 void FocusManager::FocusPanel (const sal_Int32 nPanelIndex)
286 {
287     if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size()))
288         return;
289     Panel& rPanel (*maPanels[nPanelIndex]);
290     TitleBar* pTitleBar = rPanel.GetTitleBar();
291     if (pTitleBar!=NULL && pTitleBar->IsVisible())
292     {
293         rPanel.SetExpanded(true);
294         pTitleBar->GrabFocus();
295     }
296     else
297         FocusPanelContent(nPanelIndex);
298     if (maShowPanelFunctor)
299         maShowPanelFunctor(rPanel);
300 }
301 
302 
303 
304 
305 void FocusManager::FocusPanelContent (const sal_Int32 nPanelIndex)
306 {
307     Window* pWindow = VCLUnoHelper::GetWindow(maPanels[nPanelIndex]->GetElementWindow());
308     if (pWindow != NULL)
309         pWindow->GrabFocus();
310 }
311 
312 
313 
314 
315 void FocusManager::FocusButton (const sal_Int32 nButtonIndex)
316 {
317     maButtons[nButtonIndex]->GrabFocus();
318     maButtons[nButtonIndex]->Invalidate();
319 }
320 
321 
322 
323 
324 void FocusManager::ClickButton (const sal_Int32 nButtonIndex)
325 {
326     maButtons[nButtonIndex]->Click();
327     if (nButtonIndex > 0)
328         if ( ! maPanels.empty())
329             FocusPanel(0);
330     maButtons[nButtonIndex]->GetParent()->Invalidate();
331 }
332 
333 
334 
335 
336 void FocusManager::RemoveWindow (Window& rWindow)
337 {
338     ::std::vector<Panel*>::iterator iPanel (::std::find(maPanels.begin(), maPanels.end(), &rWindow));
339     if (iPanel != maPanels.end())
340     {
341         UnregisterWindow(rWindow);
342         if ((*iPanel)->GetTitleBar() != NULL)
343         {
344             UnregisterWindow(*(*iPanel)->GetTitleBar());
345             UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox());
346         }
347         maPanels.erase(iPanel);
348         return;
349     }
350 
351     ::std::vector<Button*>::iterator iButton (::std::find(maButtons.begin(), maButtons.end(), &rWindow));
352     if (iButton != maButtons.end())
353     {
354         UnregisterWindow(rWindow);
355         maButtons.erase(iButton);
356         return;
357     }
358 }
359 
360 
361 
362 
363 bool FocusManager::MoveFocusInsidePanel (
364     const FocusLocation aFocusLocation,
365     const sal_Int32 nDirection)
366 {
367     const bool bHasToolBoxItem (
368         maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GetItemCount() > 0);
369     switch (aFocusLocation.meComponent)
370     {
371         case  PC_PanelTitle:
372             if (nDirection > 0 && bHasToolBoxItem)
373                 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GrabFocus();
374             else
375                 FocusPanelContent(aFocusLocation.mnIndex);
376             return true;
377 
378         case PC_PanelToolBox:
379             if (nDirection < 0 && bHasToolBoxItem)
380                 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GrabFocus();
381             else
382                 FocusPanelContent(aFocusLocation.mnIndex);
383             return true;
384 
385         default:
386             return false;
387     }
388 }
389 
390 
391 
392 
393 void FocusManager::HandleKeyEvent (
394     const KeyCode& rKeyCode,
395     const Window& rWindow)
396 {
397     const FocusLocation aLocation (GetFocusLocation(rWindow));
398 
399     switch (rKeyCode.GetCode())
400     {
401         case KEY_SPACE:
402             switch (aLocation.meComponent)
403             {
404                 case PC_PanelTitle:
405                     // Toggle panel between expanded and collapsed.
406                     maPanels[aLocation.mnIndex]->SetExpanded( ! maPanels[aLocation.mnIndex]->IsExpanded());
407                     break;
408 
409                 case PC_TabBar:
410                     // Activate the button.
411                     ClickButton(aLocation.mnIndex);
412                     break;
413 
414                 default:
415                     break;
416             }
417             return;
418 
419         case KEY_RETURN:
420             switch (aLocation.meComponent)
421             {
422                 case PC_DeckToolBox:
423                     FocusButton(0);
424                     break;
425 
426                 case PC_PanelTitle:
427                     // Enter the panel.
428                     FocusPanelContent(aLocation.mnIndex);
429                     break;
430 
431                 case PC_TabBar:
432                     // Activate the button.
433                     ClickButton(aLocation.mnIndex);
434                     break;
435 
436                 default:
437                     break;
438             }
439             return;
440 
441         case KEY_TAB:
442             switch (aLocation.meComponent)
443             {
444                 case PC_PanelTitle:
445                 case PC_PanelToolBox:
446                 case PC_PanelContent:
447                     if (rKeyCode.IsShift())
448                         MoveFocusInsidePanel(aLocation, -1);
449                     else
450                         MoveFocusInsidePanel(aLocation, +1);
451                     break;
452 
453                 default:
454                     break;
455             }
456             break;
457 
458         case KEY_LEFT:
459         case KEY_UP:
460             switch (aLocation.meComponent)
461             {
462                 case PC_PanelTitle:
463                 case PC_PanelToolBox:
464                 case PC_PanelContent:
465                     // Go to previous panel or the deck title.
466                     if (aLocation.mnIndex > 0)
467                         FocusPanel(aLocation.mnIndex-1);
468                     else if (IsDeckTitleVisible())
469                         FocusDeckTitle();
470                     else
471                         FocusButton(maButtons.size()-1);
472                     break;
473 
474                 case PC_DeckTitle:
475                 case PC_DeckToolBox:
476                     // Focus the last button.
477                     FocusButton(maButtons.size()-1);
478                     break;
479 
480                 case PC_TabBar:
481                     // Go to previous tab bar item.
482                     if (aLocation.mnIndex == 0)
483                         FocusPanel(maPanels.size()-1);
484                     else
485                         FocusButton((aLocation.mnIndex + maButtons.size() - 1) % maButtons.size());
486                     break;
487 
488                 default:
489                     break;
490             }
491             break;
492 
493         case KEY_RIGHT:
494         case KEY_DOWN:
495             switch(aLocation.meComponent)
496             {
497                 case PC_PanelTitle:
498                 case PC_PanelToolBox:
499                 case PC_PanelContent:
500                     // Go to next panel.
501                     if (aLocation.mnIndex < static_cast<sal_Int32>(maPanels.size())-1)
502                         FocusPanel(aLocation.mnIndex+1);
503                     else
504                         FocusButton(0);
505                     break;
506 
507                 case PC_DeckTitle:
508                 case PC_DeckToolBox:
509                     // Focus the first panel.
510                     FocusPanel(0);
511                     break;
512 
513                 case PC_TabBar:
514                     // Go to next tab bar item.
515                     if (aLocation.mnIndex < static_cast<sal_Int32>(maButtons.size())-1)
516                         FocusButton(aLocation.mnIndex + 1);
517                     else if (IsDeckTitleVisible())
518                         FocusDeckTitle();
519                     else
520                         FocusPanel(0);
521                     break;
522 
523                 default:
524                     break;
525             }
526             break;
527     }
528 }
529 
530 
531 
532 
533 IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent)
534 {
535     if (pEvent == NULL)
536         return 0;
537 
538     if ( ! pEvent->ISA(VclWindowEvent))
539         return 0;
540 
541     VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
542     Window* pSource = pWindowEvent->GetWindow();
543     if (pSource == NULL)
544         return 0;
545 
546     switch (pWindowEvent->GetId())
547     {
548         case VCLEVENT_WINDOW_KEYINPUT:
549         {
550             KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
551             HandleKeyEvent(pKeyEvent->GetKeyCode(), *pSource);
552             return 1;
553         }
554 
555         case VCLEVENT_OBJECT_DYING:
556             RemoveWindow(*pSource);
557             return 1;
558 
559         case VCLEVENT_WINDOW_GETFOCUS:
560         case VCLEVENT_WINDOW_LOSEFOCUS:
561             pSource->Invalidate();
562     }
563 
564     return 0;
565 }
566 
567 
568 
569 
570 IMPL_LINK(FocusManager, ChildEventListener, VclSimpleEvent*, pEvent)
571 {
572     if (pEvent == NULL)
573         return 0;
574 
575     if ( ! pEvent->ISA(VclWindowEvent))
576         return 0;
577 
578     VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
579     Window* pSource = pWindowEvent->GetWindow();
580     if (pSource == NULL)
581         return 0;
582 
583     switch (pWindowEvent->GetId())
584     {
585         case VCLEVENT_WINDOW_KEYINPUT:
586         {
587             KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
588 
589             // Go up the window hierarchy to find the parent of the
590             // event source which is known to us.
591             Window* pWindow = pSource;
592             FocusLocation aLocation (PC_None, -1);
593             while (true)
594             {
595                 if (pWindow == NULL)
596                     break;
597                 aLocation = GetFocusLocation(*pWindow);
598                 if (aLocation.meComponent != PC_None)
599                     break;
600                 pWindow = pWindow->GetParent();
601             }
602 
603             if (aLocation.meComponent != PC_None)
604             {
605                 switch (pKeyEvent->GetKeyCode().GetCode())
606                 {
607                     case KEY_ESCAPE:
608                         // Return focus back to the panel title.
609                         FocusPanel(aLocation.mnIndex);
610                         break;
611 
612                     default:
613                         break;
614                 }
615             }
616             break;
617         }
618 
619         default:
620             break;
621     }
622 
623     return 1;
624 }
625 
626 
627 } } // end of namespace sfx2::sidebar
628