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