| 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/content_setting_bubble_contents.h" |    5 #include "chrome/browser/ui/views/content_setting_bubble_contents.h" | 
|    6  |    6  | 
|    7 #include <algorithm> |    7 #include <algorithm> | 
|    8 #include <set> |    8 #include <set> | 
|    9 #include <string> |    9 #include <string> | 
|   10 #include <vector> |   10 #include <vector> | 
|   11  |   11  | 
 |   12 #include "base/bind.h" | 
 |   13 #include "base/stl_util.h" | 
|   12 #include "base/utf_string_conversions.h" |   14 #include "base/utf_string_conversions.h" | 
|   13 #include "chrome/browser/content_settings/host_content_settings_map.h" |   15 #include "chrome/browser/content_settings/host_content_settings_map.h" | 
|   14 #include "chrome/browser/plugins/plugin_finder.h" |   16 #include "chrome/browser/plugins/plugin_finder.h" | 
|   15 #include "chrome/browser/plugins/plugin_metadata.h" |   17 #include "chrome/browser/plugins/plugin_metadata.h" | 
|   16 #include "chrome/browser/ui/chrome_style.h" |   18 #include "chrome/browser/ui/chrome_style.h" | 
|   17 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" |   19 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" | 
 |   20 #include "chrome/browser/ui/content_settings/content_setting_media_menu_model.h" | 
|   18 #include "chrome/browser/ui/views/browser_dialogs.h" |   21 #include "chrome/browser/ui/views/browser_dialogs.h" | 
|   19 #include "content/public/browser/notification_source.h" |   22 #include "content/public/browser/notification_source.h" | 
|   20 #include "content/public/browser/notification_types.h" |   23 #include "content/public/browser/notification_types.h" | 
|   21 #include "content/public/browser/plugin_service.h" |   24 #include "content/public/browser/plugin_service.h" | 
 |   25 #include "content/public/browser/web_contents.h" | 
|   22 #include "grit/generated_resources.h" |   26 #include "grit/generated_resources.h" | 
 |   27 #include "grit/theme_resources.h" | 
|   23 #include "ui/base/l10n/l10n_util.h" |   28 #include "ui/base/l10n/l10n_util.h" | 
 |   29 #include "ui/base/models/simple_menu_model.h" | 
 |   30 #include "ui/views/controls/button/menu_button.h" | 
|   24 #include "ui/views/controls/button/radio_button.h" |   31 #include "ui/views/controls/button/radio_button.h" | 
|   25 #include "ui/views/controls/button/text_button.h" |   32 #include "ui/views/controls/button/text_button.h" | 
|   26 #include "ui/views/controls/image_view.h" |   33 #include "ui/views/controls/image_view.h" | 
|   27 #include "ui/views/controls/label.h" |   34 #include "ui/views/controls/label.h" | 
|   28 #include "ui/views/controls/link.h" |   35 #include "ui/views/controls/link.h" | 
 |   36 #include "ui/views/controls/menu/menu.h" | 
 |   37 #include "ui/views/controls/menu/menu_model_adapter.h" | 
 |   38 #include "ui/views/controls/menu/menu_runner.h" | 
|   29 #include "ui/views/controls/separator.h" |   39 #include "ui/views/controls/separator.h" | 
|   30 #include "ui/views/layout/grid_layout.h" |   40 #include "ui/views/layout/grid_layout.h" | 
|   31 #include "ui/views/layout/layout_constants.h" |   41 #include "ui/views/layout/layout_constants.h" | 
|   32  |   42  | 
|   33 #if defined(USE_AURA) |   43 #if defined(USE_AURA) | 
|   34 #include "ui/base/cursor/cursor.h" |   44 #include "ui/base/cursor/cursor.h" | 
|   35 #endif |   45 #endif | 
|   36  |   46  | 
 |   47 namespace { | 
 |   48  | 
|   37 // If we don't clamp the maximum width, then very long URLs and titles can make |   49 // If we don't clamp the maximum width, then very long URLs and titles can make | 
|   38 // the bubble arbitrarily wide. |   50 // the bubble arbitrarily wide. | 
|   39 const int kMaxContentsWidth = 500; |   51 const int kMaxContentsWidth = 500; | 
|   40  |   52  | 
|   41 // When we have multiline labels, we should set a minimum width lest we get very |   53 // When we have multiline labels, we should set a minimum width lest we get very | 
|   42 // narrow bubbles with lots of line-wrapping. |   54 // narrow bubbles with lots of line-wrapping. | 
|   43 const int kMinMultiLineContentsWidth = 250; |   55 const int kMinMultiLineContentsWidth = 250; | 
|   44  |   56  | 
 |   57 // The minimum and maximum width of the media menu buttons. | 
 |   58 const int kMinMediaMenuButtonWidth = 100; | 
 |   59 const int kMaxMediaMenuButtonWidth = 600; | 
 |   60  | 
 |   61 } | 
 |   62  | 
|   45 using content::PluginService; |   63 using content::PluginService; | 
|   46 using content::WebContents; |   64 using content::WebContents; | 
|   47  |   65  | 
 |   66  | 
 |   67 // ContentSettingBubbleContents::Favicon -------------------------------------- | 
 |   68  | 
|   48 class ContentSettingBubbleContents::Favicon : public views::ImageView { |   69 class ContentSettingBubbleContents::Favicon : public views::ImageView { | 
|   49  public: |   70  public: | 
|   50   Favicon(const gfx::Image& image, |   71   Favicon(const gfx::Image& image, | 
|   51           ContentSettingBubbleContents* parent, |   72           ContentSettingBubbleContents* parent, | 
|   52           views::Link* link); |   73           views::Link* link); | 
|   53   virtual ~Favicon(); |   74   virtual ~Favicon(); | 
|   54  |   75  | 
|   55  private: |   76  private: | 
|   56   // views::View overrides: |   77   // views::View overrides: | 
|   57   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; |   78   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   90 gfx::NativeCursor ContentSettingBubbleContents::Favicon::GetCursor( |  111 gfx::NativeCursor ContentSettingBubbleContents::Favicon::GetCursor( | 
|   91     const ui::MouseEvent& event) { |  112     const ui::MouseEvent& event) { | 
|   92 #if defined(USE_AURA) |  113 #if defined(USE_AURA) | 
|   93   return ui::kCursorHand; |  114   return ui::kCursorHand; | 
|   94 #elif defined(OS_WIN) |  115 #elif defined(OS_WIN) | 
|   95   static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND); |  116   static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND); | 
|   96   return g_hand_cursor; |  117   return g_hand_cursor; | 
|   97 #endif |  118 #endif | 
|   98 } |  119 } | 
|   99  |  120  | 
 |  121  | 
 |  122 // ContentSettingBubbleContents::MediaMenuParts ------------------------------- | 
 |  123  | 
 |  124 struct ContentSettingBubbleContents::MediaMenuParts { | 
 |  125   explicit MediaMenuParts(content::MediaStreamType type); | 
 |  126   ~MediaMenuParts(); | 
 |  127  | 
 |  128   content::MediaStreamType type; | 
 |  129   scoped_ptr<ui::SimpleMenuModel> menu_model; | 
 |  130  | 
 |  131  private: | 
 |  132   DISALLOW_COPY_AND_ASSIGN(MediaMenuParts); | 
 |  133 }; | 
 |  134  | 
 |  135 ContentSettingBubbleContents::MediaMenuParts::MediaMenuParts( | 
 |  136     content::MediaStreamType type) | 
 |  137     : type(type) {} | 
 |  138  | 
 |  139 ContentSettingBubbleContents::MediaMenuParts::~MediaMenuParts() {} | 
 |  140  | 
 |  141  | 
 |  142 // ContentSettingBubbleContents ----------------------------------------------- | 
 |  143  | 
|  100 ContentSettingBubbleContents::ContentSettingBubbleContents( |  144 ContentSettingBubbleContents::ContentSettingBubbleContents( | 
|  101     ContentSettingBubbleModel* content_setting_bubble_model, |  145     ContentSettingBubbleModel* content_setting_bubble_model, | 
|  102     WebContents* web_contents, |  146     WebContents* web_contents, | 
|  103     views::View* anchor_view, |  147     views::View* anchor_view, | 
|  104     views::BubbleBorder::ArrowLocation arrow_location) |  148     views::BubbleBorder::ArrowLocation arrow_location) | 
|  105     : BubbleDelegateView(anchor_view, arrow_location), |  149     : BubbleDelegateView(anchor_view, arrow_location), | 
|  106       content_setting_bubble_model_(content_setting_bubble_model), |  150       content_setting_bubble_model_(content_setting_bubble_model), | 
|  107       web_contents_(web_contents), |  151       web_contents_(web_contents), | 
|  108       custom_link_(NULL), |  152       custom_link_(NULL), | 
|  109       manage_link_(NULL), |  153       manage_link_(NULL), | 
|  110       close_button_(NULL) { |  154       close_button_(NULL) { | 
|  111   // Compensate for built-in vertical padding in the anchor view's image. |  155   // Compensate for built-in vertical padding in the anchor view's image. | 
|  112   set_anchor_insets(gfx::Insets(5, 0, 5, 0)); |  156   set_anchor_insets(gfx::Insets(5, 0, 5, 0)); | 
|  113  |  157  | 
|  114   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |  158   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 
|  115                  content::Source<WebContents>(web_contents)); |  159                  content::Source<WebContents>(web_contents)); | 
|  116 } |  160 } | 
|  117  |  161  | 
|  118 ContentSettingBubbleContents::~ContentSettingBubbleContents() { |  162 ContentSettingBubbleContents::~ContentSettingBubbleContents() { | 
 |  163   STLDeleteValues(&media_menus_); | 
|  119 } |  164 } | 
|  120  |  165  | 
|  121 gfx::Size ContentSettingBubbleContents::GetPreferredSize() { |  166 gfx::Size ContentSettingBubbleContents::GetPreferredSize() { | 
|  122   gfx::Size preferred_size(views::View::GetPreferredSize()); |  167   gfx::Size preferred_size(views::View::GetPreferredSize()); | 
|  123   int preferred_width = |  168   int preferred_width = | 
|  124       (!content_setting_bubble_model_->bubble_content().domain_lists.empty() && |  169       (!content_setting_bubble_model_->bubble_content().domain_lists.empty() && | 
|  125        (kMinMultiLineContentsWidth > preferred_size.width())) ? |  170        (kMinMultiLineContentsWidth > preferred_size.width())) ? | 
|  126       kMinMultiLineContentsWidth : preferred_size.width(); |  171       kMinMultiLineContentsWidth : preferred_size.width(); | 
|  127   preferred_size.set_width(std::min(preferred_width, kMaxContentsWidth)); |  172   preferred_size.set_width(std::min(preferred_width, kMaxContentsWidth)); | 
|  128   return preferred_size; |  173   return preferred_size; | 
|  129 } |  174 } | 
|  130  |  175  | 
 |  176 void ContentSettingBubbleContents::UpdateMenuLabel( | 
 |  177     content::MediaStreamType type, | 
 |  178     const std::string& label) { | 
 |  179   for (MediaMenuPartsMap::const_iterator it = media_menus_.begin(); | 
 |  180        it != media_menus_.end(); ++it) { | 
 |  181     if (it->second->type == type) { | 
 |  182       it->first->SetText(UTF8ToUTF16(label)); | 
 |  183       return; | 
 |  184     } | 
 |  185   } | 
 |  186   NOTREACHED(); | 
 |  187 } | 
 |  188  | 
|  131 void ContentSettingBubbleContents::Init() { |  189 void ContentSettingBubbleContents::Init() { | 
|  132   using views::GridLayout; |  190   using views::GridLayout; | 
|  133  |  191  | 
|  134   GridLayout* layout = new views::GridLayout(this); |  192   GridLayout* layout = new views::GridLayout(this); | 
|  135   SetLayoutManager(layout); |  193   SetLayoutManager(layout); | 
|  136  |  194  | 
|  137   const int kSingleColumnSetId = 0; |  195   const int kSingleColumnSetId = 0; | 
|  138   views::ColumnSet* column_set = layout->AddColumnSet(kSingleColumnSetId); |  196   views::ColumnSet* column_set = layout->AddColumnSet(kSingleColumnSetId); | 
|  139   column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, |  197   column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, | 
|  140                         GridLayout::USE_PREF, 0, 0); |  198                         GridLayout::USE_PREF, 0, 0); | 
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  218       layout->StartRow(0, indented_kSingleColumnSetId); |  276       layout->StartRow(0, indented_kSingleColumnSetId); | 
|  219       layout->AddView(radio); |  277       layout->AddView(radio); | 
|  220       bubble_content_empty = false; |  278       bubble_content_empty = false; | 
|  221     } |  279     } | 
|  222     DCHECK(!radio_group_.empty()); |  280     DCHECK(!radio_group_.empty()); | 
|  223     // Now that the buttons have been added to the view hierarchy, it's safe |  281     // Now that the buttons have been added to the view hierarchy, it's safe | 
|  224     // to call SetChecked() on them. |  282     // to call SetChecked() on them. | 
|  225     radio_group_[radio_group.default_item]->SetChecked(true); |  283     radio_group_[radio_group.default_item]->SetChecked(true); | 
|  226   } |  284   } | 
|  227  |  285  | 
 |  286   // Layout code for the media device menus. | 
 |  287   if (content_setting_bubble_model_->content_type() == | 
 |  288       CONTENT_SETTINGS_TYPE_MEDIASTREAM) { | 
 |  289     const int kMediaMenuColumnSetId = 2; | 
 |  290     views::ColumnSet* menu_column_set = | 
 |  291         layout->AddColumnSet(kMediaMenuColumnSetId); | 
 |  292     menu_column_set->AddPaddingColumn( | 
 |  293         0, chrome_style::kCheckboxIndent); | 
 |  294     menu_column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0, | 
 |  295                                GridLayout::USE_PREF, 0, 0); | 
 |  296     menu_column_set->AddPaddingColumn( | 
 |  297         0, views::kRelatedControlHorizontalSpacing); | 
 |  298     menu_column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, | 
 |  299                                GridLayout::USE_PREF, 0, 0); | 
 |  300  | 
 |  301     int menu_width = 0; | 
 |  302     for (ContentSettingBubbleModel::MediaMenuMap::const_iterator i( | 
 |  303          bubble_content.media_menus.begin()); | 
 |  304          i != bubble_content.media_menus.end(); ++i) { | 
 |  305       if (!bubble_content_empty) | 
 |  306         layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | 
 |  307       layout->StartRow(0, kMediaMenuColumnSetId); | 
 |  308  | 
 |  309       views::Label* label = new views::Label(UTF8ToUTF16(i->second.label)); | 
 |  310       label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 
 |  311  | 
 |  312       views::MenuButton* menu_button = new views::MenuButton( | 
 |  313           NULL, UTF8ToUTF16((i->second.selected_device.name)), this, false); | 
 |  314       menu_button->set_alignment(views::TextButton::ALIGN_LEFT); | 
 |  315       menu_button->set_border( | 
 |  316           new views::TextButtonNativeThemeBorder(menu_button)); | 
 |  317       menu_button->set_animate_on_state_change(false); | 
 |  318  | 
 |  319       MediaMenuParts* menu_view = new MediaMenuParts(i->first); | 
 |  320       menu_view->menu_model.reset(new ContentSettingMediaMenuModel( | 
 |  321           i->first, | 
 |  322           content_setting_bubble_model_.get(), | 
 |  323           base::Bind(&ContentSettingBubbleContents::UpdateMenuLabel, | 
 |  324                      base::Unretained(this)))); | 
 |  325       media_menus_[menu_button] = menu_view; | 
 |  326  | 
 |  327       // Use the longest width of the menus as the width of the menu buttons. | 
 |  328       menu_width = std::max(menu_width, | 
 |  329                             GetPreferredMediaMenuWidth( | 
 |  330                                 menu_button, menu_view->menu_model.get())); | 
 |  331  | 
 |  332       layout->AddView(label); | 
 |  333       layout->AddView(menu_button); | 
 |  334  | 
 |  335       bubble_content_empty = false; | 
 |  336     } | 
 |  337  | 
 |  338     // Make sure the width is within [kMinMediaMenuButtonWidth, | 
 |  339     // kMaxMediaMenuButtonWidth]. | 
 |  340     menu_width = std::max(kMinMediaMenuButtonWidth, menu_width); | 
 |  341     menu_width = std::min(kMaxMediaMenuButtonWidth, menu_width); | 
 |  342  | 
 |  343     // Set all the menu buttons to the width we calculated above. | 
 |  344     for (MediaMenuPartsMap::const_iterator i = media_menus_.begin(); | 
 |  345          i != media_menus_.end(); ++i) { | 
 |  346       i->first->set_min_width(menu_width); | 
 |  347       i->first->set_max_width(menu_width); | 
 |  348     } | 
 |  349   } | 
 |  350  | 
|  228   gfx::Font domain_font = |  351   gfx::Font domain_font = | 
|  229       views::Label().font().DeriveFont(0, gfx::Font::BOLD); |  352       views::Label().font().DeriveFont(0, gfx::Font::BOLD); | 
|  230   for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i( |  353   for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i( | 
|  231        bubble_content.domain_lists.begin()); |  354        bubble_content.domain_lists.begin()); | 
|  232        i != bubble_content.domain_lists.end(); ++i) { |  355        i != bubble_content.domain_lists.end(); ++i) { | 
|  233     layout->StartRow(0, kSingleColumnSetId); |  356     layout->StartRow(0, kSingleColumnSetId); | 
|  234     views::Label* section_title = new views::Label(UTF8ToUTF16(i->title)); |  357     views::Label* section_title = new views::Label(UTF8ToUTF16(i->title)); | 
|  235     section_title->SetMultiLine(true); |  358     section_title->SetMultiLine(true); | 
|  236     section_title->SetHorizontalAlignment(gfx::ALIGN_LEFT); |  359     section_title->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 
|  237     layout->AddView(section_title, 1, 1, GridLayout::FILL, GridLayout::LEADING); |  360     layout->AddView(section_title, 1, 1, GridLayout::FILL, GridLayout::LEADING); | 
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  313     // CAREFUL: Showing the settings window activates it, which deactivates the |  436     // CAREFUL: Showing the settings window activates it, which deactivates the | 
|  314     // info bubble, which causes it to close, which deletes us. |  437     // info bubble, which causes it to close, which deletes us. | 
|  315     return; |  438     return; | 
|  316   } |  439   } | 
|  317  |  440  | 
|  318   PopupLinks::const_iterator i(popup_links_.find(source)); |  441   PopupLinks::const_iterator i(popup_links_.find(source)); | 
|  319   DCHECK(i != popup_links_.end()); |  442   DCHECK(i != popup_links_.end()); | 
|  320   content_setting_bubble_model_->OnPopupClicked(i->second); |  443   content_setting_bubble_model_->OnPopupClicked(i->second); | 
|  321 } |  444 } | 
|  322  |  445  | 
 |  446 void ContentSettingBubbleContents::OnMenuButtonClicked( | 
 |  447     views::View* source, | 
 |  448     const gfx::Point& point) { | 
 |  449   MediaMenuPartsMap::iterator i(media_menus_.find( | 
 |  450       static_cast<views::MenuButton*>(source))); | 
 |  451   DCHECK(i != media_menus_.end()); | 
 |  452  | 
 |  453   views::MenuModelAdapter menu_model_adapter(i->second->menu_model.get()); | 
 |  454   menu_runner_.reset(new views::MenuRunner(menu_model_adapter.CreateMenu())); | 
 |  455  | 
 |  456   gfx::Point screen_location; | 
 |  457   views::View::ConvertPointToScreen(i->first, &screen_location); | 
 |  458   ignore_result(menu_runner_->RunMenuAt( | 
 |  459       source->GetWidget(), | 
 |  460       i->first, | 
 |  461       gfx::Rect(screen_location, i->first->size()), | 
 |  462       views::MenuItemView::TOPLEFT, | 
 |  463       views::MenuRunner::HAS_MNEMONICS)); | 
 |  464 } | 
 |  465  | 
|  323 void ContentSettingBubbleContents::Observe( |  466 void ContentSettingBubbleContents::Observe( | 
|  324     int type, |  467     int type, | 
|  325     const content::NotificationSource& source, |  468     const content::NotificationSource& source, | 
|  326     const content::NotificationDetails& details) { |  469     const content::NotificationDetails& details) { | 
|  327   DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type); |  470   DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type); | 
|  328   DCHECK(source == content::Source<WebContents>(web_contents_)); |  471   DCHECK(source == content::Source<WebContents>(web_contents_)); | 
|  329   web_contents_ = NULL; |  472   web_contents_ = NULL; | 
|  330 } |  473 } | 
 |  474  | 
 |  475 int ContentSettingBubbleContents::GetPreferredMediaMenuWidth( | 
 |  476     views::MenuButton* button, | 
 |  477     ui::SimpleMenuModel* menu_model) { | 
 |  478   string16 title = button->text(); | 
 |  479  | 
 |  480   int width = button->GetPreferredSize().width(); | 
 |  481   for (int i = 0; i < menu_model->GetItemCount(); ++i) { | 
 |  482     button->SetText(menu_model->GetLabelAt(i)); | 
 |  483     width = std::max(width, button->GetPreferredSize().width()); | 
 |  484   } | 
 |  485  | 
 |  486   // Recover the title for the menu button. | 
 |  487   button->SetText(title); | 
 |  488   return width; | 
 |  489 } | 
| OLD | NEW |