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