diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/views/accessible_toolbar_view.cc | 272 | ||||
-rw-r--r-- | chrome/browser/views/accessible_toolbar_view.h | 72 | ||||
-rw-r--r-- | chrome/browser/views/bookmark_bar_view.cc | 30 | ||||
-rw-r--r-- | chrome/browser/views/bookmark_bar_view.h | 11 | ||||
-rw-r--r-- | chrome/browser/views/detachable_toolbar_view.h | 4 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.cc | 34 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.h | 10 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.cc | 249 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.h | 39 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 4 |
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'], |