Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/views/location_bar/page_action_image_view.h" | 5 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h" |
| 6 | 6 |
| 7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
| 8 #include "chrome/browser/extensions/api/commands/command_service.h" | |
| 9 #include "chrome/browser/extensions/extension_action.h" | 8 #include "chrome/browser/extensions/extension_action.h" |
| 10 #include "chrome/browser/extensions/extension_action_icon_factory.h" | |
| 11 #include "chrome/browser/extensions/extension_action_manager.h" | |
| 12 #include "chrome/browser/extensions/extension_context_menu_model.h" | |
| 13 #include "chrome/browser/extensions/extension_tab_util.h" | |
| 14 #include "chrome/browser/extensions/location_bar_controller.h" | |
| 15 #include "chrome/browser/extensions/tab_helper.h" | |
| 16 #include "chrome/browser/platform_util.h" | 9 #include "chrome/browser/platform_util.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
| 18 #include "chrome/browser/sessions/session_id.h" | 11 #include "chrome/browser/ui/browser.h" |
| 19 #include "chrome/browser/ui/browser_list.h" | |
| 20 #include "chrome/browser/ui/extensions/accelerator_priority.h" | |
| 21 #include "chrome/browser/ui/views/frame/browser_view.h" | |
| 22 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" | 12 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
| 23 #include "chrome/browser/ui/webui/extensions/extension_info_ui.h" | |
| 24 #include "extensions/browser/extension_registry.h" | 13 #include "extensions/browser/extension_registry.h" |
| 25 #include "extensions/common/extension.h" | |
| 26 #include "ui/accessibility/ax_view_state.h" | 14 #include "ui/accessibility/ax_view_state.h" |
| 27 #include "ui/events/event.h" | 15 #include "ui/events/event.h" |
| 28 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
| 29 #include "ui/gfx/image/image.h" | 17 #include "ui/gfx/image/image.h" |
| 30 #include "ui/views/controls/menu/menu_runner.h" | |
| 31 | |
| 32 using content::WebContents; | |
| 33 using extensions::LocationBarController; | |
| 34 using extensions::Extension; | |
| 35 | 18 |
| 36 PageActionImageView::PageActionImageView(LocationBarView* owner, | 19 PageActionImageView::PageActionImageView(LocationBarView* owner, |
| 37 ExtensionAction* page_action, | 20 ExtensionAction* page_action, |
| 38 Browser* browser) | 21 Browser* browser) |
| 39 : owner_(owner), | 22 : extension_action_view_(new ExtensionActionView( |
| 40 page_action_(page_action), | 23 extensions::ExtensionRegistry::Get(browser->profile())-> |
| 41 browser_(browser), | 24 enabled_extensions().GetByID(page_action->extension_id()), |
| 42 current_tab_id_(-1), | 25 browser, |
| 43 preview_enabled_(false), | 26 page_action, |
| 44 popup_(NULL) { | 27 this)), |
| 45 const Extension* extension = extensions::ExtensionRegistry::Get( | 28 owner_(owner), |
| 46 owner_->profile())->enabled_extensions().GetByID( | 29 preview_enabled_(false) { |
| 47 page_action->extension_id()); | |
| 48 DCHECK(extension); | |
| 49 | |
| 50 icon_factory_.reset( | |
| 51 new ExtensionActionIconFactory( | |
| 52 owner_->profile(), extension, page_action, this)); | |
| 53 | |
| 54 SetAccessibilityFocusable(true); | 30 SetAccessibilityFocusable(true); |
| 55 set_context_menu_controller(this); | 31 extension_action_view_->RegisterCommand(); |
|
sky
2014/08/05 22:29:47
At the time this is invoked does GetFocusManagerFo
Devlin
2014/08/05 23:51:10
This shouldn't be any different than the existing
sky
2014/08/06 00:28:25
No need to delay if everything is good. How about
Devlin
2014/08/06 16:19:02
Done, via DCHECK(GetFocusManagerForAccelerator()).
| |
| 56 | 32 set_context_menu_controller(extension_action_view_.get()); |
| 57 extensions::CommandService* command_service = | |
| 58 extensions::CommandService::Get(browser_->profile()); | |
| 59 extensions::Command page_action_command; | |
| 60 if (command_service->GetPageActionCommand( | |
| 61 extension->id(), | |
| 62 extensions::CommandService::ACTIVE_ONLY, | |
| 63 &page_action_command, | |
| 64 NULL)) { | |
| 65 page_action_keybinding_.reset( | |
| 66 new ui::Accelerator(page_action_command.accelerator())); | |
| 67 owner_->GetFocusManager()->RegisterAccelerator( | |
| 68 *page_action_keybinding_.get(), | |
| 69 GetAcceleratorPriority(page_action_command.accelerator(), extension), | |
| 70 this); | |
| 71 } | |
| 72 } | 33 } |
| 73 | 34 |
| 74 PageActionImageView::~PageActionImageView() { | 35 PageActionImageView::~PageActionImageView() { |
| 75 if (owner_->GetFocusManager()) { | |
| 76 if (page_action_keybinding_.get()) { | |
| 77 owner_->GetFocusManager()->UnregisterAccelerator( | |
| 78 *page_action_keybinding_.get(), this); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 if (popup_) | |
| 83 popup_->GetWidget()->RemoveObserver(this); | |
| 84 HidePopup(); | |
| 85 } | |
| 86 | |
| 87 void PageActionImageView::ExecuteAction( | |
| 88 ExtensionPopup::ShowAction show_action) { | |
| 89 WebContents* web_contents = owner_->GetWebContents(); | |
| 90 if (!web_contents) | |
| 91 return; | |
| 92 | |
| 93 extensions::TabHelper* extensions_tab_helper = | |
| 94 extensions::TabHelper::FromWebContents(web_contents); | |
| 95 LocationBarController* controller = | |
| 96 extensions_tab_helper->location_bar_controller(); | |
| 97 | |
| 98 switch (controller->OnClicked(page_action_)) { | |
| 99 case LocationBarController::ACTION_NONE: | |
| 100 break; | |
| 101 | |
| 102 case LocationBarController::ACTION_SHOW_POPUP: | |
| 103 ShowPopupWithURL(page_action_->GetPopupUrl(current_tab_id_), show_action); | |
| 104 break; | |
| 105 | |
| 106 case LocationBarController::ACTION_SHOW_CONTEXT_MENU: | |
| 107 // We are never passing OnClicked a right-click button, so assume that | |
| 108 // we're never going to be asked to show a context menu. | |
| 109 // TODO(kalman): if this changes, update this class to pass the real | |
| 110 // mouse button through to the LocationBarController. | |
| 111 NOTREACHED(); | |
| 112 break; | |
| 113 } | |
| 114 } | 36 } |
| 115 | 37 |
| 116 void PageActionImageView::GetAccessibleState(ui::AXViewState* state) { | 38 void PageActionImageView::GetAccessibleState(ui::AXViewState* state) { |
| 117 state->role = ui::AX_ROLE_BUTTON; | 39 state->role = ui::AX_ROLE_BUTTON; |
| 118 state->name = base::UTF8ToUTF16(tooltip_); | 40 state->name = base::UTF8ToUTF16(tooltip_); |
| 119 } | 41 } |
| 120 | 42 |
| 121 bool PageActionImageView::OnMousePressed(const ui::MouseEvent& event) { | 43 bool PageActionImageView::OnMousePressed(const ui::MouseEvent& event) { |
| 122 // We want to show the bubble on mouse release; that is the standard behavior | 44 // We want to show the bubble on mouse release; that is the standard behavior |
| 123 // for buttons. (Also, triggering on mouse press causes bugs like | 45 // for buttons. (Also, triggering on mouse press causes bugs like |
| 124 // http://crbug.com/33155.) | 46 // http://crbug.com/33155.) |
| 125 return true; | 47 return true; |
| 126 } | 48 } |
| 127 | 49 |
| 128 void PageActionImageView::OnMouseReleased(const ui::MouseEvent& event) { | 50 void PageActionImageView::OnMouseReleased(const ui::MouseEvent& event) { |
| 129 if (!HitTestPoint(event.location())) | 51 if (!HitTestPoint(event.location())) |
| 130 return; | 52 return; |
| 131 | 53 |
| 132 if (event.IsRightMouseButton()) { | 54 if (event.IsRightMouseButton()) { |
| 133 // Don't show a menu here, its handled in View::ProcessMouseReleased. We | 55 // Don't show a menu here, its handled in View::ProcessMouseReleased. We |
| 134 // show the context menu by way of being the ContextMenuController. | 56 // show the context menu by way of being the ContextMenuController. |
| 135 return; | 57 return; |
| 136 } | 58 } |
| 137 | 59 |
| 138 ExecuteAction(ExtensionPopup::SHOW); | 60 extension_action_view_->ExecuteActionByUser(); |
| 139 } | 61 } |
| 140 | 62 |
| 141 bool PageActionImageView::OnKeyPressed(const ui::KeyEvent& event) { | 63 bool PageActionImageView::OnKeyPressed(const ui::KeyEvent& event) { |
| 142 if (event.key_code() == ui::VKEY_SPACE || | 64 if (event.key_code() == ui::VKEY_SPACE || |
| 143 event.key_code() == ui::VKEY_RETURN) { | 65 event.key_code() == ui::VKEY_RETURN) { |
| 144 ExecuteAction(ExtensionPopup::SHOW); | 66 extension_action_view_->ExecuteActionByUser(); |
| 145 return true; | 67 return true; |
| 146 } | 68 } |
| 147 return false; | 69 return false; |
| 148 } | 70 } |
| 149 | 71 |
| 150 void PageActionImageView::ShowContextMenuForView( | |
| 151 View* source, | |
| 152 const gfx::Point& point, | |
| 153 ui::MenuSourceType source_type) { | |
| 154 const Extension* extension = extensions::ExtensionRegistry::Get( | |
| 155 owner_->profile())->enabled_extensions().GetByID( | |
| 156 page_action()->extension_id()); | |
| 157 if (!extension->ShowConfigureContextMenus()) | |
| 158 return; | |
| 159 | |
| 160 scoped_refptr<ExtensionContextMenuModel> context_menu_model( | |
| 161 new ExtensionContextMenuModel(extension, browser_, this)); | |
| 162 menu_runner_.reset(new views::MenuRunner( | |
| 163 context_menu_model.get(), | |
| 164 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU)); | |
| 165 gfx::Point screen_loc; | |
| 166 views::View::ConvertPointToScreen(this, &screen_loc); | |
| 167 if (menu_runner_->RunMenuAt(GetWidget(), | |
| 168 NULL, | |
| 169 gfx::Rect(screen_loc, size()), | |
| 170 views::MENU_ANCHOR_TOPLEFT, | |
| 171 source_type) == views::MenuRunner::MENU_DELETED) { | |
| 172 return; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 bool PageActionImageView::AcceleratorPressed( | 72 bool PageActionImageView::AcceleratorPressed( |
| 177 const ui::Accelerator& accelerator) { | 73 const ui::Accelerator& accelerator) { |
| 178 DCHECK(visible()); // Should not have happened due to CanHandleAccelerator. | 74 DCHECK(visible()); // Should not have happened due to CanHandleAccelerator. |
| 179 | 75 return extension_action_view_->AcceleratorPressed(accelerator); |
| 180 const std::string extension_id = page_action()->extension_id(); | |
| 181 const ui::AcceleratorManager::HandlerPriority priority = | |
| 182 GetAcceleratorPriorityById(accelerator, extension_id, owner_->profile()); | |
| 183 // Normal priority shortcuts must be handled via standard browser commands | |
| 184 // to be processed at the proper time. | |
| 185 if (priority == ui::AcceleratorManager::kHighPriority) | |
| 186 ExecuteAction(ExtensionPopup::SHOW); | |
| 187 return priority == ui::AcceleratorManager::kHighPriority; | |
| 188 } | 76 } |
| 189 | 77 |
| 190 bool PageActionImageView::CanHandleAccelerators() const { | 78 bool PageActionImageView::CanHandleAccelerators() const { |
| 191 // While visible, we don't handle accelerators and while so we also don't | 79 // While visible, we don't handle accelerators and while so we also don't |
| 192 // count as a priority accelerator handler. | 80 // count as a priority accelerator handler. |
| 193 return visible(); | 81 return visible(); |
| 194 } | 82 } |
| 195 | 83 |
| 196 void PageActionImageView::UpdateVisibility(WebContents* contents, | 84 void PageActionImageView::UpdateVisibility(content::WebContents* contents) { |
| 197 const GURL& url) { | 85 int tab_id = extension_action_view_->GetCurrentTabId(); |
| 198 // Save this off so we can pass it back to the extension when the action gets | |
| 199 // executed. See PageActionImageView::OnMousePressed. | |
| 200 current_tab_id_ = | |
| 201 contents ? extensions::ExtensionTabUtil::GetTabId(contents) : -1; | |
| 202 current_url_ = url; | |
| 203 | 86 |
| 204 if (!contents || | 87 if (!contents || |
| 205 (!preview_enabled_ && !page_action_->GetIsVisible(current_tab_id_))) { | 88 tab_id == -1 || |
| 89 (!preview_enabled_ && !extension_action()->GetIsVisible(tab_id))) { | |
| 206 SetVisible(false); | 90 SetVisible(false); |
| 207 return; | 91 return; |
| 208 } | 92 } |
| 209 | 93 |
| 210 // Set the tooltip. | 94 // Set the tooltip. |
| 211 tooltip_ = page_action_->GetTitle(current_tab_id_); | 95 tooltip_ = extension_action()->GetTitle(tab_id); |
| 212 SetTooltipText(base::UTF8ToUTF16(tooltip_)); | 96 SetTooltipText(base::UTF8ToUTF16(tooltip_)); |
| 213 | 97 |
| 214 // Set the image. | 98 // Set the image. |
| 215 gfx::Image icon = icon_factory_->GetIcon(current_tab_id_); | 99 gfx::Image icon = extension_action_view_->GetIcon(tab_id); |
| 216 if (!icon.IsEmpty()) | 100 if (!icon.IsEmpty()) |
| 217 SetImage(*icon.ToImageSkia()); | 101 SetImage(*icon.ToImageSkia()); |
| 218 | 102 |
| 219 SetVisible(true); | 103 SetVisible(true); |
| 220 } | 104 } |
| 221 | 105 |
| 222 void PageActionImageView::InspectPopup() { | 106 void PageActionImageView::PaintChildren(gfx::Canvas* canvas, |
| 223 ExecuteAction(ExtensionPopup::SHOW_AND_INSPECT); | 107 const views::CullSet& cull_set) { |
| 224 } | 108 View::PaintChildren(canvas, cull_set); |
| 225 | 109 int tab_id = extension_action_view_->GetCurrentTabId(); |
| 226 void PageActionImageView::OnWidgetDestroying(views::Widget* widget) { | 110 if (tab_id >= 0) { |
| 227 DCHECK_EQ(popup_->GetWidget(), widget); | 111 extension_action_view_->extension_action()->PaintBadge( |
| 228 popup_->GetWidget()->RemoveObserver(this); | 112 canvas, GetLocalBounds(), tab_id); |
| 229 popup_ = NULL; | 113 } |
| 230 } | 114 } |
| 231 | 115 |
| 232 void PageActionImageView::OnIconUpdated() { | 116 void PageActionImageView::OnIconUpdated() { |
| 233 WebContents* web_contents = owner_->GetWebContents(); | 117 UpdateVisibility(GetCurrentWebContents()); |
| 234 if (web_contents) | |
| 235 UpdateVisibility(web_contents, current_url_); | |
| 236 } | 118 } |
| 237 | 119 |
| 238 void PageActionImageView::PaintChildren(gfx::Canvas* canvas, | 120 views::View* PageActionImageView::GetAsView() { |
| 239 const views::CullSet& cull_set) { | 121 return this; |
| 240 View::PaintChildren(canvas, cull_set); | |
| 241 if (current_tab_id_ >= 0) | |
| 242 page_action_->PaintBadge(canvas, GetLocalBounds(), current_tab_id_); | |
| 243 } | 122 } |
| 244 | 123 |
| 245 void PageActionImageView::ShowPopupWithURL( | 124 bool PageActionImageView::IsNestedView() { |
| 246 const GURL& popup_url, | 125 return false; |
| 247 ExtensionPopup::ShowAction show_action) { | |
| 248 bool popup_showing = popup_ != NULL; | |
| 249 | |
| 250 // Always hide the current popup. Only one popup at a time. | |
| 251 HidePopup(); | |
| 252 | |
| 253 // If we were already showing, then treat this click as a dismiss. | |
| 254 if (popup_showing) | |
| 255 return; | |
| 256 | |
| 257 views::BubbleBorder::Arrow arrow = base::i18n::IsRTL() ? | |
| 258 views::BubbleBorder::TOP_LEFT : views::BubbleBorder::TOP_RIGHT; | |
| 259 | |
| 260 popup_ = ExtensionPopup::ShowPopup(popup_url, browser_, this, arrow, | |
| 261 show_action); | |
| 262 popup_->GetWidget()->AddObserver(this); | |
| 263 } | 126 } |
| 264 | 127 |
| 265 void PageActionImageView::HidePopup() { | 128 views::FocusManager* PageActionImageView::GetFocusManagerForAccelerator() { |
| 266 if (popup_) | 129 return owner_->GetFocusManager(); |
| 267 popup_->GetWidget()->Close(); | |
| 268 } | 130 } |
| 131 | |
| 132 views::Widget* PageActionImageView::GetParentForContextMenu() { | |
| 133 return GetWidget(); | |
| 134 } | |
| 135 | |
| 136 views::View* PageActionImageView::GetReferenceViewForPopup() { | |
| 137 return this; | |
| 138 } | |
| 139 | |
| 140 content::WebContents* PageActionImageView::GetCurrentWebContents() { | |
| 141 return owner_->GetWebContents(); | |
| 142 } | |
| 143 | |
| 144 void PageActionImageView::HideActivePopup() { | |
| 145 // The only popup that will be active is this popup. | |
| 146 extension_action_view_->HidePopup(); | |
| 147 } | |
| OLD | NEW |