OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/views/accessibility_event_router_views.h" | 5 #include "chrome/browser/views/accessibility_event_router_views.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
11 #include "chrome/browser/extensions/extension_accessibility_api.h" | 11 #include "chrome/browser/extensions/extension_accessibility_api.h" |
12 #include "chrome/browser/profile.h" | 12 #include "chrome/browser/profile.h" |
13 #include "chrome/common/notification_type.h" | 13 #include "chrome/common/notification_type.h" |
| 14 #include "views/accessibility/accessibility_types.h" |
14 #include "views/controls/button/image_button.h" | 15 #include "views/controls/button/image_button.h" |
15 #include "views/controls/button/menu_button.h" | 16 #include "views/controls/button/menu_button.h" |
16 #include "views/controls/button/native_button.h" | 17 #include "views/controls/button/native_button.h" |
17 #include "views/controls/link.h" | 18 #include "views/controls/link.h" |
| 19 #include "views/controls/menu/menu_item_view.h" |
| 20 #include "views/controls/menu/submenu_view.h" |
18 | 21 |
19 using views::FocusManager; | 22 using views::FocusManager; |
20 using views::View; | 23 using views::View; |
21 | 24 |
22 AccessibilityEventRouterViews::AccessibilityEventRouterViews() | 25 AccessibilityEventRouterViews::AccessibilityEventRouterViews() |
23 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 26 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
24 } | 27 } |
25 | 28 |
26 AccessibilityEventRouterViews::~AccessibilityEventRouterViews() { | 29 AccessibilityEventRouterViews::~AccessibilityEventRouterViews() { |
27 } | 30 } |
28 | 31 |
29 // static | 32 // static |
30 AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() { | 33 AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() { |
31 return Singleton<AccessibilityEventRouterViews>::get(); | 34 return Singleton<AccessibilityEventRouterViews>::get(); |
32 } | 35 } |
33 | 36 |
34 bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) { | 37 bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) { |
35 if (view_tree_profile_map_[view] != NULL) | 38 if (view_tree_profile_map_[view] != NULL) |
36 return false; | 39 return false; |
37 | 40 |
38 view_tree_profile_map_[view] = profile; | 41 view_tree_profile_map_[view] = profile; |
39 FocusManager* focus_manager = view->GetFocusManager(); | |
40 | |
41 // Add this object as a listener for this focus manager, but use a ref | |
42 // count to ensure we only call AddFocusChangeListener on any given | |
43 // focus manager once. Note that hash_map<FocusManager*, int>::operator[] | |
44 // will initialize the ref count to zero if it's not already in the map. | |
45 if (focus_manager_ref_count_[focus_manager] == 0) { | |
46 focus_manager->AddFocusChangeListener(this); | |
47 } | |
48 focus_manager_ref_count_[focus_manager]++; | |
49 | |
50 view_info_map_[view].focus_manager = focus_manager; | |
51 return true; | 42 return true; |
52 } | 43 } |
53 | 44 |
54 void AccessibilityEventRouterViews::RemoveViewTree(View* view) { | 45 void AccessibilityEventRouterViews::RemoveViewTree(View* view) { |
55 DCHECK(view_tree_profile_map_.find(view) != | 46 DCHECK(view_tree_profile_map_.find(view) != |
56 view_tree_profile_map_.end()); | 47 view_tree_profile_map_.end()); |
57 view_tree_profile_map_.erase(view); | 48 view_tree_profile_map_.erase(view); |
58 | |
59 // Decrement the ref count of the focus manager, and remove this object | |
60 // as a listener if the count reaches zero. | |
61 FocusManager* focus_manager = view_info_map_[view].focus_manager; | |
62 DCHECK(focus_manager); | |
63 focus_manager_ref_count_[focus_manager]--; | |
64 if (focus_manager_ref_count_[focus_manager] == 0) { | |
65 focus_manager->RemoveFocusChangeListener(this); | |
66 } | |
67 } | 49 } |
68 | 50 |
69 void AccessibilityEventRouterViews::IgnoreView(View* view) { | 51 void AccessibilityEventRouterViews::IgnoreView(View* view) { |
70 view_info_map_[view].ignore = true; | 52 view_info_map_[view].ignore = true; |
71 } | 53 } |
72 | 54 |
73 void AccessibilityEventRouterViews::SetViewName(View* view, std::string name) { | 55 void AccessibilityEventRouterViews::SetViewName(View* view, std::string name) { |
74 view_info_map_[view].name = name; | 56 view_info_map_[view].name = name; |
75 } | 57 } |
76 | 58 |
77 void AccessibilityEventRouterViews::RemoveView(View* view) { | 59 void AccessibilityEventRouterViews::RemoveView(View* view) { |
78 DCHECK(view_info_map_.find(view) != view_info_map_.end()); | 60 DCHECK(view_info_map_.find(view) != view_info_map_.end()); |
79 view_info_map_.erase(view); | 61 view_info_map_.erase(view); |
80 } | 62 } |
81 | 63 |
82 // | 64 void AccessibilityEventRouterViews::HandleAccessibilityEvent( |
83 // views::FocusChangeListener | 65 views::View* view, AccessibilityTypes::Event event_type) { |
84 // | 66 switch (event_type) { |
85 | 67 case AccessibilityTypes::EVENT_FOCUS: |
86 void AccessibilityEventRouterViews::FocusWillChange( | 68 DispatchAccessibilityNotification( |
87 View* focused_before, View* focused_now) { | 69 view, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); |
88 if (focused_now) { | 70 break; |
89 DispatchAccessibilityNotification( | 71 case AccessibilityTypes::EVENT_MENUSTART: |
90 focused_now, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); | 72 case AccessibilityTypes::EVENT_MENUPOPUPSTART: |
| 73 DispatchAccessibilityNotification( |
| 74 view, NotificationType::ACCESSIBILITY_MENU_OPENED); |
| 75 break; |
| 76 case AccessibilityTypes::EVENT_MENUEND: |
| 77 case AccessibilityTypes::EVENT_MENUPOPUPEND: |
| 78 DispatchAccessibilityNotification( |
| 79 view, NotificationType::ACCESSIBILITY_MENU_CLOSED); |
| 80 break; |
91 } | 81 } |
92 } | 82 } |
93 | 83 |
94 // | 84 // |
95 // Private methods | 85 // Private methods |
96 // | 86 // |
97 | 87 |
98 void AccessibilityEventRouterViews::FindView( | 88 void AccessibilityEventRouterViews::FindView( |
99 View* view, Profile** profile, bool* is_accessible) { | 89 View* view, Profile** profile, bool* is_accessible) { |
100 *is_accessible = false; | 90 *is_accessible = false; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 } | 128 } |
139 | 129 |
140 return name; | 130 return name; |
141 } | 131 } |
142 | 132 |
143 void AccessibilityEventRouterViews::DispatchAccessibilityNotification( | 133 void AccessibilityEventRouterViews::DispatchAccessibilityNotification( |
144 View* view, NotificationType type) { | 134 View* view, NotificationType type) { |
145 Profile* profile = NULL; | 135 Profile* profile = NULL; |
146 bool is_accessible; | 136 bool is_accessible; |
147 FindView(view, &profile, &is_accessible); | 137 FindView(view, &profile, &is_accessible); |
| 138 |
| 139 // Special case: a menu isn't associated with any particular top-level |
| 140 // window, so menu events get routed to the profile of the most recent |
| 141 // event that was associated with a window, which should be the window |
| 142 // that triggered opening the menu. |
| 143 bool is_menu_event = IsMenuEvent(view, type); |
| 144 if (is_menu_event && !profile && most_recent_profile_) { |
| 145 profile = most_recent_profile_; |
| 146 is_accessible = true; |
| 147 } |
| 148 |
148 if (!is_accessible) | 149 if (!is_accessible) |
149 return; | 150 return; |
150 | 151 |
151 if (view->GetClassName() == views::ImageButton::kViewClassName) { | 152 most_recent_profile_ = profile; |
| 153 |
| 154 AccessibilityTypes::Role role; |
| 155 view->GetAccessibleRole(&role); |
| 156 std::string class_name = view->GetClassName(); |
| 157 |
| 158 if (class_name == views::MenuButton::kViewClassName || |
| 159 type == NotificationType::ACCESSIBILITY_MENU_OPENED || |
| 160 type == NotificationType::ACCESSIBILITY_MENU_CLOSED) { |
| 161 SendMenuNotification(view, type, profile); |
| 162 } else if (is_menu_event) { |
| 163 SendMenuItemNotification(view, type, profile); |
| 164 } else if (class_name == views::ImageButton::kViewClassName || |
| 165 class_name == views::NativeButton::kViewClassName || |
| 166 class_name == views::TextButton::kViewClassName) { |
152 SendButtonNotification(view, type, profile); | 167 SendButtonNotification(view, type, profile); |
153 } else if (view->GetClassName() == views::NativeButton::kViewClassName) { | 168 } else if (class_name == views::Link::kViewClassName) { |
154 SendButtonNotification(view, type, profile); | |
155 } else if (view->GetClassName() == views::Link::kViewClassName) { | |
156 SendLinkNotification(view, type, profile); | 169 SendLinkNotification(view, type, profile); |
157 } else if (view->GetClassName() == views::MenuButton::kViewClassName) { | |
158 SendMenuNotification(view, type, profile); | |
159 } | 170 } |
160 } | 171 } |
161 | 172 |
162 void AccessibilityEventRouterViews::SendButtonNotification( | 173 void AccessibilityEventRouterViews::SendButtonNotification( |
163 View* view, NotificationType type, Profile* profile) { | 174 View* view, NotificationType type, Profile* profile) { |
164 AccessibilityButtonInfo info(profile, GetViewName(view)); | 175 AccessibilityButtonInfo info(profile, GetViewName(view)); |
165 SendAccessibilityNotification(type, &info); | 176 SendAccessibilityNotification(type, &info); |
166 } | 177 } |
167 | 178 |
168 void AccessibilityEventRouterViews::SendLinkNotification( | 179 void AccessibilityEventRouterViews::SendLinkNotification( |
169 View* view, NotificationType type, Profile* profile) { | 180 View* view, NotificationType type, Profile* profile) { |
170 AccessibilityLinkInfo info(profile, GetViewName(view)); | 181 AccessibilityLinkInfo info(profile, GetViewName(view)); |
171 SendAccessibilityNotification(type, &info); | 182 SendAccessibilityNotification(type, &info); |
172 } | 183 } |
173 | 184 |
174 void AccessibilityEventRouterViews::SendMenuNotification( | 185 void AccessibilityEventRouterViews::SendMenuNotification( |
175 View* view, NotificationType type, Profile* profile) { | 186 View* view, NotificationType type, Profile* profile) { |
176 AccessibilityMenuInfo info(profile, GetViewName(view)); | 187 AccessibilityMenuInfo info(profile, GetViewName(view)); |
177 SendAccessibilityNotification(type, &info); | 188 SendAccessibilityNotification(type, &info); |
178 } | 189 } |
| 190 |
| 191 void AccessibilityEventRouterViews::SendMenuItemNotification( |
| 192 View* view, NotificationType type, Profile* profile) { |
| 193 std::string name = GetViewName(view); |
| 194 |
| 195 bool has_submenu = false; |
| 196 int index = -1; |
| 197 int count = -1; |
| 198 |
| 199 if (view->GetClassName() == views::MenuItemView::kViewClassName) |
| 200 has_submenu = static_cast<views::MenuItemView*>(view)->HasSubmenu(); |
| 201 |
| 202 View* parent_menu = view->GetParent(); |
| 203 while (parent_menu != NULL && parent_menu->GetClassName() != |
| 204 views::SubmenuView::kViewClassName) { |
| 205 parent_menu = parent_menu->GetParent(); |
| 206 } |
| 207 if (parent_menu) { |
| 208 count = 0; |
| 209 RecursiveGetMenuItemIndexAndCount(parent_menu, view, &index, &count); |
| 210 } |
| 211 |
| 212 AccessibilityMenuItemInfo info(profile, name, has_submenu, index, count); |
| 213 SendAccessibilityNotification(type, &info); |
| 214 } |
| 215 |
| 216 void AccessibilityEventRouterViews::RecursiveGetMenuItemIndexAndCount( |
| 217 views::View* menu, views::View* item, int* index, int* count) { |
| 218 for (int i = 0; i < menu->GetChildViewCount(); ++i) { |
| 219 views::View* child = menu->GetChildViewAt(i); |
| 220 int previous_count = *count; |
| 221 RecursiveGetMenuItemIndexAndCount(child, item, index, count); |
| 222 if (child->GetClassName() == views::MenuItemView::kViewClassName && |
| 223 *count == previous_count) { |
| 224 if (item == child) |
| 225 *index = *count; |
| 226 (*count)++; |
| 227 } else if (child->GetClassName() == views::TextButton::kViewClassName) { |
| 228 if (item == child) |
| 229 *index = *count; |
| 230 (*count)++; |
| 231 } |
| 232 } |
| 233 } |
| 234 |
| 235 bool AccessibilityEventRouterViews::IsMenuEvent( |
| 236 View* view, NotificationType type) { |
| 237 if (type == NotificationType::ACCESSIBILITY_MENU_OPENED || |
| 238 type == NotificationType::ACCESSIBILITY_MENU_CLOSED) |
| 239 return true; |
| 240 |
| 241 while (view) { |
| 242 AccessibilityTypes::Role role; |
| 243 view->GetAccessibleRole(&role); |
| 244 if (role == AccessibilityTypes::ROLE_MENUITEM || |
| 245 role == AccessibilityTypes::ROLE_MENUPOPUP) { |
| 246 return true; |
| 247 } |
| 248 view = view->GetParent(); |
| 249 } |
| 250 |
| 251 return false; |
| 252 } |
OLD | NEW |