Blink roll 174234:174238
[chromium-blink-merge.git] / ui / views / accessible_pane_view.cc
bloba0bbd5665fc65c77e0523cc63d8577d5b4bf5ade
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.
5 #include "ui/views/accessible_pane_view.h"
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"
13 namespace views {
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) {}
26 protected:
27 virtual View* GetParent(View* v) OVERRIDE {
28 return accessible_pane_view_->ContainsForFocusSearch(root(), v) ?
29 accessible_pane_view_->GetParentForFocusSearch(v) : NULL;
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 virtual bool Contains(View* root, const View* v) OVERRIDE {
35 return accessible_pane_view_->ContainsForFocusSearch(root, v);
38 private:
39 AccessiblePaneView* accessible_pane_view_;
40 DISALLOW_COPY_AND_ASSIGN(AccessiblePaneViewFocusSearch);
43 AccessiblePaneView::AccessiblePaneView()
44 : pane_has_focus_(false),
45 allow_deactivate_on_esc_(false),
46 method_factory_(this),
47 focus_manager_(NULL),
48 home_key_(ui::VKEY_HOME, ui::EF_NONE),
49 end_key_(ui::VKEY_END, ui::EF_NONE),
50 escape_key_(ui::VKEY_ESCAPE, ui::EF_NONE),
51 left_key_(ui::VKEY_LEFT, ui::EF_NONE),
52 right_key_(ui::VKEY_RIGHT, ui::EF_NONE) {
53 focus_search_.reset(new AccessiblePaneViewFocusSearch(this));
54 last_focused_view_storage_id_ = ViewStorage::GetInstance()->CreateStorageID();
57 AccessiblePaneView::~AccessiblePaneView() {
58 if (pane_has_focus_) {
59 focus_manager_->RemoveFocusChangeListener(this);
63 bool AccessiblePaneView::SetPaneFocus(views::View* initial_focus) {
64 if (!visible())
65 return false;
67 if (!focus_manager_)
68 focus_manager_ = GetFocusManager();
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);
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();
86 // Return false if there are no focusable children.
87 if (!initial_focus)
88 return false;
90 focus_manager_->SetFocusedView(initial_focus);
92 // If we already have pane focus, we're done.
93 if (pane_has_focus_)
94 return true;
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);
107 return true;
110 bool AccessiblePaneView::SetPaneFocusAndFocusDefault() {
111 return SetPaneFocus(GetDefaultFocusableChild());
114 views::View* AccessiblePaneView::GetDefaultFocusableChild() {
115 return NULL;
118 View* AccessiblePaneView::GetParentForFocusSearch(View* v) {
119 return v->parent();
122 bool AccessiblePaneView::ContainsForFocusSearch(View* root, const View* v) {
123 return root->Contains(v);
126 void AccessiblePaneView::RemovePaneFocus() {
127 focus_manager_->RemoveFocusChangeListener(this);
128 pane_has_focus_ = false;
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);
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);
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);
153 ////////////////////////////////////////////////////////////////////////////////
154 // View overrides:
156 views::FocusTraversable* AccessiblePaneView::GetPaneFocusTraversable() {
157 if (pane_has_focus_)
158 return this;
159 else
160 return NULL;
163 bool AccessiblePaneView::AcceleratorPressed(
164 const ui::Accelerator& accelerator) {
166 views::View* focused_view = focus_manager_->GetFocusedView();
167 if (!ContainsForFocusSearch(this, focused_view))
168 return false;
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();
181 return true;
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;
202 void AccessiblePaneView::SetVisible(bool flag) {
203 if (visible() && !flag && pane_has_focus_) {
204 RemovePaneFocus();
205 focus_manager_->RestoreFocusedView();
207 View::SetVisible(flag);
210 void AccessiblePaneView::GetAccessibleState(ui::AXViewState* state) {
211 state->role = ui::AX_ROLE_PANE;
214 void AccessiblePaneView::RequestFocus() {
215 SetPaneFocusAndFocusDefault();
218 ////////////////////////////////////////////////////////////////////////////////
219 // FocusChangeListener overrides:
221 void AccessiblePaneView::OnWillChangeFocus(views::View* focused_before,
222 views::View* focused_now) {
223 // Act when focus has changed.
226 void AccessiblePaneView::OnDidChangeFocus(views::View* focused_before,
227 views::View* focused_now) {
228 if (!focused_now)
229 return;
231 views::FocusManager::FocusChangeReason reason =
232 focus_manager_->focus_change_reason();
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();
244 ////////////////////////////////////////////////////////////////////////////////
245 // FocusTraversable overrides:
247 views::FocusSearch* AccessiblePaneView::GetFocusSearch() {
248 DCHECK(pane_has_focus_);
249 return focus_search_.get();
252 views::FocusTraversable* AccessiblePaneView::GetFocusTraversableParent() {
253 DCHECK(pane_has_focus_);
254 return NULL;
257 views::View* AccessiblePaneView::GetFocusTraversableParentView() {
258 DCHECK(pane_has_focus_);
259 return NULL;
262 } // namespace views