Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1272)

Side by Side Diff: chrome/browser/views/toolbar_view.cc

Issue 333010: Implement keyboard access between bookmarks and toolbar. (Closed)
Patch Set: Add more null checks Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/views/toolbar_view.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/views/toolbar_view.h" 5 #include "chrome/browser/views/toolbar_view.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "app/drag_drop_types.h" 9 #include "app/drag_drop_types.h"
10 #include "app/gfx/canvas.h" 10 #include "app/gfx/canvas.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 #include "chrome/common/pref_names.h" 45 #include "chrome/common/pref_names.h"
46 #include "chrome/common/pref_service.h" 46 #include "chrome/common/pref_service.h"
47 #include "grit/chromium_strings.h" 47 #include "grit/chromium_strings.h"
48 #include "grit/generated_resources.h" 48 #include "grit/generated_resources.h"
49 #include "grit/theme_resources.h" 49 #include "grit/theme_resources.h"
50 #include "net/base/net_util.h" 50 #include "net/base/net_util.h"
51 #include "views/background.h" 51 #include "views/background.h"
52 #include "views/controls/button/button_dropdown.h" 52 #include "views/controls/button/button_dropdown.h"
53 #include "views/controls/label.h" 53 #include "views/controls/label.h"
54 #include "views/drag_utils.h" 54 #include "views/drag_utils.h"
55 #include "views/focus/view_storage.h"
56 #include "views/widget/root_view.h"
57 #include "views/widget/tooltip_manager.h"
58 #include "views/window/non_client_view.h" 55 #include "views/window/non_client_view.h"
59 #include "views/window/window.h" 56 #include "views/window/window.h"
60 57
61 static const int kControlHorizOffset = 4; 58 static const int kControlHorizOffset = 4;
62 static const int kControlVertOffset = 6; 59 static const int kControlVertOffset = 6;
63 static const int kControlIndent = 3; 60 static const int kControlIndent = 3;
64 static const int kStatusBubbleWidth = 480; 61 static const int kStatusBubbleWidth = 480;
65 62
66 // Separation between the location bar and the menus. 63 // Separation between the location bar and the menus.
67 static const int kMenuButtonOffset = 3; 64 static const int kMenuButtonOffset = 3;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS); 144 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
148 AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL); 145 AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
149 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS); 146 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
150 } 147 }
151 148
152 //////////////////////////////////////////////////////////////////////////////// 149 ////////////////////////////////////////////////////////////////////////////////
153 // ToolbarView, public: 150 // ToolbarView, public:
154 151
155 ToolbarView::ToolbarView(Browser* browser) 152 ToolbarView::ToolbarView(Browser* browser)
156 : model_(browser->toolbar_model()), 153 : model_(browser->toolbar_model()),
157 acc_focused_view_(NULL),
158 last_focused_view_storage_id_(
159 views::ViewStorage::GetSharedInstance()->CreateStorageID()),
160 back_(NULL), 154 back_(NULL),
161 forward_(NULL), 155 forward_(NULL),
162 reload_(NULL), 156 reload_(NULL),
163 home_(NULL), 157 home_(NULL),
164 star_(NULL), 158 star_(NULL),
165 location_bar_(NULL), 159 location_bar_(NULL),
166 go_(NULL), 160 go_(NULL),
167 browser_actions_(NULL), 161 browser_actions_(NULL),
168 page_menu_(NULL), 162 page_menu_(NULL),
169 app_menu_(NULL), 163 app_menu_(NULL),
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 } 212 }
219 213
220 void ToolbarView::Update(TabContents* tab, bool should_restore_state) { 214 void ToolbarView::Update(TabContents* tab, bool should_restore_state) {
221 if (location_bar_) 215 if (location_bar_)
222 location_bar_->Update(should_restore_state ? tab : NULL); 216 location_bar_->Update(should_restore_state ? tab : NULL);
223 217
224 if (browser_actions_) 218 if (browser_actions_)
225 browser_actions_->RefreshBrowserActionViews(); 219 browser_actions_->RefreshBrowserActionViews();
226 } 220 }
227 221
228 int ToolbarView::GetNextAccessibleViewIndex(int view_index, bool nav_left) { 222 ////////////////////////////////////////////////////////////////////////////////
229 int modifier = 1; 223 // ToolbarView, AccessibleToolbarView overrides:
230 224
231 if (nav_left) 225 bool ToolbarView::IsAccessibleViewTraversable(views::View* view) {
232 modifier = -1; 226 return view != location_bar_;
233
234 int current_view_index = view_index + modifier;
235
236 while ((current_view_index >= 0) &&
237 (current_view_index < GetChildViewCount())) {
238 // Skip the location bar, as it has its own keyboard navigation. Also skip
239 // any views that cannot be interacted with.
240 if (current_view_index == GetChildIndex(location_bar_) ||
241 !GetChildViewAt(current_view_index)->IsEnabled() ||
242 !GetChildViewAt(current_view_index)->IsVisible()) {
243 current_view_index += modifier;
244 continue;
245 }
246 // Update view_index with the available button index found.
247 view_index = current_view_index;
248 break;
249 }
250 // Returns the next available button index, or if no button is available in
251 // the specified direction, remains where it was.
252 return view_index;
253 }
254
255 void ToolbarView::InitializeTraversal() {
256 // If MSAA focus exists, we don't need to traverse, since its already active.
257 if (acc_focused_view_ != NULL)
258 return;
259
260 // Save the last focused view so that when the user presses ESC, it will
261 // return back to the last focus.
262 views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
263 view_storage->StoreView(last_focused_view_storage_id_,
264 GetRootView()->GetFocusedView());
265
266 // HACK: Do not use RequestFocus() here, as the toolbar is not marked as
267 // "focusable". Instead bypass the sanity check in RequestFocus() and just
268 // force it to focus, which will do the right thing.
269 GetRootView()->FocusView(this);
270 } 227 }
271 228
272 //////////////////////////////////////////////////////////////////////////////// 229 ////////////////////////////////////////////////////////////////////////////////
273 // ToolbarView, Menu::BaseControllerDelegate overrides: 230 // ToolbarView, Menu::BaseControllerDelegate overrides:
274 231
275 bool ToolbarView::GetAcceleratorInfo(int id, views::Accelerator* accel) { 232 bool ToolbarView::GetAcceleratorInfo(int id, views::Accelerator* accel) {
276 return GetWidget()->GetAccelerator(id, accel); 233 return GetWidget()->GetAccelerator(id, accel);
277 } 234 }
278 235
279 //////////////////////////////////////////////////////////////////////////////// 236 ////////////////////////////////////////////////////////////////////////////////
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 if (GetWindow()->GetNonClientView()->UseNativeFrame()) 580 if (GetWindow()->GetNonClientView()->UseNativeFrame())
624 canvas->FillRectInt(SK_ColorBLACK, 0, height() - 1, width(), 1); 581 canvas->FillRectInt(SK_ColorBLACK, 0, height() - 1, width(), 1);
625 } 582 }
626 583
627 void ToolbarView::ThemeChanged() { 584 void ToolbarView::ThemeChanged() {
628 LoadLeftSideControlsImages(); 585 LoadLeftSideControlsImages();
629 LoadCenterStackImages(); 586 LoadCenterStackImages();
630 LoadRightSideControlsImages(); 587 LoadRightSideControlsImages();
631 } 588 }
632 589
633 void ToolbarView::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
634 if (acc_focused_view_)
635 acc_focused_view_->ShowContextMenu(x, y, is_mouse_gesture);
636 }
637
638 void ToolbarView::DidGainFocus() {
639 // Check to see if MSAA focus should be restored to previously focused button,
640 // and if button is an enabled, visibled child of toolbar.
641 if (!acc_focused_view_ ||
642 (acc_focused_view_->GetParent()->GetID() != VIEW_ID_TOOLBAR) ||
643 !acc_focused_view_->IsEnabled() ||
644 !acc_focused_view_->IsVisible()) {
645 // Find first accessible child (-1 to start search at parent).
646 int first_acc_child = GetNextAccessibleViewIndex(-1, false);
647
648 // No buttons enabled or visible.
649 if (first_acc_child == -1)
650 return;
651
652 set_acc_focused_view(GetChildViewAt(first_acc_child));
653 }
654
655 // Default focus is on the toolbar.
656 int view_index = VIEW_ID_TOOLBAR;
657
658 // Set hot-tracking for child, and update focused_view for MSAA focus event.
659 if (acc_focused_view_) {
660 acc_focused_view_->SetHotTracked(true);
661
662 // Show the tooltip for the view that got the focus.
663 if (GetWidget()->GetTooltipManager())
664 GetWidget()->GetTooltipManager()->ShowKeyboardTooltip(acc_focused_view_);
665
666 // Update focused_view with MSAA-adjusted child id.
667 view_index = acc_focused_view_->GetID();
668 }
669
670 #if defined(OS_WIN)
671 gfx::NativeView wnd = GetWidget()->GetNativeView();
672
673 // Notify Access Technology that there was a change in keyboard focus.
674 ::NotifyWinEvent(EVENT_OBJECT_FOCUS, wnd, OBJID_CLIENT,
675 static_cast<LONG>(view_index));
676 #else
677 // TODO(port): deal with toolbar a11y focus.
678 NOTIMPLEMENTED();
679 #endif
680 }
681
682 void ToolbarView::WillLoseFocus() {
683 // Any tooltips that are active should be hidden when toolbar loses focus.
684 if (GetWidget() && GetWidget()->GetTooltipManager())
685 GetWidget()->GetTooltipManager()->HideKeyboardTooltip();
686
687 // Removes the Child MSAA view's focus and the view from the ViewStorage,
688 // when toolbar loses focus.
689 if (acc_focused_view_) {
690 acc_focused_view_->SetHotTracked(false);
691 acc_focused_view_ = NULL;
692 views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
693 view_storage->RemoveView(last_focused_view_storage_id_);
694 }
695 }
696
697 void ToolbarView::RequestFocus() {
698 // When the toolbar needs to request focus, the default implementation of
699 // View::RequestFocus requires the View to be focusable. Since ToolbarView is
700 // not technically focused, we need to temporarily set and remove focus so
701 // that it can focus back to its MSAA focused state. |acc_focused_view_| is
702 // not necessarily set since it can be null if this view has already lost
703 // focus, such as traversing through the context menu.
704 SetFocusable(true);
705 View::RequestFocus();
706 SetFocusable(false);
707 }
708
709 bool ToolbarView::OnKeyPressed(const views::KeyEvent& e) {
710 // Paranoia check, button should be initialized upon toolbar gaining focus.
711 if (!acc_focused_view_)
712 return false;
713
714 int focused_view = GetChildIndex(acc_focused_view_);
715 int next_view = focused_view;
716
717 switch (e.GetKeyCode()) {
718 case base::VKEY_LEFT:
719 next_view = GetNextAccessibleViewIndex(focused_view, true);
720 break;
721 case base::VKEY_RIGHT:
722 next_view = GetNextAccessibleViewIndex(focused_view, false);
723 break;
724 case base::VKEY_DOWN:
725 case base::VKEY_RETURN:
726 // VKEY_SPACE is already handled by the default case.
727 if (acc_focused_view_->GetID() == VIEW_ID_PAGE_MENU ||
728 acc_focused_view_->GetID() == VIEW_ID_APP_MENU) {
729 // If a menu button in toolbar is activated and its menu is displayed,
730 // then active tooltip should be hidden.
731 if (GetWidget()->GetTooltipManager())
732 GetWidget()->GetTooltipManager()->HideKeyboardTooltip();
733 // Safe to cast, given to above view id check.
734 static_cast<views::MenuButton*>(acc_focused_view_)->Activate();
735 if (!acc_focused_view_) {
736 // Activate triggered a focus change, don't try to change focus.
737 return true;
738 }
739 // Re-enable hot-tracking, as Activate() will disable it.
740 acc_focused_view_->SetHotTracked(true);
741 break;
742 }
743 default:
744 // If key is not handled explicitly, pass it on to view.
745 return acc_focused_view_->OnKeyPressed(e);
746 }
747
748 // No buttons enabled or visible.
749 if (next_view == -1)
750 return false;
751
752 // Only send an event if focus moved.
753 if (next_view != focused_view) {
754 // Remove hot-tracking from old focused button.
755 acc_focused_view_->SetHotTracked(false);
756
757 // All is well, update the focused child member variable.
758 acc_focused_view_ = GetChildViewAt(next_view);
759
760 // Hot-track new focused button.
761 acc_focused_view_->SetHotTracked(true);
762
763 // Show the tooltip for the view that got the focus.
764 if (GetWidget()->GetTooltipManager()) {
765 GetWidget()->GetTooltipManager()->
766 ShowKeyboardTooltip(GetChildViewAt(next_view));
767 }
768 #if defined(OS_WIN)
769 // Retrieve information to generate an MSAA focus event.
770 gfx::NativeView wnd = GetWidget()->GetNativeView();
771 int view_id = acc_focused_view_->GetID();
772 // Notify Access Technology that there was a change in keyboard focus.
773 ::NotifyWinEvent(EVENT_OBJECT_FOCUS, wnd, OBJID_CLIENT,
774 static_cast<LONG>(view_id));
775 #else
776 NOTIMPLEMENTED();
777 #endif
778 return true;
779 }
780 return false;
781 }
782
783 bool ToolbarView::OnKeyReleased(const views::KeyEvent& e) {
784 // Paranoia check, button should be initialized upon toolbar gaining focus.
785 if (!acc_focused_view_)
786 return false;
787
788 // Have keys be handled by the views themselves.
789 return acc_focused_view_->OnKeyReleased(e);
790 }
791
792 bool ToolbarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
793 if (acc_focused_view_ && e.GetKeyCode() == base::VKEY_ESCAPE) {
794 // Retrieve the focused view from the storage so we can request focus back
795 // to it. If |focus_view| is null, we place focus on the location bar.
796 // |acc_focused_view_| doesn't need to be resetted here since it will be
797 // dealt within the WillLoseFocus method.
798 views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
799 views::View* focused_view =
800 view_storage->RetrieveView(last_focused_view_storage_id_);
801 if (focused_view) {
802 view_storage->RemoveView(last_focused_view_storage_id_);
803 focused_view->RequestFocus();
804 } else {
805 location_bar_->RequestFocus();
806 }
807 return true;
808 }
809 return false;
810 }
811
812 bool ToolbarView::GetAccessibleName(std::wstring* name) {
813 if (!accessible_name_.empty()) {
814 (*name).assign(accessible_name_);
815 return true;
816 }
817 return false;
818 }
819
820 bool ToolbarView::GetAccessibleRole(AccessibilityTypes::Role* role) {
821 DCHECK(role);
822
823 *role = AccessibilityTypes::ROLE_TOOLBAR;
824 return true;
825 }
826
827 void ToolbarView::SetAccessibleName(const std::wstring& name) {
828 accessible_name_.assign(name);
829 }
830
831 //////////////////////////////////////////////////////////////////////////////// 590 ////////////////////////////////////////////////////////////////////////////////
832 // ToolbarView, views::DragController implementation: 591 // ToolbarView, views::DragController implementation:
833 592
834 void ToolbarView::WriteDragData(views::View* sender, 593 void ToolbarView::WriteDragData(views::View* sender,
835 int press_x, 594 int press_x,
836 int press_y, 595 int press_y,
837 OSExchangeData* data) { 596 OSExchangeData* data) {
838 DCHECK( 597 DCHECK(
839 GetDragOperations(sender, press_x, press_y) != DragDropTypes::DRAG_NONE); 598 GetDragOperations(sender, press_x, press_y) != DragDropTypes::DRAG_NONE);
840 599
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
1203 IDS_ABOUT, 962 IDS_ABOUT,
1204 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); 963 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
1205 app_menu_contents_->AddItemWithStringId(IDC_HELP_PAGE, IDS_HELP_PAGE); 964 app_menu_contents_->AddItemWithStringId(IDC_HELP_PAGE, IDS_HELP_PAGE);
1206 if (browser_defaults::kShowExitMenuItem) { 965 if (browser_defaults::kShowExitMenuItem) {
1207 app_menu_contents_->AddSeparator(); 966 app_menu_contents_->AddSeparator();
1208 app_menu_contents_->AddItemWithStringId(IDC_EXIT, IDS_EXIT); 967 app_menu_contents_->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
1209 } 968 }
1210 969
1211 app_menu_menu_.reset(new views::Menu2(app_menu_contents_.get())); 970 app_menu_menu_.reset(new views::Menu2(app_menu_contents_.get()));
1212 } 971 }
OLDNEW
« no previous file with comments | « chrome/browser/views/toolbar_view.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698