summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormhm@chromium.org <mhm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-15 02:46:52 +0000
committermhm@chromium.org <mhm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-15 02:46:52 +0000
commit073643ffbe63b4bc4d71eb77642b163592240a47 (patch)
tree23f056f59d9c93b03dc2808b872ec7d9263de3dd
parent0b9d50c6a670d4aca60c1cef3a2577a7195a109b (diff)
downloadchromium_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.cc255
-rw-r--r--chrome/browser/views/accessible_toolbar_view.h72
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_