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