- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / focus / focus_manager.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/focus/focus_manager.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "base/auto_reset.h"
11 #include "base/logging.h"
12 #include "build/build_config.h"
13 #include "ui/base/accelerators/accelerator.h"
14 #include "ui/events/event.h"
15 #include "ui/events/keycodes/keyboard_codes.h"
16 #include "ui/views/focus/focus_manager_delegate.h"
17 #include "ui/views/focus/focus_search.h"
18 #include "ui/views/focus/view_storage.h"
19 #include "ui/views/focus/widget_focus_manager.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/root_view.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/widget/widget_delegate.h"
24
25 namespace views {
26
27 namespace {
28
29 }  // namespace
30
31 bool FocusManager::shortcut_handling_suspended_ = false;
32 bool FocusManager::arrow_key_traversal_enabled_ = false;
33
34 FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
35     : widget_(widget),
36       delegate_(delegate),
37       focused_view_(NULL),
38       accelerator_manager_(new ui::AcceleratorManager),
39       focus_change_reason_(kReasonDirectFocusChange),
40       is_changing_focus_(false) {
41   DCHECK(widget_);
42   stored_focused_view_storage_id_ =
43       ViewStorage::GetInstance()->CreateStorageID();
44 }
45
46 FocusManager::~FocusManager() {
47 }
48
49 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
50   const int key_code = event.key_code();
51
52   if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
53     return false;
54
55   if (shortcut_handling_suspended())
56     return true;
57
58   int modifiers = ui::EF_NONE;
59   if (event.IsShiftDown())
60     modifiers |= ui::EF_SHIFT_DOWN;
61   if (event.IsControlDown())
62     modifiers |= ui::EF_CONTROL_DOWN;
63   if (event.IsAltDown())
64     modifiers |= ui::EF_ALT_DOWN;
65   ui::Accelerator accelerator(event.key_code(), modifiers);
66   accelerator.set_type(event.type());
67
68   if (event.type() == ui::ET_KEY_PRESSED) {
69     // If the focused view wants to process the key event as is, let it be.
70     if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
71         !accelerator_manager_->HasPriorityHandler(accelerator))
72       return true;
73
74     // Intercept Tab related messages for focus traversal.
75     // Note that we don't do focus traversal if the root window is not part of
76     // the active window hierarchy as this would mean we have no focused view
77     // and would focus the first focusable view.
78 #if defined(OS_WIN) && !defined(USE_AURA)
79     HWND top_window = widget_->GetNativeView();
80     HWND active_window = ::GetActiveWindow();
81     if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
82         IsTabTraversalKeyEvent(event)) {
83       AdvanceFocus(event.IsShiftDown());
84       return false;
85     }
86 #else
87     if (IsTabTraversalKeyEvent(event)) {
88       AdvanceFocus(event.IsShiftDown());
89       return false;
90     }
91 #endif
92
93     if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
94       return false;
95
96     // Intercept arrow key messages to switch between grouped views.
97     if (focused_view_ && focused_view_->GetGroup() != -1 &&
98         (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
99          key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
100       bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
101       View::Views views;
102       focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
103                                                &views);
104       View::Views::const_iterator i(
105           std::find(views.begin(), views.end(), focused_view_));
106       DCHECK(i != views.end());
107       int index = static_cast<int>(i - views.begin());
108       index += next ? 1 : -1;
109       if (index < 0) {
110         index = static_cast<int>(views.size()) - 1;
111       } else if (index >= static_cast<int>(views.size())) {
112         index = 0;
113       }
114       SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
115       return false;
116     }
117   }
118
119   // Process keyboard accelerators.
120   // If the key combination matches an accelerator, the accelerator is
121   // triggered, otherwise the key event is processed as usual.
122   if (ProcessAccelerator(accelerator)) {
123     // If a shortcut was activated for this keydown message, do not propagate
124     // the event further.
125     return false;
126   }
127   return true;
128 }
129
130 void FocusManager::ValidateFocusedView() {
131   if (focused_view_ && !ContainsView(focused_view_))
132     ClearFocus();
133 }
134
135 // Tests whether a view is valid, whether it still belongs to the window
136 // hierarchy of the FocusManager.
137 bool FocusManager::ContainsView(View* view) {
138   Widget* widget = view->GetWidget();
139   return widget ? widget->GetFocusManager() == this : false;
140 }
141
142 void FocusManager::AdvanceFocus(bool reverse) {
143   View* v = GetNextFocusableView(focused_view_, NULL, reverse, false);
144   // Note: Do not skip this next block when v == focused_view_.  If the user
145   // tabs past the last focusable element in a webpage, we'll get here, and if
146   // the TabContentsContainerView is the only focusable view (possible in
147   // fullscreen mode), we need to run this block in order to cycle around to the
148   // first element on the page.
149   if (v) {
150     views::View* focused_view = focused_view_;
151     v->AboutToRequestFocusFromTabTraversal(reverse);
152     // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
153     // don't change focus again.
154     if (focused_view == focused_view_)
155       SetFocusedViewWithReason(v, kReasonFocusTraversal);
156   }
157 }
158
159 void FocusManager::ClearNativeFocus() {
160   // Keep the top root window focused so we get keyboard events.
161   widget_->ClearNativeFocus();
162 }
163
164 bool FocusManager::RotatePaneFocus(Direction direction,
165                                    FocusCycleWrappingBehavior wrap) {
166   // Get the list of all accessible panes.
167   std::vector<View*> panes;
168   widget_->widget_delegate()->GetAccessiblePanes(&panes);
169
170   // Count the number of panes and set the default index if no pane
171   // is initially focused.
172   int count = static_cast<int>(panes.size());
173   if (count == 0)
174     return false;
175
176   // Initialize |index| to an appropriate starting index if nothing is
177   // focused initially.
178   int index = direction == kBackward ? 0 : count - 1;
179
180   // Check to see if a pane already has focus and update the index accordingly.
181   const views::View* focused_view = GetFocusedView();
182   if (focused_view) {
183     for (int i = 0; i < count; i++) {
184       if (panes[i] && panes[i]->Contains(focused_view)) {
185         index = i;
186         break;
187       }
188     }
189   }
190
191   // Rotate focus.
192   int start_index = index;
193   for (;;) {
194     if (direction == kBackward)
195       index--;
196     else
197       index++;
198
199     if (wrap == kNoWrap && (index >= count || index < 0))
200       return false;
201     index = (index + count) % count;
202
203     // Ensure that we don't loop more than once.
204     if (index == start_index)
205       break;
206
207     views::View* pane = panes[index];
208     DCHECK(pane);
209
210     if (!pane->visible())
211       continue;
212
213     pane->RequestFocus();
214     focused_view = GetFocusedView();
215     if (pane == focused_view || pane->Contains(focused_view))
216       return true;
217   }
218
219   return false;
220 }
221
222 View* FocusManager::GetNextFocusableView(View* original_starting_view,
223                                          Widget* starting_widget,
224                                          bool reverse,
225                                          bool dont_loop) {
226   FocusTraversable* focus_traversable = NULL;
227
228   // Let's revalidate the focused view.
229   ValidateFocusedView();
230
231   View* starting_view = NULL;
232   if (original_starting_view) {
233     // Search up the containment hierarchy to see if a view is acting as
234     // a pane, and wants to implement its own focus traversable to keep
235     // the focus trapped within that pane.
236     View* pane_search = original_starting_view;
237     while (pane_search) {
238       focus_traversable = pane_search->GetPaneFocusTraversable();
239       if (focus_traversable) {
240         starting_view = original_starting_view;
241         break;
242       }
243       pane_search = pane_search->parent();
244     }
245
246     if (!focus_traversable) {
247       if (!reverse) {
248         // If the starting view has a focus traversable, use it.
249         // This is the case with NativeWidgetWins for example.
250         focus_traversable = original_starting_view->GetFocusTraversable();
251
252         // Otherwise default to the root view.
253         if (!focus_traversable) {
254           focus_traversable =
255               original_starting_view->GetWidget()->GetFocusTraversable();
256           starting_view = original_starting_view;
257         }
258       } else {
259         // When you are going back, starting view's FocusTraversable
260         // should not be used.
261         focus_traversable =
262             original_starting_view->GetWidget()->GetFocusTraversable();
263         starting_view = original_starting_view;
264       }
265     }
266   } else {
267     Widget* widget = starting_widget ? starting_widget : widget_;
268     focus_traversable = widget->GetFocusTraversable();
269   }
270
271   // Traverse the FocusTraversable tree down to find the focusable view.
272   View* v = FindFocusableView(focus_traversable, starting_view, reverse);
273   if (v) {
274     return v;
275   } else {
276     // Let's go up in the FocusTraversable tree.
277     FocusTraversable* parent_focus_traversable =
278         focus_traversable->GetFocusTraversableParent();
279     starting_view = focus_traversable->GetFocusTraversableParentView();
280     while (parent_focus_traversable) {
281       FocusTraversable* new_focus_traversable = NULL;
282       View* new_starting_view = NULL;
283       // When we are going backward, the parent view might gain the next focus.
284       bool check_starting_view = reverse;
285       v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
286           starting_view, reverse, FocusSearch::UP,
287           check_starting_view, &new_focus_traversable, &new_starting_view);
288
289       if (new_focus_traversable) {
290         DCHECK(!v);
291
292         // There is a FocusTraversable, traverse it down.
293         v = FindFocusableView(new_focus_traversable, NULL, reverse);
294       }
295
296       if (v)
297         return v;
298
299       starting_view = focus_traversable->GetFocusTraversableParentView();
300       parent_focus_traversable =
301           parent_focus_traversable->GetFocusTraversableParent();
302     }
303
304     // If we get here, we have reached the end of the focus hierarchy, let's
305     // loop. Make sure there was at least a view to start with, to prevent
306     // infinitely looping in empty windows.
307     if (!dont_loop && original_starting_view) {
308       // Easy, just clear the selection and press tab again.
309       // By calling with NULL as the starting view, we'll start from either
310       // the starting views widget or |widget_|.
311       Widget* widget = original_starting_view->GetWidget();
312       if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
313         widget = widget_;
314       return GetNextFocusableView(NULL, widget, reverse, true);
315     }
316   }
317   return NULL;
318 }
319
320 void FocusManager::SetFocusedViewWithReason(
321     View* view, FocusChangeReason reason) {
322   if (focused_view_ == view)
323     return;
324
325   base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
326   // Update the reason for the focus change (since this is checked by
327   // some listeners), then notify all listeners.
328   focus_change_reason_ = reason;
329   FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
330                     OnWillChangeFocus(focused_view_, view));
331
332   View* old_focused_view = focused_view_;
333   focused_view_ = view;
334   if (old_focused_view)
335     old_focused_view->Blur();
336   // Also make |focused_view_| the stored focus view. This way the stored focus
337   // view is remembered if focus changes are requested prior to a show or while
338   // hidden.
339   SetStoredFocusView(focused_view_);
340   if (focused_view_)
341     focused_view_->Focus();
342
343   FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
344                     OnDidChangeFocus(old_focused_view, focused_view_));
345 }
346
347 void FocusManager::ClearFocus() {
348   // SetFocusedView(NULL) is going to clear out the stored view to. We need to
349   // persist it in this case.
350   views::View* focused_view = GetStoredFocusView();
351   SetFocusedView(NULL);
352   ClearNativeFocus();
353   SetStoredFocusView(focused_view);
354 }
355
356 void FocusManager::StoreFocusedView(bool clear_native_focus) {
357   View* focused_view = focused_view_;
358   // Don't do anything if no focused view. Storing the view (which is NULL), in
359   // this case, would clobber the view that was previously saved.
360   if (!focused_view_)
361     return;
362
363   View* v = focused_view_;
364
365   if (clear_native_focus) {
366     // Temporarily disable notification.  ClearFocus() will set the focus to the
367     // main browser window.  This extra focus bounce which happens during
368     // deactivation can confuse registered WidgetFocusListeners, as the focus
369     // is not changing due to a user-initiated event.
370     AutoNativeNotificationDisabler local_notification_disabler;
371     // ClearFocus() also stores the focused view.
372     ClearFocus();
373   } else {
374     SetFocusedView(NULL);
375     SetStoredFocusView(focused_view);
376   }
377
378   if (v)
379     v->SchedulePaint();  // Remove focus border.
380 }
381
382 bool FocusManager::RestoreFocusedView() {
383   View* view = GetStoredFocusView();
384   if (view) {
385     if (ContainsView(view)) {
386       if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
387         // RequestFocus would fail, but we want to restore focus to controls
388         // that had focus in accessibility mode.
389         SetFocusedViewWithReason(view, kReasonFocusRestore);
390       } else {
391         // This usually just sets the focus if this view is focusable, but
392         // let the view override RequestFocus if necessary.
393         view->RequestFocus();
394
395         // If it succeeded, the reason would be incorrect; set it to
396         // focus restore.
397         if (focused_view_ == view)
398           focus_change_reason_ = kReasonFocusRestore;
399       }
400     }
401     return true;
402   }
403   return false;
404 }
405
406 void FocusManager::SetStoredFocusView(View* focus_view) {
407   ViewStorage* view_storage = ViewStorage::GetInstance();
408   if (!view_storage) {
409     // This should never happen but bug 981648 seems to indicate it could.
410     NOTREACHED();
411     return;
412   }
413
414   // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
415   // is stored twice causing an assert. We should find a better alternative than
416   // removing the view from the storage explicitly.
417   view_storage->RemoveView(stored_focused_view_storage_id_);
418
419   if (!focus_view)
420     return;
421
422   view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
423 }
424
425 View* FocusManager::GetStoredFocusView() {
426   ViewStorage* view_storage = ViewStorage::GetInstance();
427   if (!view_storage) {
428     // This should never happen but bug 981648 seems to indicate it could.
429     NOTREACHED();
430     return NULL;
431   }
432
433   return view_storage->RetrieveView(stored_focused_view_storage_id_);
434 }
435
436 void FocusManager::ClearStoredFocusedView() {
437   SetStoredFocusView(NULL);
438 }
439
440 // Find the next (previous if reverse is true) focusable view for the specified
441 // FocusTraversable, starting at the specified view, traversing down the
442 // FocusTraversable hierarchy.
443 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
444                                       View* starting_view,
445                                       bool reverse) {
446   FocusTraversable* new_focus_traversable = NULL;
447   View* new_starting_view = NULL;
448   View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
449       starting_view,
450       reverse,
451       FocusSearch::DOWN,
452       false,
453       &new_focus_traversable,
454       &new_starting_view);
455
456   // Let's go down the FocusTraversable tree as much as we can.
457   while (new_focus_traversable) {
458     DCHECK(!v);
459     focus_traversable = new_focus_traversable;
460     new_focus_traversable = NULL;
461     starting_view = NULL;
462     v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
463         starting_view,
464         reverse,
465         FocusSearch::DOWN,
466         false,
467         &new_focus_traversable,
468         &new_starting_view);
469   }
470   return v;
471 }
472
473 void FocusManager::RegisterAccelerator(
474     const ui::Accelerator& accelerator,
475     ui::AcceleratorManager::HandlerPriority priority,
476     ui::AcceleratorTarget* target) {
477   accelerator_manager_->Register(accelerator, priority, target);
478 }
479
480 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
481                                          ui::AcceleratorTarget* target) {
482   accelerator_manager_->Unregister(accelerator, target);
483 }
484
485 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
486   accelerator_manager_->UnregisterAll(target);
487 }
488
489 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
490   if (accelerator_manager_->Process(accelerator))
491     return true;
492   if (delegate_.get())
493     return delegate_->ProcessAccelerator(accelerator);
494   return false;
495 }
496
497 ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
498     const ui::Accelerator& accelerator) const {
499   ui::AcceleratorTarget* target =
500       accelerator_manager_->GetCurrentTarget(accelerator);
501   if (!target && delegate_.get())
502     target = delegate_->GetCurrentTargetForAccelerator(accelerator);
503   return target;
504 }
505
506 bool FocusManager::HasPriorityHandler(
507     const ui::Accelerator& accelerator) const {
508   return accelerator_manager_->HasPriorityHandler(accelerator);
509 }
510
511 // static
512 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
513   return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
514 }
515
516 void FocusManager::ViewRemoved(View* removed) {
517   // If the view being removed contains (or is) the focused view,
518   // clear the focus.  However, it's not safe to call ClearFocus()
519   // (and in turn ClearNativeFocus()) here because ViewRemoved() can
520   // be called while the top level widget is being destroyed.
521   if (focused_view_ && removed->Contains(focused_view_))
522     SetFocusedView(NULL);
523 }
524
525 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
526   focus_change_listeners_.AddObserver(listener);
527 }
528
529 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
530   focus_change_listeners_.RemoveObserver(listener);
531 }
532
533 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
534   if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
535     return false;
536
537   const int key_code = event.key_code();
538   if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
539     AdvanceFocus(true);
540     return true;
541   }
542   if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
543     AdvanceFocus(false);
544     return true;
545   }
546
547   return false;
548 }
549
550 }  // namespace views