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