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