| OLD | NEW |
| (Empty) |
| 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 virtual 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 virtual 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 | |
| OLD | NEW |