| OLD | NEW |
| 1 // Copyright (c) 2011 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 <algorithm> | 5 #include <algorithm> |
| 6 #include <vector> | 6 #include <vector> |
| 7 | 7 |
| 8 #include "chrome/browser/ui/browser.h" | 8 #include "chrome/browser/ui/browser.h" |
| 9 #include "chrome/browser/ui/intents/web_intent_picker.h" | 9 #include "chrome/browser/ui/intents/web_intent_picker.h" |
| 10 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" | 10 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" |
| 11 #include "chrome/browser/ui/intents/web_intent_picker_model.h" |
| 12 #include "chrome/browser/ui/intents/web_intent_picker_model_observer.h" |
| 11 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 13 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 12 #include "chrome/browser/ui/views/frame/browser_view.h" | 14 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 13 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" | 15 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" |
| 14 #include "chrome/browser/ui/views/toolbar_view.h" | 16 #include "chrome/browser/ui/views/toolbar_view.h" |
| 15 #include "chrome/browser/ui/views/window.h" | 17 #include "chrome/browser/ui/views/window.h" |
| 16 #include "grit/generated_resources.h" | 18 #include "grit/generated_resources.h" |
| 17 #include "grit/theme_resources.h" | |
| 18 #include "grit/theme_resources_standard.h" | |
| 19 #include "grit/ui_resources.h" | |
| 20 #include "ui/base/l10n/l10n_util.h" | 19 #include "ui/base/l10n/l10n_util.h" |
| 21 #include "ui/base/resource/resource_bundle.h" | |
| 22 #include "ui/gfx/canvas.h" | 20 #include "ui/gfx/canvas.h" |
| 23 #include "ui/gfx/canvas_skia.h" | 21 #include "ui/gfx/canvas_skia.h" |
| 24 #include "ui/gfx/image/image.h" | 22 #include "ui/gfx/image/image.h" |
| 25 #include "ui/views/bubble/bubble_delegate.h" | 23 #include "ui/views/bubble/bubble_delegate.h" |
| 26 #include "ui/views/controls/button/image_button.h" | 24 #include "ui/views/controls/button/text_button.h" |
| 27 #include "ui/views/controls/image_view.h" | 25 #include "ui/views/controls/image_view.h" |
| 28 #include "ui/views/controls/label.h" | 26 #include "ui/views/controls/label.h" |
| 29 #include "ui/views/layout/box_layout.h" | 27 #include "ui/views/layout/box_layout.h" |
| 30 | 28 |
| 31 using content::WebContents; | 29 using content::WebContents; |
| 32 | 30 |
| 33 namespace { | 31 namespace { |
| 34 | 32 |
| 35 // The space in pixels between the top-level groups in the dialog. | 33 // The space in pixels between the top-level groups in the dialog. |
| 36 const int kContentAreaSpacing = 18; | 34 const int kContentAreaSpacing = 18; |
| 37 | 35 |
| 38 // The space in pixels between the top-level groups and the dialog border. | 36 // The space in pixels between the top-level groups and the dialog border. |
| 39 const int kContentAreaBorder = 12; | 37 const int kContentAreaBorder = 12; |
| 40 | 38 |
| 41 // The space in pixels between controls in a group. | 39 // The space in pixels between controls in a group. |
| 42 const int kControlSpacing = 6; | 40 const int kControlSpacing = 6; |
| 43 | 41 |
| 44 // The size, relative to default, of the Chrome Web store label. | 42 // The size, relative to default, of the Chrome Web store label. |
| 45 const int kWebStoreLabelFontDelta = -2; | 43 const int kWebStoreLabelFontDelta = -2; |
| 46 | 44 |
| 47 // Create a new image where |image| is drawn on top of the image identified by | |
| 48 // |bg_id|. The result is drawn to |out_image|. | |
| 49 void CreateButtonImage(int bg_id, const SkBitmap& image, SkBitmap* out_image) { | |
| 50 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 51 SkBitmap bg_bitmap = rb.GetImageNamed(bg_id); | |
| 52 bg_bitmap.copyTo(out_image, SkBitmap::kARGB_8888_Config); | |
| 53 | |
| 54 SkPaint paint; | |
| 55 paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); | |
| 56 | |
| 57 SkCanvas bg_canvas(*out_image); | |
| 58 bg_canvas.drawBitmap(image, | |
| 59 SkIntToScalar((bg_bitmap.width() - image.width()) / 2), | |
| 60 SkIntToScalar((bg_bitmap.height() - image.height()) / 2), | |
| 61 &paint); | |
| 62 } | |
| 63 | |
| 64 // Set the images on |button| for states normal, hot, and pushed. | |
| 65 // The images are generated by drawing |image| on top of the identified by | |
| 66 // |bg_normal_id|, |bg_hot_id|, and |bg_pushed_id| respectively. | |
| 67 void SetButtonImages(views::ImageButton* button, | |
| 68 const SkBitmap& image, | |
| 69 int bg_normal_id, int bg_hot_id, int bg_pushed_id) { | |
| 70 SkBitmap image_normal; | |
| 71 CreateButtonImage(bg_normal_id, image, &image_normal); | |
| 72 button->SetImage(views::CustomButton::BS_NORMAL, &image_normal); | |
| 73 | |
| 74 SkBitmap image_hot; | |
| 75 CreateButtonImage(bg_hot_id, image, &image_hot); | |
| 76 button->SetImage(views::CustomButton::BS_HOT, &image_hot); | |
| 77 | |
| 78 SkBitmap image_pushed; | |
| 79 CreateButtonImage(bg_pushed_id, image, &image_pushed); | |
| 80 button->SetImage(views::CustomButton::BS_PUSHED, &image_pushed); | |
| 81 } | |
| 82 | |
| 83 } // namespace | 45 } // namespace |
| 84 | 46 |
| 85 // Views implementation of WebIntentPicker. | 47 // Views implementation of WebIntentPicker. |
| 86 class WebIntentPickerView : public views::BubbleDelegateView, | 48 class WebIntentPickerView : public views::BubbleDelegateView, |
| 87 public views::ButtonListener, | 49 public views::ButtonListener, |
| 88 public WebIntentPicker { | 50 public WebIntentPicker, |
| 51 public WebIntentPickerModelObserver { |
| 89 public: | 52 public: |
| 90 WebIntentPickerView(views::View* anchor_view, | 53 WebIntentPickerView(views::View* anchor_view, |
| 91 TabContentsWrapper* tab_contents, | 54 TabContentsWrapper* tab_contents, |
| 92 WebIntentPickerDelegate* delegate); | 55 WebIntentPickerDelegate* delegate, |
| 56 WebIntentPickerModel* model); |
| 93 virtual ~WebIntentPickerView(); | 57 virtual ~WebIntentPickerView(); |
| 94 | 58 |
| 95 // views::ButtonListener implementation. | 59 // views::ButtonListener implementation. |
| 96 virtual void ButtonPressed(views::Button* sender, | 60 virtual void ButtonPressed(views::Button* sender, |
| 97 const views::Event& event) OVERRIDE; | 61 const views::Event& event) OVERRIDE; |
| 98 | 62 |
| 99 // views::WidgetDelegate implementation. | 63 // views::WidgetDelegate implementation. |
| 100 virtual void WindowClosing() OVERRIDE; | 64 virtual void WindowClosing() OVERRIDE; |
| 101 | 65 |
| 102 // WebIntentPicker implementation. | 66 // WebIntentPicker implementation. |
| 103 virtual void SetServiceURLs(const std::vector<GURL>& urls) OVERRIDE; | |
| 104 virtual void SetServiceIcon(size_t index, const SkBitmap& icon) OVERRIDE; | |
| 105 virtual void SetDefaultServiceIcon(size_t index) OVERRIDE; | |
| 106 virtual void Close() OVERRIDE; | 67 virtual void Close() OVERRIDE; |
| 107 virtual content::WebContents* SetInlineDisposition(const GURL& url) OVERRIDE; | 68 |
| 69 // WebIntentPickerModelObserver implementation. |
| 70 virtual void OnModelChanged(WebIntentPickerModel* model) OVERRIDE; |
| 71 virtual void OnFaviconChanged(WebIntentPickerModel* model, |
| 72 size_t index) OVERRIDE; |
| 73 virtual void OnInlineDisposition(WebIntentPickerModel* model) OVERRIDE; |
| 108 | 74 |
| 109 protected: | 75 protected: |
| 110 // views::BubbleDelegateView overrides: | 76 // views::BubbleDelegateView overrides: |
| 111 void Init() OVERRIDE; | 77 void Init() OVERRIDE; |
| 112 | 78 |
| 113 private: | 79 private: |
| 114 // A weak pointer to the WebIntentPickerDelegate to notify when the user | 80 // A weak pointer to the WebIntentPickerDelegate to notify when the user |
| 115 // chooses a service or cancels. | 81 // chooses a service or cancels. |
| 116 WebIntentPickerDelegate* delegate_; | 82 WebIntentPickerDelegate* delegate_; |
| 117 | 83 |
| 84 // Web pointer to the picker model. |
| 85 WebIntentPickerModel* model_; |
| 86 |
| 118 // A weak pointer to the hbox that contains the buttons used to choose the | 87 // A weak pointer to the hbox that contains the buttons used to choose the |
| 119 // service. | 88 // service. |
| 120 views::View* button_hbox_; | 89 views::View* button_vbox_; |
| 121 | 90 |
| 122 // A vector of weak pointers to each of the service buttons. | 91 // A vector of weak pointers to each of the service buttons. |
| 123 std::vector<views::Button*> buttons_; | 92 std::vector<views::TextButton*> buttons_; |
| 124 | |
| 125 // A weak pointer to the plus button, used to search for more services on the | |
| 126 // Chrome Web Store. | |
| 127 views::ImageButton* plus_button_; | |
| 128 | 93 |
| 129 DISALLOW_COPY_AND_ASSIGN(WebIntentPickerView); | 94 DISALLOW_COPY_AND_ASSIGN(WebIntentPickerView); |
| 130 }; | 95 }; |
| 131 | 96 |
| 132 // static | 97 // static |
| 133 WebIntentPicker* WebIntentPicker::Create(Browser* browser, | 98 WebIntentPicker* WebIntentPicker::Create(Browser* browser, |
| 134 TabContentsWrapper* wrapper, | 99 TabContentsWrapper* wrapper, |
| 135 WebIntentPickerDelegate* delegate) { | 100 WebIntentPickerDelegate* delegate, |
| 101 WebIntentPickerModel* model) { |
| 136 // Find where to point the bubble at. | 102 // Find where to point the bubble at. |
| 137 BrowserView* browser_view = | 103 BrowserView* browser_view = |
| 138 BrowserView::GetBrowserViewForBrowser(browser); | 104 BrowserView::GetBrowserViewForBrowser(browser); |
| 139 views::View* anchor_view = | 105 views::View* anchor_view = |
| 140 browser_view->toolbar()->location_bar()->location_icon_view(); | 106 browser_view->toolbar()->location_bar()->location_icon_view(); |
| 141 WebIntentPickerView* bubble_delegate = | 107 WebIntentPickerView* bubble_delegate = |
| 142 new WebIntentPickerView(anchor_view, wrapper, delegate); | 108 new WebIntentPickerView(anchor_view, wrapper, delegate, model); |
| 143 browser::CreateViewsBubble(bubble_delegate); | 109 browser::CreateViewsBubble(bubble_delegate); |
| 144 bubble_delegate->Show(); | 110 bubble_delegate->Show(); |
| 145 return bubble_delegate; | 111 return bubble_delegate; |
| 146 } | 112 } |
| 147 | 113 |
| 148 WebIntentPickerView::WebIntentPickerView(views::View* anchor_view, | 114 WebIntentPickerView::WebIntentPickerView(views::View* anchor_view, |
| 149 TabContentsWrapper* wrapper, | 115 TabContentsWrapper* wrapper, |
| 150 WebIntentPickerDelegate* delegate) | 116 WebIntentPickerDelegate* delegate, |
| 117 WebIntentPickerModel* model) |
| 151 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT), | 118 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT), |
| 152 delegate_(delegate), | 119 delegate_(delegate), |
| 153 button_hbox_(NULL), | 120 model_(model), |
| 154 plus_button_(NULL) { | 121 button_vbox_(NULL) { |
| 122 model_->set_observer(this); |
| 155 } | 123 } |
| 156 | 124 |
| 157 WebIntentPickerView::~WebIntentPickerView() { | 125 WebIntentPickerView::~WebIntentPickerView() { |
| 126 model_->set_observer(NULL); |
| 158 } | 127 } |
| 159 | 128 |
| 160 void WebIntentPickerView::ButtonPressed(views::Button* sender, | 129 void WebIntentPickerView::ButtonPressed(views::Button* sender, |
| 161 const views::Event& event) { | 130 const views::Event& event) { |
| 162 // TODO(binji) When we support the plus button, pressing it should forward the | 131 std::vector<views::TextButton*>::iterator iter = |
| 163 // user to services in the Chrome Web Store that provide this intent. | |
| 164 if (sender == plus_button_) | |
| 165 return; | |
| 166 | |
| 167 std::vector<views::Button*>::iterator iter = | |
| 168 std::find(buttons_.begin(), buttons_.end(), sender); | 132 std::find(buttons_.begin(), buttons_.end(), sender); |
| 169 DCHECK(iter != buttons_.end()); | 133 DCHECK(iter != buttons_.end()); |
| 170 | 134 |
| 171 size_t index = iter - buttons_.begin(); | 135 size_t index = iter - buttons_.begin(); |
| 172 delegate_->OnServiceChosen(index); | 136 const WebIntentPickerModel::Item& item = model_->GetItemAt(index); |
| 137 |
| 138 delegate_->OnServiceChosen(index, item.disposition); |
| 173 } | 139 } |
| 174 | 140 |
| 175 void WebIntentPickerView::WindowClosing() { | 141 void WebIntentPickerView::WindowClosing() { |
| 176 delegate_->OnCancelled(); | 142 delegate_->OnClosing(); |
| 177 } | |
| 178 | |
| 179 void WebIntentPickerView::SetServiceURLs(const std::vector<GURL>& urls) { | |
| 180 for (size_t i = 0; i < urls.size(); ++i) { | |
| 181 views::ImageButton* button = new views::ImageButton(this); | |
| 182 button->SetTooltipText(UTF8ToUTF16(urls[i].spec().c_str())); | |
| 183 button_hbox_->AddChildView(button); | |
| 184 buttons_.push_back(button); | |
| 185 } | |
| 186 | |
| 187 // Add the '+' button, to use the Chrome Web Store. | |
| 188 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 189 plus_button_ = new views::ImageButton(this); | |
| 190 plus_button_->SetTooltipText( | |
| 191 l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_TOOLTIP)); | |
| 192 SetButtonImages(plus_button_, rb.GetImageNamed(IDR_SIDETABS_NEW_TAB), | |
| 193 IDR_BROWSER_ACTION, IDR_BROWSER_ACTION_H, IDR_BROWSER_ACTION_P); | |
| 194 button_hbox_->AddChildView(plus_button_); | |
| 195 } | |
| 196 | |
| 197 void WebIntentPickerView::SetServiceIcon(size_t index, const SkBitmap& icon) { | |
| 198 views::ImageButton* button = | |
| 199 static_cast<views::ImageButton*>(button_hbox_->child_at(index)); | |
| 200 SetButtonImages(button, icon, | |
| 201 IDR_BROWSER_ACTION, IDR_BROWSER_ACTION_H, IDR_BROWSER_ACTION_P); | |
| 202 | |
| 203 Layout(); | |
| 204 SizeToContents(); | |
| 205 } | |
| 206 | |
| 207 void WebIntentPickerView::SetDefaultServiceIcon(size_t index) { | |
| 208 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 209 SetServiceIcon(index, rb.GetImageNamed(IDR_DEFAULT_FAVICON)); | |
| 210 } | 143 } |
| 211 | 144 |
| 212 void WebIntentPickerView::Close() { | 145 void WebIntentPickerView::Close() { |
| 213 GetWidget()->Close(); | 146 GetWidget()->Close(); |
| 214 } | 147 } |
| 215 | 148 |
| 216 WebContents* WebIntentPickerView::SetInlineDisposition(const GURL& url) { | 149 void WebIntentPickerView::OnModelChanged(WebIntentPickerModel* model) { |
| 150 button_vbox_->RemoveAllChildViews(true); |
| 151 buttons_.clear(); |
| 152 |
| 153 for (size_t i = 0; i < model->GetItemCount(); ++i) { |
| 154 const WebIntentPickerModel::Item& item = model_->GetItemAt(i); |
| 155 |
| 156 views::TextButton* button = new views::TextButton(this, item.title); |
| 157 button->SetTooltipText(UTF8ToUTF16(item.url.spec().c_str())); |
| 158 button->SetIcon(*item.favicon.ToSkBitmap()); |
| 159 button_vbox_->AddChildView(button); |
| 160 |
| 161 buttons_.push_back(button); |
| 162 } |
| 163 } |
| 164 |
| 165 void WebIntentPickerView::OnFaviconChanged(WebIntentPickerModel* model, |
| 166 size_t index) { |
| 167 const WebIntentPickerModel::Item& item = model_->GetItemAt(index); |
| 168 views::TextButton* button = buttons_[index]; |
| 169 |
| 170 button->SetIcon(*item.favicon.ToSkBitmap()); |
| 171 |
| 172 Layout(); |
| 173 SizeToContents(); |
| 174 } |
| 175 |
| 176 void WebIntentPickerView::OnInlineDisposition(WebIntentPickerModel* model) { |
| 217 // TODO(gbillock): add support here. | 177 // TODO(gbillock): add support here. |
| 218 return NULL; | 178 delegate_->OnInlineDispositionWebContentsCreated(NULL); |
| 219 } | 179 } |
| 220 | 180 |
| 221 void WebIntentPickerView::Init() { | 181 void WebIntentPickerView::Init() { |
| 222 SetLayoutManager(new views::BoxLayout( | 182 SetLayoutManager(new views::BoxLayout( |
| 223 views::BoxLayout::kHorizontal, | 183 views::BoxLayout::kHorizontal, |
| 224 kContentAreaBorder, // inside border horizontal spacing | 184 kContentAreaBorder, // inside border horizontal spacing |
| 225 kContentAreaBorder, // inside border vertical spacing | 185 kContentAreaBorder, // inside border vertical spacing |
| 226 kContentAreaSpacing)); // between child spacing | 186 kContentAreaSpacing)); // between child spacing |
| 227 | 187 |
| 228 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 229 SkBitmap image_bitmap = rb.GetImageNamed(IDR_PAGEINFO_INFO); | |
| 230 views::ImageView* image = new views::ImageView(); | |
| 231 image->SetImage(image_bitmap); | |
| 232 image->SetVerticalAlignment(views::ImageView::LEADING); | |
| 233 AddChildView(image); | |
| 234 | |
| 235 views::View* main_content = new views::View(); | 188 views::View* main_content = new views::View(); |
| 236 main_content->SetLayoutManager(new views::BoxLayout( | 189 main_content->SetLayoutManager(new views::BoxLayout( |
| 237 views::BoxLayout::kVertical, | 190 views::BoxLayout::kVertical, |
| 238 0, // inside border horizontal spacing | 191 0, // inside border horizontal spacing |
| 239 0, // inside border vertical spacing | 192 0, // inside border vertical spacing |
| 240 kContentAreaSpacing)); // between child spacing | 193 kContentAreaSpacing)); // between child spacing |
| 241 | 194 |
| 242 views::Label* top_label = new views::Label( | 195 views::Label* top_label = new views::Label( |
| 243 l10n_util::GetStringUTF16(IDS_CHOOSE_INTENT_HANDLER_MESSAGE)); | 196 l10n_util::GetStringUTF16(IDS_CHOOSE_INTENT_HANDLER_MESSAGE)); |
| 244 top_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | 197 top_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| 245 main_content->AddChildView(top_label); | 198 main_content->AddChildView(top_label); |
| 246 | 199 |
| 247 button_hbox_ = new views::View(); | 200 button_vbox_ = new views::View(); |
| 248 button_hbox_->SetLayoutManager(new views::BoxLayout( | 201 button_vbox_->SetLayoutManager(new views::BoxLayout( |
| 249 views::BoxLayout::kHorizontal, | 202 views::BoxLayout::kVertical, |
| 250 0, // inside border horizontal spacing | 203 0, // inside border horizontal spacing |
| 251 0, // inside border vertical spacing | 204 0, // inside border vertical spacing |
| 252 kControlSpacing)); // between child spacing | 205 kControlSpacing)); // between child spacing |
| 253 main_content->AddChildView(button_hbox_); | 206 main_content->AddChildView(button_vbox_); |
| 254 | 207 |
| 255 views::Label* bottom_label = new views::Label( | 208 views::Label* bottom_label = new views::Label( |
| 256 l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE)); | 209 l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE)); |
| 257 bottom_label->SetMultiLine(true); | 210 bottom_label->SetMultiLine(true); |
| 258 bottom_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | 211 bottom_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| 259 bottom_label->SetFont( | 212 bottom_label->SetFont( |
| 260 bottom_label->font().DeriveFont(kWebStoreLabelFontDelta)); | 213 bottom_label->font().DeriveFont(kWebStoreLabelFontDelta)); |
| 261 main_content->AddChildView(bottom_label); | 214 main_content->AddChildView(bottom_label); |
| 262 | 215 |
| 263 AddChildView(main_content); | 216 AddChildView(main_content); |
| 264 } | 217 } |
| OLD | NEW |