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