summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/toolbar_view.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/views/toolbar_view.cc')
-rw-r--r--chrome/browser/views/toolbar_view.cc249
1 files changed, 245 insertions, 4 deletions
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index 20346c2..0747331 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -51,6 +51,9 @@
#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"
@@ -150,6 +153,9 @@ 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),
@@ -218,11 +224,48 @@ void ToolbarView::Update(TabContents* tab, bool should_restore_state) {
browser_actions_->RefreshBrowserActionViews();
}
-////////////////////////////////////////////////////////////////////////////////
-// ToolbarView, AccessibleToolbarView overrides:
+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;
-bool ToolbarView::IsAccessibleViewTraversable(views::View* view) {
- return view != location_bar_;
+ // 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());
+
+ // 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);
}
////////////////////////////////////////////////////////////////////////////////
@@ -586,6 +629,204 @@ 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: