Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: chrome/browser/ui/views/content_setting_bubble_contents.cc

Issue 1977673002: Make the combobox in ContentSettingBubbleContents an actual combobox. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix compile Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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" 12 #include "base/bind.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
16 #include "chrome/browser/plugins/plugin_finder.h" 17 #include "chrome/browser/plugins/plugin_finder.h"
17 #include "chrome/browser/plugins/plugin_metadata.h" 18 #include "chrome/browser/plugins/plugin_metadata.h"
18 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" 19 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
19 #include "chrome/browser/ui/content_settings/content_setting_media_menu_model.h"
20 #include "chrome/browser/ui/layout_constants.h" 20 #include "chrome/browser/ui/layout_constants.h"
21 #include "chrome/grit/generated_resources.h" 21 #include "chrome/grit/generated_resources.h"
22 #include "components/content_settings/core/browser/host_content_settings_map.h" 22 #include "components/content_settings/core/browser/host_content_settings_map.h"
23 #include "content/public/browser/plugin_service.h" 23 #include "content/public/browser/plugin_service.h"
24 #include "content/public/browser/web_contents.h" 24 #include "content/public/browser/web_contents.h"
25 #include "grit/components_strings.h" 25 #include "grit/components_strings.h"
26 #include "ui/base/cursor/cursor.h" 26 #include "ui/base/cursor/cursor.h"
27 #include "ui/base/l10n/l10n_util.h" 27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/models/simple_menu_model.h" 28 #include "ui/base/models/simple_menu_model.h"
29 #include "ui/base/resource/resource_bundle.h" 29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/font_list.h" 30 #include "ui/gfx/font_list.h"
31 #include "ui/gfx/text_utils.h" 31 #include "ui/gfx/text_utils.h"
32 #include "ui/views/controls/button/label_button.h" 32 #include "ui/views/controls/button/label_button.h"
33 #include "ui/views/controls/button/menu_button.h" 33 #include "ui/views/controls/button/menu_button.h"
34 #include "ui/views/controls/button/radio_button.h" 34 #include "ui/views/controls/button/radio_button.h"
35 #include "ui/views/controls/combobox/combobox.h"
35 #include "ui/views/controls/image_view.h" 36 #include "ui/views/controls/image_view.h"
36 #include "ui/views/controls/label.h" 37 #include "ui/views/controls/label.h"
37 #include "ui/views/controls/link.h" 38 #include "ui/views/controls/link.h"
38 #include "ui/views/controls/menu/menu_config.h" 39 #include "ui/views/controls/menu/menu_config.h"
39 #include "ui/views/controls/menu/menu_runner.h" 40 #include "ui/views/controls/menu/menu_runner.h"
40 #include "ui/views/controls/separator.h" 41 #include "ui/views/controls/separator.h"
41 #include "ui/views/layout/grid_layout.h" 42 #include "ui/views/layout/grid_layout.h"
42 #include "ui/views/layout/layout_constants.h" 43 #include "ui/views/layout/layout_constants.h"
43 #include "ui/views/native_cursor.h" 44 #include "ui/views/native_cursor.h"
44 45
45 namespace { 46 namespace {
46 47
47 // If we don't clamp the maximum width, then very long URLs and titles can make 48 // If we don't clamp the maximum width, then very long URLs and titles can make
48 // the bubble arbitrarily wide. 49 // the bubble arbitrarily wide.
49 const int kMaxContentsWidth = 500; 50 const int kMaxContentsWidth = 500;
50 51
51 // When we have multiline labels, we should set a minimum width lest we get very 52 // When we have multiline labels, we should set a minimum width lest we get very
52 // narrow bubbles with lots of line-wrapping. 53 // narrow bubbles with lots of line-wrapping.
53 const int kMinMultiLineContentsWidth = 250; 54 const int kMinMultiLineContentsWidth = 250;
54 55
55 // The minimum width of the media menu buttons.
56 const int kMinMediaMenuButtonWidth = 150;
57
58 } // namespace 56 } // namespace
59 57
60 using content::PluginService; 58 using content::PluginService;
61 using content::WebContents; 59 using content::WebContents;
62 60
61 // ContentSettingBubbleContents::MediaComboboxModel ----------------------------
62
63 ContentSettingBubbleContents::MediaComboboxModel::MediaComboboxModel(
64 content::MediaStreamType type)
65 : type_(type) {
66 DCHECK(type_ == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
67 type_ == content::MEDIA_DEVICE_VIDEO_CAPTURE);
68 }
69
70 ContentSettingBubbleContents::MediaComboboxModel::~MediaComboboxModel() {}
71
72 const content::MediaStreamDevices&
73 ContentSettingBubbleContents::MediaComboboxModel::GetDevices() const {
74 MediaCaptureDevicesDispatcher* dispatcher =
75 MediaCaptureDevicesDispatcher::GetInstance();
76 return type_ == content::MEDIA_DEVICE_AUDIO_CAPTURE
77 ? dispatcher->GetAudioCaptureDevices()
78 : dispatcher->GetVideoCaptureDevices();
79 }
80
81 int ContentSettingBubbleContents::MediaComboboxModel::GetDeviceIndex(
82 const content::MediaStreamDevice& device) const {
83 const auto& devices = GetDevices();
84 for (size_t i = 0; i < devices.size(); ++i) {
85 if (device.id == devices[i].id)
86 return i;
87 }
88 NOTREACHED();
89 return 0;
90 }
91
92 int ContentSettingBubbleContents::MediaComboboxModel::GetItemCount() const {
93 return std::max(1, static_cast<int>(GetDevices().size()));
94 }
95
96 base::string16 ContentSettingBubbleContents::MediaComboboxModel::GetItemAt(
97 int index) {
98 return GetDevices().empty()
99 ? l10n_util::GetStringUTF16(IDS_MEDIA_MENU_NO_DEVICE_TITLE)
100 : base::UTF8ToUTF16(GetDevices()[index].name);
101 }
63 102
64 // ContentSettingBubbleContents::Favicon -------------------------------------- 103 // ContentSettingBubbleContents::Favicon --------------------------------------
65 104
66 class ContentSettingBubbleContents::Favicon : public views::ImageView { 105 class ContentSettingBubbleContents::Favicon : public views::ImageView {
67 public: 106 public:
68 Favicon(const gfx::Image& image, 107 Favicon(const gfx::Image& image,
69 ContentSettingBubbleContents* parent, 108 ContentSettingBubbleContents* parent,
70 views::Link* link); 109 views::Link* link);
71 ~Favicon() override; 110 ~Favicon() override;
72 111
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 parent_->LinkClicked(link_, event.flags()); 143 parent_->LinkClicked(link_, event.flags());
105 } 144 }
106 } 145 }
107 146
108 gfx::NativeCursor ContentSettingBubbleContents::Favicon::GetCursor( 147 gfx::NativeCursor ContentSettingBubbleContents::Favicon::GetCursor(
109 const ui::MouseEvent& event) { 148 const ui::MouseEvent& event) {
110 return views::GetNativeHandCursor(); 149 return views::GetNativeHandCursor();
111 } 150 }
112 151
113 152
114 // ContentSettingBubbleContents::MediaMenuParts -------------------------------
115
116 struct ContentSettingBubbleContents::MediaMenuParts {
117 explicit MediaMenuParts(content::MediaStreamType type);
118 ~MediaMenuParts();
119
120 content::MediaStreamType type;
121 std::unique_ptr<ui::SimpleMenuModel> menu_model;
122
123 private:
124 DISALLOW_COPY_AND_ASSIGN(MediaMenuParts);
125 };
126
127 ContentSettingBubbleContents::MediaMenuParts::MediaMenuParts(
128 content::MediaStreamType type)
129 : type(type) {}
130
131 ContentSettingBubbleContents::MediaMenuParts::~MediaMenuParts() {}
132
133 // ContentSettingBubbleContents ----------------------------------------------- 153 // ContentSettingBubbleContents -----------------------------------------------
134 154
135 ContentSettingBubbleContents::ContentSettingBubbleContents( 155 ContentSettingBubbleContents::ContentSettingBubbleContents(
136 ContentSettingBubbleModel* content_setting_bubble_model, 156 ContentSettingBubbleModel* content_setting_bubble_model,
137 content::WebContents* web_contents, 157 content::WebContents* web_contents,
138 views::View* anchor_view, 158 views::View* anchor_view,
139 views::BubbleBorder::Arrow arrow) 159 views::BubbleBorder::Arrow arrow)
140 : content::WebContentsObserver(web_contents), 160 : content::WebContentsObserver(web_contents),
141 BubbleDialogDelegateView(anchor_view, arrow), 161 BubbleDialogDelegateView(anchor_view, arrow),
142 content_setting_bubble_model_(content_setting_bubble_model), 162 content_setting_bubble_model_(content_setting_bubble_model),
143 custom_link_(NULL), 163 custom_link_(NULL),
144 manage_link_(NULL), 164 manage_link_(NULL),
145 learn_more_link_(NULL), 165 learn_more_link_(NULL),
146 close_button_(NULL) { 166 close_button_(NULL) {
147 // Compensate for built-in vertical padding in the anchor view's image. 167 // Compensate for built-in vertical padding in the anchor view's image.
148 set_anchor_view_insets(gfx::Insets( 168 set_anchor_view_insets(gfx::Insets(
149 GetLayoutConstant(LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET), 0)); 169 GetLayoutConstant(LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET), 0));
150 } 170 }
151 171
152 ContentSettingBubbleContents::~ContentSettingBubbleContents() { 172 ContentSettingBubbleContents::~ContentSettingBubbleContents() {
153 STLDeleteValues(&media_menus_); 173 // Must remove the children here so the comboboxes get destroyed before
174 // their associated models.
175 RemoveAllChildViews(true);
154 } 176 }
155 177
156 gfx::Size ContentSettingBubbleContents::GetPreferredSize() const { 178 gfx::Size ContentSettingBubbleContents::GetPreferredSize() const {
157 gfx::Size preferred_size(views::View::GetPreferredSize()); 179 gfx::Size preferred_size(views::View::GetPreferredSize());
158 int preferred_width = 180 int preferred_width =
159 (!content_setting_bubble_model_->bubble_content().domain_lists.empty() && 181 (!content_setting_bubble_model_->bubble_content().domain_lists.empty() &&
160 (kMinMultiLineContentsWidth > preferred_size.width())) 182 (kMinMultiLineContentsWidth > preferred_size.width()))
161 ? kMinMultiLineContentsWidth 183 ? kMinMultiLineContentsWidth
162 : preferred_size.width(); 184 : preferred_size.width();
163 preferred_size.set_width(std::min(preferred_width, kMaxContentsWidth)); 185 preferred_size.set_width(std::min(preferred_width, kMaxContentsWidth));
164 return preferred_size; 186 return preferred_size;
165 } 187 }
166 188
167 void ContentSettingBubbleContents::UpdateMenuLabel(
168 content::MediaStreamType type,
169 const std::string& label) {
170 for (MediaMenuPartsMap::const_iterator it = media_menus_.begin();
171 it != media_menus_.end(); ++it) {
172 if (it->second->type == type) {
173 it->first->SetText(base::UTF8ToUTF16(label));
174 it->first->Layout();
175 return;
176 }
177 }
178 NOTREACHED();
179 }
180
181 void ContentSettingBubbleContents::Init() { 189 void ContentSettingBubbleContents::Init() {
182 using views::GridLayout; 190 using views::GridLayout;
183 191
184 GridLayout* layout = new views::GridLayout(this); 192 GridLayout* layout = new views::GridLayout(this);
185 SetLayoutManager(layout); 193 SetLayoutManager(layout);
186 194
187 const int kSingleColumnSetId = 0; 195 const int kSingleColumnSetId = 0;
188 views::ColumnSet* column_set = layout->AddColumnSet(kSingleColumnSetId); 196 views::ColumnSet* column_set = layout->AddColumnSet(kSingleColumnSetId);
189 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, 197 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
190 GridLayout::USE_PREF, 0, 0); 198 GridLayout::USE_PREF, 0, 0);
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 for (ContentSettingBubbleModel::MediaMenuMap::const_iterator i( 306 for (ContentSettingBubbleModel::MediaMenuMap::const_iterator i(
299 bubble_content.media_menus.begin()); 307 bubble_content.media_menus.begin());
300 i != bubble_content.media_menus.end(); ++i) { 308 i != bubble_content.media_menus.end(); ++i) {
301 if (!bubble_content_empty) 309 if (!bubble_content_empty)
302 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 310 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
303 layout->StartRow(0, kMediaMenuColumnSetId); 311 layout->StartRow(0, kMediaMenuColumnSetId);
304 312
305 views::Label* label = 313 views::Label* label =
306 new views::Label(base::UTF8ToUTF16(i->second.label)); 314 new views::Label(base::UTF8ToUTF16(i->second.label));
307 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 315 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
316 layout->AddView(label);
308 317
309 views::MenuButton* menu_button = new views::MenuButton( 318 combobox_models_.emplace_back(i->first);
310 base::UTF8ToUTF16((i->second.selected_device.name)), this, true); 319 MediaComboboxModel* model = &combobox_models_.back();
311 menu_button->SetStyle(views::Button::STYLE_BUTTON); 320 views::Combobox* combobox = new views::Combobox(model);
312 menu_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
313 menu_button->set_animate_on_state_change(false);
314
315 MediaMenuParts* menu_view = new MediaMenuParts(i->first);
316 menu_view->menu_model.reset(new ContentSettingMediaMenuModel(
317 i->first,
318 content_setting_bubble_model_.get(),
319 base::Bind(&ContentSettingBubbleContents::UpdateMenuLabel,
320 base::Unretained(this))));
321 media_menus_[menu_button] = menu_view;
322
323 if (!menu_view->menu_model->GetItemCount()) {
324 // Show a "None available" title and grey out the menu when there are
325 // no available devices.
326 menu_button->SetText(
327 l10n_util::GetStringUTF16(IDS_MEDIA_MENU_NO_DEVICE_TITLE));
328 menu_button->SetEnabled(false);
329 }
330
331 // Disable the device selection when the website is managing the devices 321 // Disable the device selection when the website is managing the devices
332 // itself. 322 // itself or if there are no devices present.
333 if (i->second.disabled) 323 combobox->SetEnabled(
334 menu_button->SetEnabled(false); 324 !(i->second.disabled || model->GetDevices().empty()));
335 325 combobox->set_listener(this);
336 layout->AddView(label); 326 combobox->SetSelectedIndex(
337 layout->AddView(menu_button); 327 model->GetDeviceIndex(i->second.selected_device));
328 layout->AddView(combobox);
338 329
339 bubble_content_empty = false; 330 bubble_content_empty = false;
340 } 331 }
341 } 332 }
342 333
343 UpdateMenuButtonSizes();
344
345 const gfx::FontList& domain_font = 334 const gfx::FontList& domain_font =
346 ui::ResourceBundle::GetSharedInstance().GetFontList( 335 ui::ResourceBundle::GetSharedInstance().GetFontList(
347 ui::ResourceBundle::BoldFont); 336 ui::ResourceBundle::BoldFont);
348 for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i( 337 for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i(
349 bubble_content.domain_lists.begin()); 338 bubble_content.domain_lists.begin());
350 i != bubble_content.domain_lists.end(); ++i) { 339 i != bubble_content.domain_lists.end(); ++i) {
351 layout->StartRow(0, kSingleColumnSetId); 340 layout->StartRow(0, kSingleColumnSetId);
352 views::Label* section_title = new views::Label(base::UTF8ToUTF16(i->title)); 341 views::Label* section_title = new views::Label(base::UTF8ToUTF16(i->title));
353 section_title->SetMultiLine(true); 342 section_title->SetMultiLine(true);
354 section_title->SetHorizontalAlignment(gfx::ALIGN_LEFT); 343 section_title->SetHorizontalAlignment(gfx::ALIGN_LEFT);
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 // CAREFUL: Showing the settings window activates it, which deactivates the 427 // CAREFUL: Showing the settings window activates it, which deactivates the
439 // info bubble, which causes it to close, which deletes us. 428 // info bubble, which causes it to close, which deletes us.
440 return; 429 return;
441 } 430 }
442 431
443 ListItemLinks::const_iterator i(list_item_links_.find(source)); 432 ListItemLinks::const_iterator i(list_item_links_.find(source));
444 DCHECK(i != list_item_links_.end()); 433 DCHECK(i != list_item_links_.end());
445 content_setting_bubble_model_->OnListItemClicked(i->second); 434 content_setting_bubble_model_->OnListItemClicked(i->second);
446 } 435 }
447 436
448 void ContentSettingBubbleContents::OnMenuButtonClicked( 437 void ContentSettingBubbleContents::OnPerformAction(views::Combobox* combobox) {
449 views::MenuButton* source, 438 MediaComboboxModel* model =
450 const gfx::Point& point, 439 static_cast<MediaComboboxModel*>(combobox->model());
451 const ui::Event* event) { 440 content_setting_bubble_model_->OnMediaMenuClicked(
452 MediaMenuPartsMap::iterator j( 441 model->type(), model->GetDevices()[combobox->selected_index()].id);
453 media_menus_.find(static_cast<views::MenuButton*>(source)));
454 DCHECK(j != media_menus_.end());
455 menu_runner_.reset(new views::MenuRunner(j->second->menu_model.get(),
456 views::MenuRunner::HAS_MNEMONICS));
457
458 gfx::Point screen_location;
459 views::View::ConvertPointToScreen(j->first, &screen_location);
460 ignore_result(menu_runner_->RunMenuAt(
461 source->GetWidget(), j->first,
462 gfx::Rect(screen_location, j->first->size()), views::MENU_ANCHOR_TOPLEFT,
463 ui::MENU_SOURCE_NONE));
464 } 442 }
465
466 void ContentSettingBubbleContents::UpdateMenuButtonSizes() {
467 const views::MenuConfig& config = views::MenuConfig::instance();
468 const int margins = config.item_left_margin + config.check_width +
469 config.label_to_arrow_padding + config.arrow_width +
470 config.arrow_to_edge_padding;
471
472 // The preferred media menu size sort of copies the logic in
473 // MenuItemView::CalculateDimensions(). When this was using TextButton, it
474 // completely coincidentally matched the logic in MenuItemView. We now need
475 // to redo this manually.
476 int menu_width = 0;
477 for (MediaMenuPartsMap::const_iterator i = media_menus_.begin();
478 i != media_menus_.end(); ++i) {
479 for (int j = 0; j < i->second->menu_model->GetItemCount(); ++j) {
480 int string_width = gfx::GetStringWidth(
481 i->second->menu_model->GetLabelAt(j),
482 config.font_list);
483
484 menu_width = std::max(menu_width, string_width);
485 }
486 }
487
488 // Make sure the width is at least kMinMediaMenuButtonWidth. The
489 // maximum width will be clamped by kMaxContentsWidth of the view.
490 menu_width = std::max(kMinMediaMenuButtonWidth, menu_width + margins);
491
492 for (MediaMenuPartsMap::const_iterator i = media_menus_.begin();
493 i != media_menus_.end(); ++i) {
494 i->first->SetMinSize(gfx::Size(menu_width, 0));
495 i->first->SetMaxSize(gfx::Size(menu_width, 0));
496 }
497 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/content_setting_bubble_contents.h ('k') | chrome/chrome_browser_ui.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698