Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(845)

Side by Side Diff: chrome/browser/ui/views/accessibility_event_router_views.cc

Issue 10458036: browser: Move browser_views_accessibility_browsertest.cc into views/ directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 "chrome/browser/ui/views/accessibility_event_router_views.h"
6
7 #include "base/basictypes.h"
8 #include "base/callback.h"
9 #include "base/memory/singleton.h"
10 #include "base/message_loop.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/accessibility/accessibility_extension_api.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/common/chrome_notification_types.h"
17 #include "ui/base/accessibility/accessible_view_state.h"
18 #include "ui/views/controls/button/text_button.h"
19 #include "ui/views/controls/menu/menu_item_view.h"
20 #include "ui/views/controls/menu/submenu_view.h"
21 #include "ui/views/view.h"
22 #include "ui/views/widget/widget.h"
23
24 using views::FocusManager;
25
26 AccessibilityEventRouterViews::AccessibilityEventRouterViews()
27 : most_recent_profile_(NULL) {
28 }
29
30 AccessibilityEventRouterViews::~AccessibilityEventRouterViews() {
31 }
32
33 // static
34 AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() {
35 return Singleton<AccessibilityEventRouterViews>::get();
36 }
37
38 void AccessibilityEventRouterViews::HandleAccessibilityEvent(
39 views::View* view, ui::AccessibilityTypes::Event event_type) {
40 if (!ExtensionAccessibilityEventRouter::GetInstance()->
41 IsAccessibilityEnabled()) {
42 return;
43 }
44
45 switch (event_type) {
46 case ui::AccessibilityTypes::EVENT_FOCUS:
47 DispatchAccessibilityNotification(
48 view, chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED);
49 break;
50 case ui::AccessibilityTypes::EVENT_MENUSTART:
51 case ui::AccessibilityTypes::EVENT_MENUPOPUPSTART:
52 DispatchAccessibilityNotification(
53 view, chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED);
54 break;
55 case ui::AccessibilityTypes::EVENT_MENUEND:
56 case ui::AccessibilityTypes::EVENT_MENUPOPUPEND:
57 DispatchAccessibilityNotification(
58 view, chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED);
59 break;
60 case ui::AccessibilityTypes::EVENT_TEXT_CHANGED:
61 case ui::AccessibilityTypes::EVENT_SELECTION_CHANGED:
62 DispatchAccessibilityNotification(
63 view, chrome::NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED);
64 break;
65 case ui::AccessibilityTypes::EVENT_VALUE_CHANGED:
66 DispatchAccessibilityNotification(
67 view, chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION);
68 break;
69 case ui::AccessibilityTypes::EVENT_ALERT:
70 DispatchAccessibilityNotification(
71 view, chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED);
72 break;
73 case ui::AccessibilityTypes::EVENT_NAME_CHANGED:
74 NOTIMPLEMENTED();
75 break;
76 }
77 }
78
79 void AccessibilityEventRouterViews::HandleMenuItemFocused(
80 const string16& menu_name,
81 const string16& menu_item_name,
82 int item_index,
83 int item_count,
84 bool has_submenu) {
85 if (!ExtensionAccessibilityEventRouter::GetInstance()->
86 IsAccessibilityEnabled()) {
87 return;
88 }
89
90 if (!most_recent_profile_)
91 return;
92
93 AccessibilityMenuItemInfo info(most_recent_profile_,
94 UTF16ToUTF8(menu_item_name),
95 UTF16ToUTF8(menu_name),
96 has_submenu,
97 item_index,
98 item_count);
99 SendAccessibilityNotification(
100 chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED, &info);
101 }
102
103 //
104 // Private methods
105 //
106
107 void AccessibilityEventRouterViews::DispatchAccessibilityNotification(
108 views::View* view, int type) {
109 // Get the profile associated with this view. If it's not found, use
110 // the most recent profile where accessibility events were sent, or
111 // the default profile.
112 Profile* profile = NULL;
113 views::Widget* widget = view->GetWidget();
114 if (widget) {
115 profile = reinterpret_cast<Profile*>(
116 widget->GetNativeWindowProperty(Profile::kProfileKey));
117 }
118 if (!profile)
119 profile = most_recent_profile_;
120 if (!profile)
121 profile = g_browser_process->profile_manager()->GetLastUsedProfile();
122 if (!profile) {
123 NOTREACHED();
124 return;
125 }
126
127 most_recent_profile_ = profile;
128
129 if (type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED ||
130 type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED) {
131 SendMenuNotification(view, type, profile);
132 return;
133 }
134
135 ui::AccessibleViewState state;
136 view->GetAccessibleState(&state);
137 switch (state.role) {
138 case ui::AccessibilityTypes::ROLE_ALERT:
139 case ui::AccessibilityTypes::ROLE_WINDOW:
140 SendWindowNotification(view, type, profile);
141 break;
142 case ui::AccessibilityTypes::ROLE_BUTTONMENU:
143 case ui::AccessibilityTypes::ROLE_MENUBAR:
144 case ui::AccessibilityTypes::ROLE_MENUPOPUP:
145 SendMenuNotification(view, type, profile);
146 break;
147 case ui::AccessibilityTypes::ROLE_BUTTONDROPDOWN:
148 case ui::AccessibilityTypes::ROLE_PUSHBUTTON:
149 SendButtonNotification(view, type, profile);
150 break;
151 case ui::AccessibilityTypes::ROLE_CHECKBUTTON:
152 SendCheckboxNotification(view, type, profile);
153 break;
154 case ui::AccessibilityTypes::ROLE_COMBOBOX:
155 SendComboboxNotification(view, type, profile);
156 break;
157 case ui::AccessibilityTypes::ROLE_LINK:
158 SendLinkNotification(view, type, profile);
159 break;
160 case ui::AccessibilityTypes::ROLE_LOCATION_BAR:
161 case ui::AccessibilityTypes::ROLE_TEXT:
162 SendTextfieldNotification(view, type, profile);
163 break;
164 case ui::AccessibilityTypes::ROLE_MENUITEM:
165 SendMenuItemNotification(view, type, profile);
166 break;
167 case ui::AccessibilityTypes::ROLE_RADIOBUTTON:
168 // Not used anymore?
169 case ui::AccessibilityTypes::ROLE_SLIDER:
170 SendSliderNotification(view, type, profile);
171 break;
172 default:
173 // If this is encountered, please file a bug with the role that wasn't
174 // caught so we can add accessibility extension API support.
175 NOTREACHED();
176 }
177 }
178
179 // static
180 void AccessibilityEventRouterViews::SendButtonNotification(
181 views::View* view,
182 int type,
183 Profile* profile) {
184 AccessibilityButtonInfo info(
185 profile, GetViewName(view), GetViewContext(view));
186 SendAccessibilityNotification(type, &info);
187 }
188
189 // static
190 void AccessibilityEventRouterViews::SendLinkNotification(
191 views::View* view,
192 int type,
193 Profile* profile) {
194 AccessibilityLinkInfo info(profile, GetViewName(view), GetViewContext(view));
195 SendAccessibilityNotification(type, &info);
196 }
197
198 // static
199 void AccessibilityEventRouterViews::SendMenuNotification(
200 views::View* view,
201 int type,
202 Profile* profile) {
203 AccessibilityMenuInfo info(profile, GetViewName(view));
204 SendAccessibilityNotification(type, &info);
205 }
206
207 // static
208 void AccessibilityEventRouterViews::SendMenuItemNotification(
209 views::View* view,
210 int type,
211 Profile* profile) {
212 std::string name = GetViewName(view);
213 std::string context = GetViewContext(view);
214
215 bool has_submenu = false;
216 int index = -1;
217 int count = -1;
218
219 if (view->GetClassName() == views::MenuItemView::kViewClassName)
220 has_submenu = static_cast<views::MenuItemView*>(view)->HasSubmenu();
221
222 views::View* parent_menu = view->parent();
223 while (parent_menu != NULL && parent_menu->GetClassName() !=
224 views::SubmenuView::kViewClassName) {
225 parent_menu = parent_menu->parent();
226 }
227 if (parent_menu) {
228 count = 0;
229 RecursiveGetMenuItemIndexAndCount(parent_menu, view, &index, &count);
230 }
231
232 AccessibilityMenuItemInfo info(
233 profile, name, context, has_submenu, index, count);
234 SendAccessibilityNotification(type, &info);
235 }
236
237 // static
238 void AccessibilityEventRouterViews::SendTextfieldNotification(
239 views::View* view,
240 int type,
241 Profile* profile) {
242 ui::AccessibleViewState state;
243 view->GetAccessibleState(&state);
244 std::string name = UTF16ToUTF8(state.name);
245 std::string context = GetViewContext(view);
246 bool password =
247 (state.state & ui::AccessibilityTypes::STATE_PROTECTED) != 0;
248 AccessibilityTextBoxInfo info(profile, name, context, password);
249 std::string value = UTF16ToUTF8(state.value);
250 info.SetValue(value, state.selection_start, state.selection_end);
251 SendAccessibilityNotification(type, &info);
252 }
253
254 // static
255 void AccessibilityEventRouterViews::SendComboboxNotification(
256 views::View* view,
257 int type,
258 Profile* profile) {
259 ui::AccessibleViewState state;
260 view->GetAccessibleState(&state);
261 std::string name = UTF16ToUTF8(state.name);
262 std::string value = UTF16ToUTF8(state.value);
263 std::string context = GetViewContext(view);
264 AccessibilityComboBoxInfo info(
265 profile, name, context, value, state.index, state.count);
266 SendAccessibilityNotification(type, &info);
267 }
268
269 // static
270 void AccessibilityEventRouterViews::SendCheckboxNotification(
271 views::View* view,
272 int type,
273 Profile* profile) {
274 ui::AccessibleViewState state;
275 view->GetAccessibleState(&state);
276 std::string name = UTF16ToUTF8(state.name);
277 std::string value = UTF16ToUTF8(state.value);
278 std::string context = GetViewContext(view);
279 AccessibilityCheckboxInfo info(
280 profile,
281 name,
282 context,
283 state.state == ui::AccessibilityTypes::STATE_CHECKED);
284 SendAccessibilityNotification(type, &info);
285 }
286
287 // static
288 void AccessibilityEventRouterViews::SendWindowNotification(
289 views::View* view,
290 int type,
291 Profile* profile) {
292 ui::AccessibleViewState state;
293 view->GetAccessibleState(&state);
294 std::string window_text;
295
296 // If it's an alert, try to get the text from the contents of the
297 // static text, not the window title.
298 if (state.role == ui::AccessibilityTypes::ROLE_ALERT)
299 window_text = RecursiveGetStaticText(view);
300
301 // Otherwise get it from the window's accessible name.
302 if (window_text.empty())
303 window_text = UTF16ToUTF8(state.name);
304
305 AccessibilityWindowInfo info(profile, window_text);
306 SendAccessibilityNotification(type, &info);
307 }
308
309 // static
310 void AccessibilityEventRouterViews::SendSliderNotification(
311 views::View* view,
312 int type,
313 Profile* profile) {
314 ui::AccessibleViewState state;
315 view->GetAccessibleState(&state);
316
317 std::string name = UTF16ToUTF8(state.name);
318 std::string value = UTF16ToUTF8(state.value);
319 std::string context = GetViewContext(view);
320 AccessibilitySliderInfo info(
321 profile,
322 name,
323 context,
324 value);
325 SendAccessibilityNotification(type, &info);
326 }
327
328 // static
329 std::string AccessibilityEventRouterViews::GetViewName(views::View* view) {
330 ui::AccessibleViewState state;
331 view->GetAccessibleState(&state);
332 return UTF16ToUTF8(state.name);
333 }
334
335 // static
336 std::string AccessibilityEventRouterViews::GetViewContext(views::View* view) {
337 for (views::View* parent = view->parent();
338 parent;
339 parent = parent->parent()) {
340 ui::AccessibleViewState state;
341 parent->GetAccessibleState(&state);
342
343 // Two cases are handled right now. More could be added in the future
344 // depending on how the UI evolves.
345
346 // A control in a toolbar should use the toolbar's accessible name
347 // as the context.
348 if (state.role == ui::AccessibilityTypes::ROLE_TOOLBAR &&
349 !state.name.empty()) {
350 return UTF16ToUTF8(state.name);
351 }
352
353 // A control inside of an alert (like an infobar) should grab the
354 // first static text descendant as the context; that's the prompt.
355 if (state.role == ui::AccessibilityTypes::ROLE_ALERT) {
356 views::View* static_text_child = FindDescendantWithAccessibleRole(
357 parent, ui::AccessibilityTypes::ROLE_STATICTEXT);
358 if (static_text_child) {
359 ui::AccessibleViewState state;
360 static_text_child->GetAccessibleState(&state);
361 if (!state.name.empty())
362 return UTF16ToUTF8(state.name);
363 }
364 return std::string();
365 }
366 }
367
368 return std::string();
369 }
370
371 // static
372 views::View* AccessibilityEventRouterViews::FindDescendantWithAccessibleRole(
373 views::View* view, ui::AccessibilityTypes::Role role) {
374 ui::AccessibleViewState state;
375 view->GetAccessibleState(&state);
376 if (state.role == role)
377 return view;
378
379 for (int i = 0; i < view->child_count(); i++) {
380 views::View* child = view->child_at(i);
381 views::View* result = FindDescendantWithAccessibleRole(child, role);
382 if (result)
383 return result;
384 }
385
386 return NULL;
387 }
388
389 // static
390 bool AccessibilityEventRouterViews::IsMenuEvent(
391 views::View* view,
392 int type) {
393 if (type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED ||
394 type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED)
395 return true;
396
397 while (view) {
398 ui::AccessibleViewState state;
399 view->GetAccessibleState(&state);
400 ui::AccessibilityTypes::Role role = state.role;
401 if (role == ui::AccessibilityTypes::ROLE_MENUITEM ||
402 role == ui::AccessibilityTypes::ROLE_MENUPOPUP) {
403 return true;
404 }
405 view = view->parent();
406 }
407
408 return false;
409 }
410
411 // static
412 void AccessibilityEventRouterViews::RecursiveGetMenuItemIndexAndCount(
413 views::View* menu,
414 views::View* item,
415 int* index,
416 int* count) {
417 for (int i = 0; i < menu->child_count(); ++i) {
418 views::View* child = menu->child_at(i);
419 int previous_count = *count;
420 RecursiveGetMenuItemIndexAndCount(child, item, index, count);
421 if (child->GetClassName() == views::MenuItemView::kViewClassName &&
422 *count == previous_count) {
423 if (item == child)
424 *index = *count;
425 (*count)++;
426 } else if (child->GetClassName() == views::TextButton::kViewClassName) {
427 if (item == child)
428 *index = *count;
429 (*count)++;
430 }
431 }
432 }
433
434 // static
435 std::string AccessibilityEventRouterViews::RecursiveGetStaticText(
436 views::View* view) {
437 ui::AccessibleViewState state;
438 view->GetAccessibleState(&state);
439 if (state.role == ui::AccessibilityTypes::ROLE_STATICTEXT)
440 return UTF16ToUTF8(state.name);
441
442 for (int i = 0; i < view->child_count(); ++i) {
443 views::View* child = view->child_at(i);
444 std::string result = RecursiveGetStaticText(child);
445 if (!result.empty())
446 return result;
447 }
448 return std::string();
449 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698