diff options
author | mhm@chromium.org <mhm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-15 02:46:52 +0000 |
---|---|---|
committer | mhm@chromium.org <mhm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-15 02:46:52 +0000 |
commit | 073643ffbe63b4bc4d71eb77642b163592240a47 (patch) | |
tree | 23f056f59d9c93b03dc2808b872ec7d9263de3dd | |
parent | 0b9d50c6a670d4aca60c1cef3a2577a7195a109b (diff) | |
download | chromium_src-073643ffbe63b4bc4d71eb77642b163592240a47.zip chromium_src-073643ffbe63b4bc4d71eb77642b163592240a47.tar.gz chromium_src-073643ffbe63b4bc4d71eb77642b163592240a47.tar.bz2 |
Rebase
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32014 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/views/accessible_toolbar_view.cc | 255 | ||||
-rw-r--r-- | chrome/browser/views/accessible_toolbar_view.h | 72 |
2 files changed, 327 insertions, 0 deletions
diff --git a/chrome/browser/views/accessible_toolbar_view.cc b/chrome/browser/views/accessible_toolbar_view.cc new file mode 100644 index 0000000..4bf537a --- /dev/null +++ b/chrome/browser/views/accessible_toolbar_view.cc @@ -0,0 +1,255 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/view_ids.h" +#include "chrome/browser/views/accessible_toolbar_view.h" +#include "views/controls/button/menu_button.h" +#include "views/focus/view_storage.h" +#include "views/widget/root_view.h" +#include "views/widget/tooltip_manager.h" +#include "views/widget/widget.h" + +AccessibleToolbarView::AccessibleToolbarView() + : acc_focused_view_(NULL), + last_focused_view_storage_id_( + views::ViewStorage::GetSharedInstance()->CreateStorageID()) { +} + +AccessibleToolbarView::~AccessibleToolbarView() { +} + +int AccessibleToolbarView::GetNextAccessibleViewIndex(int view_index, + bool forward) { + int modifier = forward ? 1 : -1; + int current_view_index = view_index + modifier; + + while ((current_view_index >= 0) && + (current_view_index < GetChildViewCount())) { + // Try to find the next available view that can be interacted with. That + // view must be enabled, visible, and traversable. + views::View* current_view = GetChildViewAt(current_view_index); + if (current_view->IsEnabled() && current_view->IsVisible() && + IsAccessibleViewTraversable(current_view)) { + return current_view_index; + } + current_view_index += modifier; + } + + // No button is available in the specified direction, remains where it was. + return view_index; +} + +bool AccessibleToolbarView::IsAccessibleViewTraversable(views::View* view) { + return true; +} + +void AccessibleToolbarView::DidGainFocus() { + // Check to see if the accessible focus should be restored to previously + // focused button. The must be enabled and visible in the toolbar. + if (!acc_focused_view_ || + !acc_focused_view_->IsEnabled() || + !acc_focused_view_->IsVisible()) { + // Find first accessible child (-1 to start search at parent). + int first_acc_child = GetNextAccessibleViewIndex(-1, true); + + // No buttons enabled or visible. + if (first_acc_child == -1) + return; + + set_acc_focused_view(GetChildViewAt(first_acc_child)); + } + + // Set the focus to the current accessible view. + SetFocusToAccessibleView(); +} + +void AccessibleToolbarView::WillLoseFocus() { + // Any tooltips that are active should be hidden when toolbar loses focus. + if (GetWidget() && GetWidget()->GetTooltipManager()) + GetWidget()->GetTooltipManager()->HideKeyboardTooltip(); + + // Removes the child accessibility view's focus and the view from the + // ViewStorage, when toolbar loses focus. + if (acc_focused_view_) { + acc_focused_view_->SetHotTracked(false); + acc_focused_view_ = NULL; + views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance(); + view_storage->RemoveView(last_focused_view_storage_id_); + } +} + +void AccessibleToolbarView::ShowContextMenu(int x, int y, + bool is_mouse_gesture) { + if (acc_focused_view_) + acc_focused_view_->ShowContextMenu(x, y, is_mouse_gesture); +} + +void AccessibleToolbarView::RequestFocus() { + // We only traverse if accessibility is active. + if (acc_focused_view_ != NULL) + return; + + // Save the last focused view so that when the user presses ESC, it will + // return back to the last focus. + views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance(); + view_storage->StoreView(last_focused_view_storage_id_, + GetRootView()->GetFocusedView()); + + // When the toolbar needs to request focus, the default implementation of + // View::RequestFocus requires the View to be focusable. Since ToolbarView is + // not technically focused, we need to temporarily set and remove focus so + // that it can focus back to its focused state. |acc_focused_view_| is + // not necessarily set since it can be null if this view has already lost + // focus, such as traversing through the context menu. + SetFocusable(true); + View::RequestFocus(); + SetFocusable(false); +} + +bool AccessibleToolbarView::OnKeyPressed(const views::KeyEvent& e) { + // Paranoia check, button should be initialized upon toolbar gaining focus. + if (!acc_focused_view_) + return View::OnKeyPressed(e); + + int focused_view = GetChildIndex(acc_focused_view_); + int next_view = focused_view; + + switch (e.GetKeyCode()) { + case base::VKEY_LEFT: + next_view = GetNextAccessibleViewIndex(focused_view, false); + break; + case base::VKEY_RIGHT: + next_view = GetNextAccessibleViewIndex(focused_view, true); + break; + case base::VKEY_DOWN: + case base::VKEY_RETURN: + if (GetAccFocusedChildView()->GetClassName() == + views::MenuButton::kViewClassName) { + // If a menu button is activated and its menu is displayed, then the + // active tooltip should be hidden. + if (GetWidget()->GetTooltipManager()) + GetWidget()->GetTooltipManager()->HideKeyboardTooltip(); + // Safe to cast, given to above check. + static_cast<views::MenuButton*>(GetAccFocusedChildView())->Activate(); + if (!GetAccFocusedChildView()) { + // Activate triggered a focus change, don't try to change focus. + return true; + } + // Re-enable hot-tracking, as Activate() will disable it. + GetAccFocusedChildView()->SetHotTracked(true); + break; + } + default: + // If key is not handled explicitly, pass it on to view. + return acc_focused_view_->OnKeyPressed(e); + } + + // No buttons enabled, visible, or focus hasn't moved. + if (next_view == -1 || next_view == focused_view) + return false; + + // Remove hot-tracking from old focused button. + acc_focused_view_->SetHotTracked(false); + + // All is well, update the focused child member variable. + acc_focused_view_ = GetChildViewAt(next_view); + + // Set the focus to the current accessible view. + SetFocusToAccessibleView(); + return true; +} + +bool AccessibleToolbarView::OnKeyReleased(const views::KeyEvent& e) { + // Paranoia check, button should be initialized upon toolbar gaining focus. + if (!acc_focused_view_) + return false; + + // Have keys be handled by the views themselves. + return acc_focused_view_->OnKeyReleased(e); +} + +bool AccessibleToolbarView::SkipDefaultKeyEventProcessing( + const views::KeyEvent& e) { + // Accessibility focus must be present in order to handle ESC and TAB related + // key events. + if (!acc_focused_view_) + return false; + + // The ancestor *must* be a BrowserView. + views::View* view = GetAncestorWithClassName(BrowserView::kViewClassName); + if (!view) + return false; + + // Given the check above, we can ensure its a BrowserView. + BrowserView* browser_view = static_cast<BrowserView*>(view); + + // Handle ESC and TAB events. + switch (e.GetKeyCode()) { + case base::VKEY_ESCAPE: { + // Retrieve the focused view from the storage so we can request focus back + // to it. If |focus_view| is null, we place focus on the default view. + // |acc_focused_view_| doesn't need to be reset here since it will be + // dealt within the WillLoseFocus method. + views::ViewStorage* view_storage = + views::ViewStorage::GetSharedInstance(); + views::View* focused_view = + view_storage->RetrieveView(last_focused_view_storage_id_); + if (focused_view) { + view_storage->RemoveView(last_focused_view_storage_id_); + focused_view->RequestFocus(); + } else { + browser_view->SetFocusToLocationBar(); + } + return true; + } + case base::VKEY_TAB: { + if (e.IsShiftDown()) { + browser_view->TraverseNextAccessibleToolbar(true); + } else { + browser_view->TraverseNextAccessibleToolbar(false); + } + return true; + } + default: return false; + } +} + +bool AccessibleToolbarView::GetAccessibleName(std::wstring* name) { + *name = accessible_name_; + return !accessible_name_.empty(); +} + +bool AccessibleToolbarView::GetAccessibleRole(AccessibilityTypes::Role* role) { + DCHECK(role); + + *role = AccessibilityTypes::ROLE_TOOLBAR; + return true; +} + +void AccessibleToolbarView::SetAccessibleName(const std::wstring& name) { + accessible_name_ = name; +} + +void AccessibleToolbarView::SetFocusToAccessibleView() { + // Hot-track new focused button. + acc_focused_view_->SetHotTracked(true); + + // Show the tooltip for the view that got the focus. + if (GetWidget()->GetTooltipManager()) { + GetWidget()->GetTooltipManager()->ShowKeyboardTooltip(acc_focused_view_); + } + +#if defined(OS_WIN) + // Retrieve information to generate an accessible focus event. + gfx::NativeView wnd = GetWidget()->GetNativeView(); + int view_id = acc_focused_view_->GetID(); + // Notify Access Technology that there was a change in keyboard focus. + ::NotifyWinEvent(EVENT_OBJECT_FOCUS, wnd, OBJID_CLIENT, + static_cast<LONG>(view_id)); +#else + NOTIMPLEMENTED(); +#endif +} diff --git a/chrome/browser/views/accessible_toolbar_view.h b/chrome/browser/views/accessible_toolbar_view.h new file mode 100644 index 0000000..293ebeb --- /dev/null +++ b/chrome/browser/views/accessible_toolbar_view.h @@ -0,0 +1,72 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_ACCESSIBLE_TOOLBAR_VIEW_H_ +#define CHROME_BROWSER_VIEWS_ACCESSIBLE_TOOLBAR_VIEW_H_ + +#include "views/view.h" + +// This class provides keyboard access to any view that extends it by intiating +// ALT+SHIFT+T. And once you press TAB or SHIFT-TAB, it will traverse all the +// toolbars within Chrome. It traverses child views in the order of adding them, +// not necessarily the visual order. +// +// If a toolbar needs to be traversal then it needs to be focusable. But we do +// not want the toolbar to have any focus, so some hacking needs to be done to +// tell the focus manager that this view is focusable while it's not. The main +// purpose of this class is to provide keyboard access to any View that extends +// this. It will properly hot track and add the tooltip to the first level +// children if visited. + +class AccessibleToolbarView : public views::View { + public: + AccessibleToolbarView(); + virtual ~AccessibleToolbarView(); + + // Returns the index of the next view of the toolbar, starting from the given + // view index, in the given navigation direction, |forward| when true means it + // will navigate from left to right, and vice versa when false. When + // |view_index| is -1, it finds the first accessible child. + int GetNextAccessibleViewIndex(int view_index, bool forward); + + // Invoked when you press left and right arrows while traversing in the view. + // The default implementation is true, where every child in the view is + // traversable. + virtual bool IsAccessibleViewTraversable(views::View* view); + + // Sets the accessible focused view. + void set_acc_focused_view(views::View* acc_focused_view) { + acc_focused_view_ = acc_focused_view; + } + + // Overridden from views::View: + virtual void DidGainFocus(); + virtual void WillLoseFocus(); + virtual bool OnKeyPressed(const views::KeyEvent& e); + virtual bool OnKeyReleased(const views::KeyEvent& e); + virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e); + virtual void ShowContextMenu(int x, int y, bool is_mouse_gesture); + virtual void RequestFocus(); + virtual bool GetAccessibleName(std::wstring* name); + virtual bool GetAccessibleRole(AccessibilityTypes::Role* role); + virtual void SetAccessibleName(const std::wstring& name); + virtual View* GetAccFocusedChildView() { return acc_focused_view_; } + + private: + // Sets the focus to the currently |acc_focused_view_| view. + void SetFocusToAccessibleView(); + + // Storage of strings needed for accessibility. + std::wstring accessible_name_; + + // Child view currently having accessibility focus. + views::View* acc_focused_view_; + + // Last focused view that issued this traversal. + int last_focused_view_storage_id_; + + DISALLOW_COPY_AND_ASSIGN(AccessibleToolbarView); +}; + +#endif // CHROME_BROWSER_VIEWS_ACCESSIBLE_TOOLBAR_VIEW_H_ |