Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / views / accessible_pane_view.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/accessible_pane_view.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "ui/accessibility/ax_view_state.h"
9 #include "ui/views/focus/focus_search.h"
10 #include "ui/views/focus/view_storage.h"
11 #include "ui/views/widget/widget.h"
12
13 namespace views {
14
15 // Create tiny subclass of FocusSearch that overrides GetParent and Contains,
16 // delegating these to methods in AccessiblePaneView. This is needed so that
17 // subclasses of AccessiblePaneView can customize the focus search logic and
18 // include views that aren't part of the AccessiblePaneView's view
19 // hierarchy in the focus order.
20 class AccessiblePaneViewFocusSearch : public FocusSearch {
21  public:
22   explicit AccessiblePaneViewFocusSearch(AccessiblePaneView* pane_view)
23       : FocusSearch(pane_view, true, true),
24         accessible_pane_view_(pane_view) {}
25
26  protected:
27   View* GetParent(View* v) override {
28     return accessible_pane_view_->ContainsForFocusSearch(root(), v) ?
29         accessible_pane_view_->GetParentForFocusSearch(v) : NULL;
30   }
31
32   // Returns true if |v| is contained within the hierarchy rooted at |root|.
33   // Subclasses can override this if they need custom focus search behavior.
34   bool Contains(View* root, const View* v) override {
35     return accessible_pane_view_->ContainsForFocusSearch(root, v);
36   }
37
38  private:
39   AccessiblePaneView* accessible_pane_view_;
40   DISALLOW_COPY_AND_ASSIGN(AccessiblePaneViewFocusSearch);
41 };
42
43 AccessiblePaneView::AccessiblePaneView()
44     : pane_has_focus_(false),
45       allow_deactivate_on_esc_(false),
46       focus_manager_(NULL),
47       home_key_(ui::VKEY_HOME, ui::EF_NONE),
48       end_key_(ui::VKEY_END, ui::EF_NONE),
49       escape_key_(ui::VKEY_ESCAPE, ui::EF_NONE),
50       left_key_(ui::VKEY_LEFT, ui::EF_NONE),
51       right_key_(ui::VKEY_RIGHT, ui::EF_NONE),
52       method_factory_(this) {
53   focus_search_.reset(new AccessiblePaneViewFocusSearch(this));
54   last_focused_view_storage_id_ = ViewStorage::GetInstance()->CreateStorageID();
55 }
56
57 AccessiblePaneView::~AccessiblePaneView() {
58   if (pane_has_focus_) {
59     focus_manager_->RemoveFocusChangeListener(this);
60   }
61 }
62
63 bool AccessiblePaneView::SetPaneFocus(views::View* initial_focus) {
64   if (!visible())
65     return false;
66
67   if (!focus_manager_)
68     focus_manager_ = GetFocusManager();
69
70   View* focused_view = focus_manager_->GetFocusedView();
71   if (focused_view && !ContainsForFocusSearch(this, focused_view)) {
72     ViewStorage* view_storage = ViewStorage::GetInstance();
73     view_storage->RemoveView(last_focused_view_storage_id_);
74     view_storage->StoreView(last_focused_view_storage_id_, focused_view);
75   }
76
77   // Use the provided initial focus if it's visible and enabled, otherwise
78   // use the first focusable child.
79   if (!initial_focus ||
80       !ContainsForFocusSearch(this, initial_focus) ||
81       !initial_focus->visible() ||
82       !initial_focus->enabled()) {
83     initial_focus = GetFirstFocusableChild();
84   }
85
86   // Return false if there are no focusable children.
87   if (!initial_focus)
88     return false;
89
90   focus_manager_->SetFocusedView(initial_focus);
91
92   // If we already have pane focus, we're done.
93   if (pane_has_focus_)
94     return true;
95
96   // Otherwise, set accelerators and start listening for focus change events.
97   pane_has_focus_ = true;
98   ui::AcceleratorManager::HandlerPriority normal =
99       ui::AcceleratorManager::kNormalPriority;
100   focus_manager_->RegisterAccelerator(home_key_, normal, this);
101   focus_manager_->RegisterAccelerator(end_key_, normal, this);
102   focus_manager_->RegisterAccelerator(escape_key_, normal, this);
103   focus_manager_->RegisterAccelerator(left_key_, normal, this);
104   focus_manager_->RegisterAccelerator(right_key_, normal, this);
105   focus_manager_->AddFocusChangeListener(this);
106
107   return true;
108 }
109
110 bool AccessiblePaneView::SetPaneFocusAndFocusDefault() {
111   return SetPaneFocus(GetDefaultFocusableChild());
112 }
113
114 views::View* AccessiblePaneView::GetDefaultFocusableChild() {
115   return NULL;
116 }
117
118 View* AccessiblePaneView::GetParentForFocusSearch(View* v) {
119   return v->parent();
120 }
121
122 bool AccessiblePaneView::ContainsForFocusSearch(View* root, const View* v) {
123   return root->Contains(v);
124 }
125
126 void AccessiblePaneView::RemovePaneFocus() {
127   focus_manager_->RemoveFocusChangeListener(this);
128   pane_has_focus_ = false;
129
130   focus_manager_->UnregisterAccelerator(home_key_, this);
131   focus_manager_->UnregisterAccelerator(end_key_, this);
132   focus_manager_->UnregisterAccelerator(escape_key_, this);
133   focus_manager_->UnregisterAccelerator(left_key_, this);
134   focus_manager_->UnregisterAccelerator(right_key_, this);
135 }
136
137 views::View* AccessiblePaneView::GetFirstFocusableChild() {
138   FocusTraversable* dummy_focus_traversable;
139   views::View* dummy_focus_traversable_view;
140   return focus_search_->FindNextFocusableView(
141       NULL, false, views::FocusSearch::DOWN, false,
142       &dummy_focus_traversable, &dummy_focus_traversable_view);
143 }
144
145 views::View* AccessiblePaneView::GetLastFocusableChild() {
146   FocusTraversable* dummy_focus_traversable;
147   views::View* dummy_focus_traversable_view;
148   return focus_search_->FindNextFocusableView(
149       this, true, views::FocusSearch::DOWN, false,
150       &dummy_focus_traversable, &dummy_focus_traversable_view);
151 }
152
153 ////////////////////////////////////////////////////////////////////////////////
154 // View overrides:
155
156 views::FocusTraversable* AccessiblePaneView::GetPaneFocusTraversable() {
157   if (pane_has_focus_)
158     return this;
159   else
160     return NULL;
161 }
162
163 bool AccessiblePaneView::AcceleratorPressed(
164     const ui::Accelerator& accelerator) {
165
166   views::View* focused_view = focus_manager_->GetFocusedView();
167   if (!ContainsForFocusSearch(this, focused_view))
168     return false;
169
170   switch (accelerator.key_code()) {
171     case ui::VKEY_ESCAPE: {
172       RemovePaneFocus();
173       View* last_focused_view = ViewStorage::GetInstance()->RetrieveView(
174           last_focused_view_storage_id_);
175       if (last_focused_view) {
176         focus_manager_->SetFocusedViewWithReason(
177             last_focused_view, FocusManager::kReasonFocusRestore);
178       } else if (allow_deactivate_on_esc_) {
179         focused_view->GetWidget()->Deactivate();
180       }
181       return true;
182     }
183     case ui::VKEY_LEFT:
184       focus_manager_->AdvanceFocus(true);
185       return true;
186     case ui::VKEY_RIGHT:
187       focus_manager_->AdvanceFocus(false);
188       return true;
189     case ui::VKEY_HOME:
190       focus_manager_->SetFocusedViewWithReason(
191           GetFirstFocusableChild(), views::FocusManager::kReasonFocusTraversal);
192       return true;
193     case ui::VKEY_END:
194       focus_manager_->SetFocusedViewWithReason(
195           GetLastFocusableChild(), views::FocusManager::kReasonFocusTraversal);
196       return true;
197     default:
198       return false;
199   }
200 }
201
202 void AccessiblePaneView::SetVisible(bool flag) {
203   if (visible() && !flag && pane_has_focus_) {
204     RemovePaneFocus();
205     focus_manager_->RestoreFocusedView();
206   }
207   View::SetVisible(flag);
208 }
209
210 void AccessiblePaneView::GetAccessibleState(ui::AXViewState* state) {
211   state->role = ui::AX_ROLE_PANE;
212 }
213
214 void AccessiblePaneView::RequestFocus() {
215   SetPaneFocusAndFocusDefault();
216 }
217
218 ////////////////////////////////////////////////////////////////////////////////
219 // FocusChangeListener overrides:
220
221 void AccessiblePaneView::OnWillChangeFocus(views::View* focused_before,
222                                            views::View* focused_now) {
223   //  Act when focus has changed.
224 }
225
226 void AccessiblePaneView::OnDidChangeFocus(views::View* focused_before,
227                                           views::View* focused_now) {
228   if (!focused_now)
229     return;
230
231   views::FocusManager::FocusChangeReason reason =
232       focus_manager_->focus_change_reason();
233
234   if (!ContainsForFocusSearch(this, focused_now) ||
235       reason == views::FocusManager::kReasonDirectFocusChange) {
236     // We should remove pane focus (i.e. make most of the controls
237     // not focusable again) because the focus has left the pane,
238     // or because the focus changed within the pane due to the user
239     // directly focusing to a specific view (e.g., clicking on it).
240     RemovePaneFocus();
241   }
242 }
243
244 ////////////////////////////////////////////////////////////////////////////////
245 // FocusTraversable overrides:
246
247 views::FocusSearch* AccessiblePaneView::GetFocusSearch() {
248   DCHECK(pane_has_focus_);
249   return focus_search_.get();
250 }
251
252 views::FocusTraversable* AccessiblePaneView::GetFocusTraversableParent() {
253   DCHECK(pane_has_focus_);
254   return NULL;
255 }
256
257 views::View* AccessiblePaneView::GetFocusTraversableParentView() {
258   DCHECK(pane_has_focus_);
259   return NULL;
260 }
261
262 }  // namespace views