summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormhm@chromium.org <mhm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-04 05:32:25 +0000
committermhm@chromium.org <mhm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-04 05:32:25 +0000
commitb9376951e95e4cb1dda5a21f6f698a359ad51da0 (patch)
tree0f9e7fd4990cf431578bf15222ac2d5e4299d008 /chrome
parent6371bf471df4ae89446c22b924909f09ad034fae (diff)
downloadchromium_src-b9376951e95e4cb1dda5a21f6f698a359ad51da0.zip
chromium_src-b9376951e95e4cb1dda5a21f6f698a359ad51da0.tar.gz
chromium_src-b9376951e95e4cb1dda5a21f6f698a359ad51da0.tar.bz2
Implement keyboard access between bookmarks and main toolbar.
Allow ALT+SHIFT+T and TAB to traverse between bookmarks bar and main toolbar, same thing goes for SHIFT+TAB. Once any toolbar is focused, the arrow keys are used to traverse its children views. Any toolbar that needs to be traversable needs to extend "AccessibleToolbarView", that class will deal with all the toolbar accessibility needs such as handling ESC, Left/Right arrows, Enter, Drop downs, and traversals with Tab/Shift+Tab. There is one abstract method that the views who are extending this would need to implement if needed which allows the toolbar to skip views that are being traversed: bool IsAccessibleViewTraversable(views::View* view) BUG=25625 TEST=Test to see if the main toolbar and bookmarks bar is traversable. Review URL: http://codereview.chromium.org/333010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33793 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/views/accessible_toolbar_view.cc272
-rw-r--r--chrome/browser/views/accessible_toolbar_view.h72
-rw-r--r--chrome/browser/views/bookmark_bar_view.cc30
-rw-r--r--chrome/browser/views/bookmark_bar_view.h11
-rw-r--r--chrome/browser/views/detachable_toolbar_view.h4
-rw-r--r--chrome/browser/views/frame/browser_view.cc34
-rw-r--r--chrome/browser/views/frame/browser_view.h10
-rw-r--r--chrome/browser/views/toolbar_view.cc249
-rw-r--r--chrome/browser/views/toolbar_view.h39
-rwxr-xr-xchrome/chrome_browser.gypi4
10 files changed, 410 insertions, 315 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..3556fe7
--- /dev/null
+++ b/chrome/browser/views/accessible_toolbar_view.cc
@@ -0,0 +1,272 @@
+// 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/view_ids.h"
+#include "chrome/browser/views/frame/browser_view.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/tooltip_manager.h"
+#include "views/widget/widget.h"
+
+AccessibleToolbarView::AccessibleToolbarView()
+ : selected_focused_view_(NULL),
+ last_focused_view_storage_id_(-1) {
+}
+
+AccessibleToolbarView::~AccessibleToolbarView() {
+}
+
+void AccessibleToolbarView::InitiateTraversal(int view_storage_id) {
+ // We only traverse if accessibility is active.
+ if (selected_focused_view_)
+ return;
+
+ // Save the storage id to the last focused view. This would be used to request
+ // focus to the view when the traversal is ended.
+ last_focused_view_storage_id_ = view_storage_id;
+
+ // Request focus to the toolbar.
+ RequestFocus();
+}
+
+views::View* AccessibleToolbarView::GetNextAccessibleView(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;
+ }
+ current_view_index += modifier;
+ }
+
+ // No button is available in the specified direction.
+ return NULL;
+}
+
+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 (!selected_focused_view_ ||
+ !selected_focused_view_->IsEnabled() ||
+ !selected_focused_view_->IsVisible()) {
+ // Find first accessible child (-1 to start search at parent).
+ selected_focused_view_ = GetNextAccessibleView(-1, true);
+
+ // No buttons enabled or visible.
+ if (!selected_focused_view_)
+ return;
+ }
+
+ // 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 when toolbar loses focus. It
+ // will not remove the view from the ViewStorage because it might be
+ // traversing to another toolbar hence the last focused view should not be
+ // removed.
+ if (selected_focused_view_) {
+ selected_focused_view_->SetHotTracked(false);
+ selected_focused_view_ = NULL;
+ }
+}
+
+void AccessibleToolbarView::ShowContextMenu(int x, int y,
+ bool is_mouse_gesture) {
+ if (selected_focused_view_)
+ selected_focused_view_->ShowContextMenu(x, y, is_mouse_gesture);
+}
+
+void AccessibleToolbarView::RequestFocus() {
+ // 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. |selected_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) {
+ if (!HasFocus())
+ return View::OnKeyPressed(e);
+
+ int focused_view = GetChildIndex(selected_focused_view_);
+ views::View* next_view = NULL;
+
+ switch (e.GetKeyCode()) {
+ case base::VKEY_LEFT:
+ next_view = GetNextAccessibleView(focused_view, false);
+ break;
+ case base::VKEY_RIGHT:
+ next_view = GetNextAccessibleView(focused_view, true);
+ break;
+ case base::VKEY_DOWN:
+ case base::VKEY_RETURN:
+ if (selected_focused_view_ && selected_focused_view_->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*>(selected_focused_view_)->Activate();
+
+ // If activate did not trigger a focus change, the menu button should
+ // remain hot tracked since the view is still focused.
+ if (selected_focused_view_)
+ selected_focused_view_->SetHotTracked(true);
+ return true;
+ }
+ default:
+ // If key is not handled explicitly, pass it on to view.
+ if (selected_focused_view_)
+ return selected_focused_view_->OnKeyPressed(e);
+ else
+ return View::OnKeyPressed(e);
+ }
+
+ // No buttons enabled, visible, or focus hasn't moved.
+ if (!next_view || !selected_focused_view_)
+ return false;
+
+ // Remove hot-tracking from old focused button.
+ selected_focused_view_->SetHotTracked(false);
+
+ // All is well, update the focused child member variable.
+ selected_focused_view_ = next_view;
+
+ // Set the focus to the current accessible view.
+ SetFocusToAccessibleView();
+ return true;
+}
+
+bool AccessibleToolbarView::OnKeyReleased(const views::KeyEvent& e) {
+ if (!selected_focused_view_)
+ return false;
+
+ // Have keys be handled by the views themselves.
+ return selected_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 (!HasFocus())
+ 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: {
+ SetFocusToLastFocusedView();
+ return true;
+ }
+ case base::VKEY_TAB: {
+ if (e.IsShiftDown()) {
+ browser_view->TraverseNextAccessibleToolbar(false);
+ } else {
+ browser_view->TraverseNextAccessibleToolbar(true);
+ }
+ 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::ViewHierarchyChanged(bool is_add, View* parent,
+ View* child) {
+ // When the toolbar is removed, traverse to the next accessible toolbar.
+ if (child == selected_focused_view_ && !is_add) {
+ selected_focused_view_->SetHotTracked(false);
+ selected_focused_view_ = NULL;
+ SetFocusToLastFocusedView();
+ }
+}
+
+void AccessibleToolbarView::SetFocusToAccessibleView() {
+ // Hot-track new focused button.
+ selected_focused_view_->SetHotTracked(true);
+
+ // Show the tooltip for the view that got the focus.
+ if (GetWidget()->GetTooltipManager()) {
+ GetWidget()->GetTooltipManager()->ShowKeyboardTooltip(
+ selected_focused_view_);
+ }
+
+#if defined(OS_WIN)
+ // Retrieve information to generate an accessible focus event.
+ gfx::NativeView wnd = GetWidget()->GetNativeView();
+ int view_id = selected_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
+}
+
+void AccessibleToolbarView::SetFocusToLastFocusedView() {
+ 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 {
+ // The ancestor *must* be a BrowserView. The check below can ensure that.
+ views::View* view = GetAncestorWithClassName(BrowserView::kViewClassName);
+ if (!view)
+ return;
+ BrowserView* browser_view = static_cast<BrowserView*>(view);
+
+ // Force the focus to be set on the location bar.
+ browser_view->SetFocusToLocationBar();
+ }
+}
diff --git a/chrome/browser/views/accessible_toolbar_view.h b/chrome/browser/views/accessible_toolbar_view.h
new file mode 100644
index 0000000..f892a74
--- /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. Child views are traversed in the order they were
+// added.
+
+class AccessibleToolbarView : public views::View {
+ public:
+ AccessibleToolbarView();
+ virtual ~AccessibleToolbarView();
+
+ // Initiate the traversal on the toolbar. The last focused view is stored in
+ // the ViewStorage with the corresponding |view_storage_id|.
+ void InitiateTraversal(int view_storage_id);
+
+ // 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 void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+ virtual View* GetAccFocusedChildView() { return selected_focused_view_; }
+
+ protected:
+ // Returns the next accessible view on the toolbar, starting from the given
+ // |view_index|. |forward| when true means it will navigate from left to right
+ // and vice versa when false. If |view_index| is -1 the first accessible child
+ // is returned.
+ views::View* GetNextAccessibleView(int view_index, bool forward);
+
+ // Invoked from GetNextAccessibleViewIndex to determine if |view| can be
+ // traversed to. Default implementation returns true, override to return false
+ // for views you don't want reachable.
+ virtual bool IsAccessibleViewTraversable(views::View* view);
+
+ private:
+ // Sets the focus to the currently |acc_focused_view_| view.
+ void SetFocusToAccessibleView();
+
+ // 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.
+ // |selected_focused_view_| doesn't need to reset here since it will be
+ // dealt within the WillLoseFocus method.
+ void SetFocusToLastFocusedView();
+
+ // Storage of strings needed for accessibility.
+ std::wstring accessible_name_;
+
+ // Selected child view currently having accessibility focus.
+ views::View* selected_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_
diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc
index 47a13be0..5237069 100644
--- a/chrome/browser/views/bookmark_bar_view.cc
+++ b/chrome/browser/views/bookmark_bar_view.cc
@@ -39,7 +39,6 @@
#include "grit/theme_resources.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/label.h"
-#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_item_view.h"
#include "views/drag_utils.h"
#include "views/view_constants.h"
@@ -716,25 +715,8 @@ int BookmarkBarView::OnPerformDrop(const DropTargetEvent& event) {
index);
}
-bool BookmarkBarView::GetAccessibleName(std::wstring* name) {
- DCHECK(name);
-
- if (!accessible_name_.empty()) {
- name->assign(accessible_name_);
- return true;
- }
- return false;
-}
-
-bool BookmarkBarView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_TOOLBAR;
- return true;
-}
-
-void BookmarkBarView::SetAccessibleName(const std::wstring& name) {
- accessible_name_.assign(name);
+bool BookmarkBarView::IsAccessibleViewTraversable(views::View* view) {
+ return view != bookmarks_separator_view_ && view != instructions_;
}
void BookmarkBarView::OnStateChanged() {
@@ -903,15 +885,17 @@ void BookmarkBarView::Init() {
if (!kDefaultFavIcon)
kDefaultFavIcon = rb.GetBitmapNamed(IDR_DEFAULT_FAVICON);
- other_bookmarked_button_ = CreateOtherBookmarkedButton();
- AddChildView(other_bookmarked_button_);
-
+ // Child views are traversed in the order they are added. Make sure the order
+ // they are added matches the visual order.
sync_error_button_ = CreateSyncErrorButton();
AddChildView(sync_error_button_);
overflow_button_ = CreateOverflowButton();
AddChildView(overflow_button_);
+ other_bookmarked_button_ = CreateOtherBookmarkedButton();
+ AddChildView(other_bookmarked_button_);
+
bookmarks_separator_view_ = new ButtonSeparatorView();
bookmarks_separator_view_->SetAccessibleName(
l10n_util::GetString(IDS_ACCNAME_SEPARATOR));
diff --git a/chrome/browser/views/bookmark_bar_view.h b/chrome/browser/views/bookmark_bar_view.h
index a9cc397..bb3d975 100644
--- a/chrome/browser/views/bookmark_bar_view.h
+++ b/chrome/browser/views/bookmark_bar_view.h
@@ -71,7 +71,7 @@ class BookmarkBarView : public DetachableToolbarView,
static const int kNewtabBarHeight;
- explicit BookmarkBarView(Profile* profile, Browser* browser);
+ BookmarkBarView(Profile* profile, Browser* browser);
virtual ~BookmarkBarView();
// Resets the profile. This removes any buttons for the current profile and
@@ -112,9 +112,9 @@ class BookmarkBarView : public DetachableToolbarView,
virtual int OnDragUpdated(const views::DropTargetEvent& event);
virtual void OnDragExited();
virtual int OnPerformDrop(const views::DropTargetEvent& event);
- virtual bool GetAccessibleName(std::wstring* name);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
- virtual void SetAccessibleName(const std::wstring& name);
+
+ // AccessibleToolbarView methods:
+ virtual bool IsAccessibleViewTraversable(views::View* view);
// ProfileSyncServiceObserver method.
virtual void OnStateChanged();
@@ -488,9 +488,6 @@ class BookmarkBarView : public DetachableToolbarView,
// Background for extension toolstrips.
SkBitmap toolstrip_background_;
- // Storage of strings needed for accessibility.
- std::wstring accessible_name_;
-
DISALLOW_COPY_AND_ASSIGN(BookmarkBarView);
};
diff --git a/chrome/browser/views/detachable_toolbar_view.h b/chrome/browser/views/detachable_toolbar_view.h
index 875ad98..d27ee53 100644
--- a/chrome/browser/views/detachable_toolbar_view.h
+++ b/chrome/browser/views/detachable_toolbar_view.h
@@ -5,14 +5,14 @@
#ifndef CHROME_BROWSER_VIEWS_DETACHABLE_TOOLBAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_DETACHABLE_TOOLBAR_VIEW_H_
-#include "views/view.h"
+#include "chrome/browser/views/accessible_toolbar_view.h"
class SkBitmap;
struct SkRect;
// DetachableToolbarView contains functionality common to views that can detach
// from the Chrome frame, such as the BookmarkBarView and the Extension shelf.
-class DetachableToolbarView : public views::View {
+class DetachableToolbarView : public AccessibleToolbarView {
public:
// The color gradient start value close to the edge of the divider.
static const SkColor kEdgeDividerColor;
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index 50d1dbe..0572717 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -66,6 +66,7 @@
#include "views/controls/single_split_view.h"
#include "views/fill_layout.h"
#include "views/focus/external_focus_tracker.h"
+#include "views/focus/view_storage.h"
#include "views/grid_layout.h"
#include "views/view.h"
#include "views/widget/root_view.h"
@@ -124,7 +125,7 @@ static const int kNewtabBarRoundness = 5;
// ------------
// Returned from BrowserView::GetClassName.
-static const char kBrowserViewClassName[] = "browser/views/BrowserView";
+const char BrowserView::kViewClassName[] = "browser/views/BrowserView";
///////////////////////////////////////////////////////////////////////////////
// BookmarkExtensionBackground, private:
@@ -412,7 +413,9 @@ BrowserView::BrowserView(Browser* browser)
hung_window_detector_(&hung_plugin_action_),
ticker_(0),
#endif
- extension_shelf_(NULL) {
+ extension_shelf_(NULL),
+ last_focused_view_storage_id_(
+ views::ViewStorage::GetSharedInstance()->CreateStorageID()) {
InitClass();
browser_->tabstrip_model()->AddObserver(this);
}
@@ -656,6 +659,17 @@ void BrowserView::PrepareToRunSystemMenu(HMENU menu) {
}
#endif
+void BrowserView::TraverseNextAccessibleToolbar(bool forward) {
+ // TODO(mohamed) This needs to be smart, that applies to all toolbars.
+ // Currently it just traverses between bookmarks and toolbar.
+ if (!forward && toolbar_->IsVisible() && toolbar_->IsEnabled()) {
+ toolbar_->InitiateTraversal(last_focused_view_storage_id_);
+ } else if (forward && bookmark_bar_view_->IsVisible() &&
+ bookmark_bar_view_->IsEnabled()) {
+ bookmark_bar_view_->InitiateTraversal(last_focused_view_storage_id_);
+ }
+}
+
// static
void BrowserView::RegisterBrowserViewPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kPluginMessageResponseTimeout,
@@ -958,7 +972,17 @@ void BrowserView::UpdateToolbar(TabContents* contents,
}
void BrowserView::FocusToolbar() {
- toolbar_->InitializeTraversal();
+ // Remove existing views in the storage, traversal should be restarted.
+ views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ if (view_storage->RetrieveView(last_focused_view_storage_id_))
+ view_storage->RemoveView(last_focused_view_storage_id_);
+
+ // Store the last focused view into the storage, to handle existing traversal.
+ view_storage->StoreView(last_focused_view_storage_id_,
+ GetRootView()->GetFocusedView());
+
+ // Start the traversal within the main toolbar.
+ toolbar_->InitiateTraversal(last_focused_view_storage_id_);
}
void BrowserView::DestroyBrowser() {
@@ -1642,7 +1666,7 @@ gfx::Size BrowserView::GetMinimumSize() {
// BrowserView, views::View overrides:
std::string BrowserView::GetClassName() const {
- return kBrowserViewClassName;
+ return kViewClassName;
}
void BrowserView::Layout() {
@@ -2074,7 +2098,7 @@ bool BrowserView::UpdateChildViewAndLayout(views::View* new_view,
new_view->SetBounds((*old_view)->bounds());
new_view->SchedulePaint();
} else if (new_view) {
- DCHECK(new_height == 0);
+ DCHECK_EQ(0, new_height);
// The heights are the same, but the old view is null. This only happens
// when the height is zero. Zero out the bounds.
new_view->SetBounds(0, 0, 0, 0);
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index 8354226..4ec827e 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -70,6 +70,9 @@ class BrowserView : public BrowserWindow,
public views::WindowDelegate,
public views::ClientView {
public:
+ // The browser view's class name.
+ static const char kViewClassName[];
+
// Explicitly sets how windows are shown. Use a value of -1 to give the
// default behavior. This is used during testing and not generally useful
// otherwise.
@@ -180,6 +183,10 @@ class BrowserView : public BrowserWindow,
void PrepareToRunSystemMenu(HMENU menu);
#endif
+ // Traverses to the next toolbar. |forward| when true, will navigate from left
+ // to right and vice versa when false.
+ void TraverseNextAccessibleToolbar(bool forward);
+
// Returns true if the Browser object associated with this BrowserView is a
// normal-type window (i.e. a browser window, not an app or popup).
bool IsBrowserTypeNormal() const {
@@ -533,6 +540,9 @@ class BrowserView : public BrowserWindow,
scoped_ptr<BrowserExtender> browser_extender_;
+ // Last focused view that issued a tab traversal.
+ int last_focused_view_storage_id_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserView);
};
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index 29a1e7a..f5e189d 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -52,9 +52,6 @@
#include "views/controls/button/button_dropdown.h"
#include "views/controls/label.h"
#include "views/drag_utils.h"
-#include "views/focus/view_storage.h"
-#include "views/widget/root_view.h"
-#include "views/widget/tooltip_manager.h"
#include "views/window/non_client_view.h"
#include "views/window/window.h"
@@ -154,9 +151,6 @@ void ZoomMenuModel::Build() {
ToolbarView::ToolbarView(Browser* browser)
: model_(browser->toolbar_model()),
- acc_focused_view_(NULL),
- last_focused_view_storage_id_(
- views::ViewStorage::GetSharedInstance()->CreateStorageID()),
back_(NULL),
forward_(NULL),
reload_(NULL),
@@ -225,48 +219,11 @@ void ToolbarView::Update(TabContents* tab, bool should_restore_state) {
browser_actions_->RefreshBrowserActionViews();
}
-int ToolbarView::GetNextAccessibleViewIndex(int view_index, bool nav_left) {
- int modifier = 1;
-
- if (nav_left)
- modifier = -1;
-
- int current_view_index = view_index + modifier;
-
- while ((current_view_index >= 0) &&
- (current_view_index < GetChildViewCount())) {
- // Skip the location bar, as it has its own keyboard navigation. Also skip
- // any views that cannot be interacted with.
- if (current_view_index == GetChildIndex(location_bar_) ||
- !GetChildViewAt(current_view_index)->IsEnabled() ||
- !GetChildViewAt(current_view_index)->IsVisible()) {
- current_view_index += modifier;
- continue;
- }
- // Update view_index with the available button index found.
- view_index = current_view_index;
- break;
- }
- // Returns the next available button index, or if no button is available in
- // the specified direction, remains where it was.
- return view_index;
-}
-
-void ToolbarView::InitializeTraversal() {
- // If MSAA focus exists, we don't need to traverse, since its already 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());
+////////////////////////////////////////////////////////////////////////////////
+// ToolbarView, AccessibleToolbarView overrides:
- // HACK: Do not use RequestFocus() here, as the toolbar is not marked as
- // "focusable". Instead bypass the sanity check in RequestFocus() and just
- // force it to focus, which will do the right thing.
- GetRootView()->FocusView(this);
+bool ToolbarView::IsAccessibleViewTraversable(views::View* view) {
+ return view != location_bar_;
}
////////////////////////////////////////////////////////////////////////////////
@@ -630,204 +587,6 @@ void ToolbarView::ThemeChanged() {
LoadRightSideControlsImages();
}
-void ToolbarView::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
- if (acc_focused_view_)
- acc_focused_view_->ShowContextMenu(x, y, is_mouse_gesture);
-}
-
-void ToolbarView::DidGainFocus() {
- // Check to see if MSAA focus should be restored to previously focused button,
- // and if button is an enabled, visibled child of toolbar.
- if (!acc_focused_view_ ||
- (acc_focused_view_->GetParent()->GetID() != VIEW_ID_TOOLBAR) ||
- !acc_focused_view_->IsEnabled() ||
- !acc_focused_view_->IsVisible()) {
- // Find first accessible child (-1 to start search at parent).
- int first_acc_child = GetNextAccessibleViewIndex(-1, false);
-
- // No buttons enabled or visible.
- if (first_acc_child == -1)
- return;
-
- set_acc_focused_view(GetChildViewAt(first_acc_child));
- }
-
- // Default focus is on the toolbar.
- int view_index = VIEW_ID_TOOLBAR;
-
- // Set hot-tracking for child, and update focused_view for MSAA focus event.
- if (acc_focused_view_) {
- acc_focused_view_->SetHotTracked(true);
-
- // Show the tooltip for the view that got the focus.
- if (GetWidget()->GetTooltipManager())
- GetWidget()->GetTooltipManager()->ShowKeyboardTooltip(acc_focused_view_);
-
- // Update focused_view with MSAA-adjusted child id.
- view_index = acc_focused_view_->GetID();
- }
-
-#if defined(OS_WIN)
- gfx::NativeView wnd = GetWidget()->GetNativeView();
-
- // Notify Access Technology that there was a change in keyboard focus.
- ::NotifyWinEvent(EVENT_OBJECT_FOCUS, wnd, OBJID_CLIENT,
- static_cast<LONG>(view_index));
-#else
- // TODO(port): deal with toolbar a11y focus.
- NOTIMPLEMENTED();
-#endif
-}
-
-void ToolbarView::WillLoseFocus() {
- // Any tooltips that are active should be hidden when toolbar loses focus.
- if (GetWidget() && GetWidget()->GetTooltipManager())
- GetWidget()->GetTooltipManager()->HideKeyboardTooltip();
-
- // Removes the Child MSAA 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 ToolbarView::RequestFocus() {
- // 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 MSAA 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 ToolbarView::OnKeyPressed(const views::KeyEvent& e) {
- // Paranoia check, button should be initialized upon toolbar gaining focus.
- if (!acc_focused_view_)
- return false;
-
- int focused_view = GetChildIndex(acc_focused_view_);
- int next_view = focused_view;
-
- switch (e.GetKeyCode()) {
- case base::VKEY_LEFT:
- next_view = GetNextAccessibleViewIndex(focused_view, true);
- break;
- case base::VKEY_RIGHT:
- next_view = GetNextAccessibleViewIndex(focused_view, false);
- break;
- case base::VKEY_DOWN:
- case base::VKEY_RETURN:
- // VKEY_SPACE is already handled by the default case.
- if (acc_focused_view_->GetID() == VIEW_ID_PAGE_MENU ||
- acc_focused_view_->GetID() == VIEW_ID_APP_MENU) {
- // If a menu button in toolbar is activated and its menu is displayed,
- // then active tooltip should be hidden.
- if (GetWidget()->GetTooltipManager())
- GetWidget()->GetTooltipManager()->HideKeyboardTooltip();
- // Safe to cast, given to above view id check.
- static_cast<views::MenuButton*>(acc_focused_view_)->Activate();
- if (!acc_focused_view_) {
- // Activate triggered a focus change, don't try to change focus.
- return true;
- }
- // Re-enable hot-tracking, as Activate() will disable it.
- acc_focused_view_->SetHotTracked(true);
- break;
- }
- default:
- // If key is not handled explicitly, pass it on to view.
- return acc_focused_view_->OnKeyPressed(e);
- }
-
- // No buttons enabled or visible.
- if (next_view == -1)
- return false;
-
- // Only send an event if focus moved.
- if (next_view != focused_view) {
- // 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);
-
- // 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(GetChildViewAt(next_view));
- }
-#if defined(OS_WIN)
- // Retrieve information to generate an MSAA 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
- return true;
- }
- return false;
-}
-
-bool ToolbarView::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 ToolbarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
- if (acc_focused_view_ && e.GetKeyCode() == 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 location bar.
- // |acc_focused_view_| doesn't need to be resetted 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 {
- location_bar_->RequestFocus();
- }
- return true;
- }
- return false;
-}
-
-bool ToolbarView::GetAccessibleName(std::wstring* name) {
- if (!accessible_name_.empty()) {
- (*name).assign(accessible_name_);
- return true;
- }
- return false;
-}
-
-bool ToolbarView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_TOOLBAR;
- return true;
-}
-
-void ToolbarView::SetAccessibleName(const std::wstring& name) {
- accessible_name_.assign(name);
-}
-
////////////////////////////////////////////////////////////////////////////////
// ToolbarView, views::DragController implementation:
diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h
index 94b54e4..cfca8b4 100644
--- a/chrome/browser/views/toolbar_view.h
+++ b/chrome/browser/views/toolbar_view.h
@@ -12,6 +12,7 @@
#include "chrome/browser/bubble_positioner.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/user_data_manager.h"
+#include "chrome/browser/views/accessible_toolbar_view.h"
#include "chrome/browser/views/go_button.h"
#include "chrome/browser/views/location_bar_view.h"
#include "chrome/common/pref_member.h"
@@ -63,8 +64,8 @@ class ZoomMenuModel : public views::SimpleMenuModel {
DISALLOW_COPY_AND_ASSIGN(ZoomMenuModel);
};
-// The Browser Window's toolbar. Used within BrowserView.
-class ToolbarView : public views::View,
+// The Browser Window's toolbar.
+class ToolbarView : public AccessibleToolbarView,
public views::ViewMenuDelegate,
public views::DragController,
public views::SimpleMenuModel::Delegate,
@@ -91,19 +92,6 @@ class ToolbarView : public views::View,
// (such as user editing) as well.
void Update(TabContents* tab, bool should_restore_state);
- // Returns the index of the next view of the toolbar, starting from the given
- // view index (skipping the location bar), in the given navigation direction
- // (nav_left true means navigation right to left, and vice versa). -1 finds
- // first accessible child, based on the above policy.
- int GetNextAccessibleViewIndex(int view_index, bool nav_left);
-
- // Initialize the MSAA focus traversal on the toolbar.
- void InitializeTraversal();
-
- void set_acc_focused_view(views::View* acc_focused_view) {
- acc_focused_view_ = acc_focused_view;
- }
-
// Accessors...
Browser* browser() const { return browser_; }
BrowserActionsContainer* browser_actions() const { return browser_actions_; }
@@ -113,6 +101,9 @@ class ToolbarView : public views::View,
views::MenuButton* page_menu() const { return page_menu_; }
views::MenuButton* app_menu() const { return app_menu_; }
+ // Overridden from AccessibleToolbarView:
+ virtual bool IsAccessibleViewTraversable(views::View* view);
+
// Overridden from Menu::BaseControllerDelegate:
virtual bool GetAcceleratorInfo(int id, views::Accelerator* accel);
@@ -152,17 +143,6 @@ class ToolbarView : public views::View,
virtual void Layout();
virtual void Paint(gfx::Canvas* canvas);
virtual void ThemeChanged();
- virtual void ShowContextMenu(int x, int y, bool is_mouse_gesture);
- virtual void DidGainFocus();
- virtual void WillLoseFocus();
- virtual void RequestFocus();
- virtual bool OnKeyPressed(const views::KeyEvent& e);
- virtual bool OnKeyReleased(const views::KeyEvent& e);
- virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e);
- 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:
// Overridden from views::DragController:
@@ -211,13 +191,6 @@ class ToolbarView : public views::View,
// The model that contains the security level, text, icon to display...
ToolbarModel* model_;
- // Storage of strings needed for accessibility.
- std::wstring accessible_name_;
- // Child view currently having MSAA focus (location bar excluded from arrow
- // navigation).
- views::View* acc_focused_view_;
- int last_focused_view_storage_id_;
-
// Controls
views::ImageButton* back_;
views::ImageButton* forward_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 244d6ba..c34bc49 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1504,6 +1504,8 @@
'browser/views/about_network_dialog.h',
'browser/views/accelerator_table_gtk.cc',
'browser/views/accelerator_table_gtk.h',
+ 'browser/views/accessible_toolbar_view.cc',
+ 'browser/views/accessible_toolbar_view.h',
'browser/views/autocomplete/autocomplete_popup_contents_view.cc',
'browser/views/autocomplete/autocomplete_popup_contents_view.h',
'browser/views/autocomplete/autocomplete_popup_win.cc',
@@ -2064,6 +2066,8 @@
['include', '^browser/extensions/'],
['include', '^browser/views/accelerator_table_gtk.cc'],
['include', '^browser/views/accelerator_table_gtk.h'],
+ ['include', '^browser/views/accessible_toolbar_view.cc'],
+ ['include', '^browser/views/accessible_toolbar_view.h'],
['include', '^browser/views/autocomplete/autocomplete_popup_contents_view.cc'],
['include', '^browser/views/autocomplete/autocomplete_popup_contents_view.h'],
['include', '^browser/views/autocomplete/autocomplete_popup_gtk.cc'],