Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / content_settings / content_setting_bubble_model.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/content_settings/content_setting_bubble_model.h"
6
7 #include "base/command_line.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/content_settings/content_settings_utils.h"
12 #include "chrome/browser/content_settings/cookie_settings.h"
13 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
14 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
15 #include "chrome/browser/favicon/favicon_tab_helper.h"
16 #include "chrome/browser/infobars/infobar_service.h"
17 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
18 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
21 #include "chrome/browser/ui/browser_navigator.h"
22 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
23 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
24 #include "chrome/browser/ui/content_settings/media_setting_changed_infobar_delegate.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/common/render_messages.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "components/content_settings/core/common/content_settings.h"
30 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/render_frame_host.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/render_view_host.h"
34 #include "content/public/browser/user_metrics.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/browser/web_contents_delegate.h"
37 #include "grit/components_strings.h"
38 #include "net/base/net_util.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/resources/grit/ui_resources.h"
42
43 using base::UserMetricsAction;
44 using content::WebContents;
45 using content_settings::SettingInfo;
46 using content_settings::SettingSource;
47 using content_settings::SETTING_SOURCE_USER;
48 using content_settings::SETTING_SOURCE_NONE;
49
50 namespace {
51
52 const int kAllowButtonIndex = 0;
53
54 struct ContentSettingsTypeIdEntry {
55   ContentSettingsType type;
56   int id;
57 };
58
59 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
60                         size_t num_entries,
61                         ContentSettingsType type) {
62   for (size_t i = 0; i < num_entries; ++i) {
63     if (entries[i].type == type)
64       return entries[i].id;
65   }
66   return 0;
67 }
68
69 const content::MediaStreamDevice& GetMediaDeviceById(
70     const std::string& device_id,
71     const content::MediaStreamDevices& devices) {
72   DCHECK(!devices.empty());
73   for (content::MediaStreamDevices::const_iterator it = devices.begin();
74        it != devices.end(); ++it) {
75     if (it->id == device_id)
76       return *(it);
77   }
78
79   // A device with the |device_id| was not found. It is likely that the device
80   // has been unplugged from the OS. Return the first device as the default
81   // device.
82   return *devices.begin();
83 }
84
85 }  // namespace
86
87 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel(
88     Delegate* delegate,
89     WebContents* web_contents,
90     Profile* profile,
91     ContentSettingsType content_type)
92     : ContentSettingBubbleModel(web_contents, profile, content_type),
93         delegate_(delegate) {
94   // Notifications do not have a bubble.
95   DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
96   SetTitle();
97   SetManageLink();
98   SetLearnMoreLink();
99 }
100
101 void ContentSettingTitleAndLinkModel::SetTitle() {
102   static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = {
103     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE},
104     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE},
105     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE},
106     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE},
107     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE},
108     {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
109         IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
110     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
111         IDS_BLOCKED_PPAPI_BROKER_TITLE},
112     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE},
113   };
114   // Fields as for kBlockedTitleIDs, above.
115   static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = {
116     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
117     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
118     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE},
119   };
120   const ContentSettingsTypeIdEntry *title_ids = kBlockedTitleIDs;
121   size_t num_title_ids = arraysize(kBlockedTitleIDs);
122   if (web_contents() &&
123       TabSpecificContentSettings::FromWebContents(
124           web_contents())->IsContentAllowed(content_type()) &&
125       !TabSpecificContentSettings::FromWebContents(
126           web_contents())->IsContentBlocked(content_type())) {
127     title_ids = kAccessedTitleIDs;
128     num_title_ids = arraysize(kAccessedTitleIDs);
129   }
130   int title_id =
131       GetIdForContentType(title_ids, num_title_ids, content_type());
132   if (title_id)
133     set_title(l10n_util::GetStringUTF8(title_id));
134 }
135
136 void ContentSettingTitleAndLinkModel::SetManageLink() {
137   static const ContentSettingsTypeIdEntry kLinkIDs[] = {
138     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_LINK},
139     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_LINK},
140     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK},
141     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK},
142     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK},
143     {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK},
144     {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_LEARN_MORE},
145     {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, IDS_HANDLERS_BUBBLE_MANAGE_LINK},
146     {CONTENT_SETTINGS_TYPE_MEDIASTREAM, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK},
147     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK},
148     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOADS_LINK},
149     {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK},
150   };
151   set_manage_link(l10n_util::GetStringUTF8(
152       GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type())));
153 }
154
155 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() {
156   if (delegate_)
157     delegate_->ShowContentSettingsPage(content_type());
158 }
159
160 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() {
161   static const ContentSettingsTypeIdEntry kLearnMoreIDs[] = {
162     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_LEARN_MORE},
163   };
164   int learn_more_id =
165       GetIdForContentType(kLearnMoreIDs, arraysize(kLearnMoreIDs),
166                           content_type());
167   if (learn_more_id)
168     set_learn_more_link(l10n_util::GetStringUTF8(learn_more_id));
169 }
170
171 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() {
172   if (delegate_)
173     delegate_->ShowLearnMorePage(content_type());
174 }
175
176 class ContentSettingTitleLinkAndCustomModel
177     : public ContentSettingTitleAndLinkModel {
178  public:
179   ContentSettingTitleLinkAndCustomModel(Delegate* delegate,
180                                         WebContents* web_contents,
181                                         Profile* profile,
182                                         ContentSettingsType content_type);
183   virtual ~ContentSettingTitleLinkAndCustomModel() {}
184
185  private:
186   void SetCustomLink();
187   virtual void OnCustomLinkClicked() OVERRIDE {}
188 };
189
190 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel(
191     Delegate* delegate,
192     WebContents* web_contents,
193     Profile* profile,
194     ContentSettingsType content_type)
195     : ContentSettingTitleAndLinkModel(
196           delegate, web_contents, profile, content_type) {
197   SetCustomLink();
198 }
199
200 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() {
201   static const ContentSettingsTypeIdEntry kCustomIDs[] = {
202     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO},
203     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL},
204     {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON},
205   };
206   int custom_link_id =
207       GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type());
208   if (custom_link_id)
209     set_custom_link(l10n_util::GetStringUTF8(custom_link_id));
210 }
211
212 class ContentSettingSingleRadioGroup
213     : public ContentSettingTitleLinkAndCustomModel {
214  public:
215   ContentSettingSingleRadioGroup(Delegate* delegate,
216                                  WebContents* web_contents,
217                                  Profile* profile,
218                                  ContentSettingsType content_type);
219   virtual ~ContentSettingSingleRadioGroup();
220
221  protected:
222   bool settings_changed() const;
223   int selected_item() const { return selected_item_; }
224
225  private:
226   void SetRadioGroup();
227   void AddException(ContentSetting setting);
228   virtual void OnRadioClicked(int radio_index) OVERRIDE;
229
230   ContentSetting block_setting_;
231   int selected_item_;
232 };
233
234 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup(
235     Delegate* delegate,
236     WebContents* web_contents,
237     Profile* profile,
238     ContentSettingsType content_type)
239     : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile,
240                                             content_type),
241       block_setting_(CONTENT_SETTING_BLOCK),
242       selected_item_(0) {
243   SetRadioGroup();
244 }
245
246 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() {
247   if (settings_changed()) {
248     ContentSetting setting =
249         selected_item_ == kAllowButtonIndex ?
250                           CONTENT_SETTING_ALLOW :
251                           block_setting_;
252     AddException(setting);
253   }
254 }
255
256 bool ContentSettingSingleRadioGroup::settings_changed() const {
257   return selected_item_ != bubble_content().radio_group.default_item;
258 }
259
260 // Initialize the radio group by setting the appropriate labels for the
261 // content type and setting the default value based on the content setting.
262 void ContentSettingSingleRadioGroup::SetRadioGroup() {
263   GURL url = web_contents()->GetURL();
264   base::string16 display_host;
265   net::AppendFormattedHost(
266       url,
267       profile()->GetPrefs()->GetString(prefs::kAcceptLanguages),
268       &display_host);
269
270   if (display_host.empty())
271     display_host = base::ASCIIToUTF16(url.spec());
272
273   TabSpecificContentSettings* content_settings =
274       TabSpecificContentSettings::FromWebContents(web_contents());
275   bool allowed =
276       !content_settings->IsContentBlocked(content_type());
277   DCHECK(!allowed ||
278          content_settings->IsContentAllowed(content_type()));
279
280   RadioGroup radio_group;
281   radio_group.url = url;
282
283   static const ContentSettingsTypeIdEntry kBlockedAllowIDs[] = {
284     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
285     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK},
286     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK},
287     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL},
288     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK},
289     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK},
290     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_UNBLOCK},
291   };
292   // Fields as for kBlockedAllowIDs, above.
293   static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = {
294     // TODO(bauerb): The string shouldn't be "unblock" (they weren't blocked).
295     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
296     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION},
297     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION},
298   };
299
300   std::string radio_allow_label;
301   if (allowed) {
302     int resource_id = GetIdForContentType(kAllowedAllowIDs,
303                                           arraysize(kAllowedAllowIDs),
304                                           content_type());
305     radio_allow_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ?
306         l10n_util::GetStringFUTF8(resource_id, display_host) :
307         l10n_util::GetStringUTF8(resource_id);
308   } else {
309     radio_allow_label = l10n_util::GetStringFUTF8(
310         GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs),
311                             content_type()),
312         display_host);
313   }
314
315   static const ContentSettingsTypeIdEntry kBlockedBlockIDs[] = {
316     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
317     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION},
318     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION},
319     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_NO_ACTION},
320     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION},
321     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION},
322     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION},
323   };
324   static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = {
325     // TODO(bauerb): The string should say "block".
326     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
327     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK},
328     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK},
329   };
330
331   std::string radio_block_label;
332   if (allowed) {
333     int resource_id = GetIdForContentType(kAllowedBlockIDs,
334                                           arraysize(kAllowedBlockIDs),
335                                           content_type());
336     radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ?
337         l10n_util::GetStringUTF8(resource_id) :
338         l10n_util::GetStringFUTF8(resource_id, display_host);
339   } else {
340     radio_block_label = l10n_util::GetStringUTF8(
341         GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs),
342                             content_type()));
343   }
344
345   radio_group.radio_items.push_back(radio_allow_label);
346   radio_group.radio_items.push_back(radio_block_label);
347   ContentSetting setting;
348   SettingSource setting_source = SETTING_SOURCE_NONE;
349   bool setting_is_wildcard = false;
350
351   if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) {
352     CookieSettings* cookie_settings =
353         CookieSettings::Factory::GetForProfile(profile()).get();
354     setting = cookie_settings->GetCookieSetting(
355         url, url, true, &setting_source);
356   } else {
357     SettingInfo info;
358     HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
359     scoped_ptr<base::Value> value =
360         map->GetWebsiteSetting(url, url, content_type(), std::string(), &info);
361     setting = content_settings::ValueToContentSetting(value.get());
362     setting_source = info.source;
363     setting_is_wildcard =
364         info.primary_pattern == ContentSettingsPattern::Wildcard() &&
365         info.secondary_pattern == ContentSettingsPattern::Wildcard();
366   }
367
368   if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS &&
369       setting == CONTENT_SETTING_ALLOW &&
370       setting_is_wildcard) {
371     // In the corner case of unrecognized plugins (which are now blocked by
372     // default) we indicate the blocked state in the UI and allow the user to
373     // whitelist.
374     radio_group.default_item = 1;
375   } else if (setting == CONTENT_SETTING_ALLOW) {
376     radio_group.default_item = kAllowButtonIndex;
377     // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|.
378   } else {
379     radio_group.default_item = 1;
380     block_setting_ = setting;
381   }
382
383   set_setting_is_managed(setting_source != SETTING_SOURCE_USER);
384   if (setting_source != SETTING_SOURCE_USER) {
385     set_radio_group_enabled(false);
386   } else {
387     set_radio_group_enabled(true);
388   }
389   selected_item_ = radio_group.default_item;
390   set_radio_group(radio_group);
391 }
392
393 void ContentSettingSingleRadioGroup::AddException(ContentSetting setting) {
394   if (profile()) {
395     profile()->GetHostContentSettingsMap()->AddExceptionForURL(
396         bubble_content().radio_group.url,
397         bubble_content().radio_group.url,
398         content_type(),
399         setting);
400   }
401 }
402
403 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) {
404   selected_item_ = radio_index;
405 }
406
407 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup {
408  public:
409   ContentSettingCookiesBubbleModel(Delegate* delegate,
410                                    WebContents* web_contents,
411                                    Profile* profile,
412                                    ContentSettingsType content_type);
413
414   virtual ~ContentSettingCookiesBubbleModel();
415
416  private:
417   virtual void OnCustomLinkClicked() OVERRIDE;
418 };
419
420 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel(
421     Delegate* delegate,
422     WebContents* web_contents,
423     Profile* profile,
424     ContentSettingsType content_type)
425     : ContentSettingSingleRadioGroup(
426           delegate, web_contents, profile, content_type) {
427   DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type);
428   set_custom_link_enabled(true);
429 }
430
431 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() {
432   // On some plattforms e.g. MacOS X it is possible to close a tab while the
433   // cookies settings bubble is open. This resets the web contents to NULL.
434   if (settings_changed() && web_contents()) {
435     CollectedCookiesInfoBarDelegate::Create(
436         InfoBarService::FromWebContents(web_contents()));
437   }
438 }
439
440 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() {
441   if (!web_contents())
442     return;
443   content::NotificationService::current()->Notify(
444       chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
445       content::Source<TabSpecificContentSettings>(
446           TabSpecificContentSettings::FromWebContents(web_contents())),
447       content::NotificationService::NoDetails());
448   delegate()->ShowCollectedCookiesDialog(web_contents());
449 }
450
451 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
452  public:
453   ContentSettingPluginBubbleModel(Delegate* delegate,
454                                   WebContents* web_contents,
455                                   Profile* profile,
456                                   ContentSettingsType content_type);
457
458   virtual ~ContentSettingPluginBubbleModel();
459
460  private:
461   virtual void OnCustomLinkClicked() OVERRIDE;
462 };
463
464 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel(
465     Delegate* delegate,
466     WebContents* web_contents,
467     Profile* profile,
468     ContentSettingsType content_type)
469     : ContentSettingSingleRadioGroup(
470           delegate, web_contents, profile, content_type) {
471   DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS);
472   // Disable the "Run all plugins this time" link if the setting is managed and
473   // can't be controlled by the user or if the user already clicked on the link
474   // and ran all plugins.
475   set_custom_link_enabled(!setting_is_managed() &&
476                           web_contents &&
477                           TabSpecificContentSettings::FromWebContents(
478                               web_contents)->load_plugins_link_enabled());
479 }
480
481 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() {
482   if (settings_changed()) {
483     // If the user elected to allow all plugins then run plugins at this time.
484     if (selected_item() == kAllowButtonIndex)
485       OnCustomLinkClicked();
486   }
487 }
488
489 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() {
490   content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
491   DCHECK(web_contents());
492 #if defined(ENABLE_PLUGINS)
493   // TODO(bauerb): We should send the identifiers of blocked plug-ins here.
494   ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
495       web_contents(), true, std::string());
496 #endif
497   set_custom_link_enabled(false);
498   TabSpecificContentSettings::FromWebContents(web_contents())->
499       set_load_plugins_link_enabled(false);
500 }
501
502 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
503  public:
504   ContentSettingPopupBubbleModel(Delegate* delegate,
505                                  WebContents* web_contents,
506                                  Profile* profile,
507                                  ContentSettingsType content_type);
508   virtual ~ContentSettingPopupBubbleModel() {}
509
510  private:
511   void SetPopups();
512   virtual void OnPopupClicked(int index) OVERRIDE;
513 };
514
515 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel(
516     Delegate* delegate,
517     WebContents* web_contents,
518     Profile* profile,
519     ContentSettingsType content_type)
520     : ContentSettingSingleRadioGroup(
521         delegate, web_contents, profile, content_type) {
522   SetPopups();
523 }
524
525
526 void ContentSettingPopupBubbleModel::SetPopups() {
527   std::map<int32, GURL> blocked_popups =
528       PopupBlockerTabHelper::FromWebContents(web_contents())
529           ->GetBlockedPopupRequests();
530   for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin();
531        iter != blocked_popups.end();
532        ++iter) {
533     std::string title(iter->second.spec());
534     // The popup may not have a valid URL.
535     if (title.empty())
536       title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
537     PopupItem popup_item(
538         ui::ResourceBundle::GetSharedInstance().GetImageNamed(
539             IDR_DEFAULT_FAVICON),
540         title,
541         iter->first);
542     add_popup(popup_item);
543   }
544 }
545
546 void ContentSettingPopupBubbleModel::OnPopupClicked(int index) {
547   if (web_contents()) {
548     PopupBlockerTabHelper::FromWebContents(web_contents())->
549         ShowBlockedPopup(bubble_content().popup_items[index].popup_id);
550   }
551 }
552
553 // The model of the content settings bubble for media settings.
554 class ContentSettingMediaStreamBubbleModel
555     : public ContentSettingTitleAndLinkModel {
556  public:
557   ContentSettingMediaStreamBubbleModel(Delegate* delegate,
558                                        WebContents* web_contents,
559                                        Profile* profile);
560
561   virtual ~ContentSettingMediaStreamBubbleModel();
562
563  private:
564   void SetTitle();
565   // Sets the data for the radio buttons of the bubble.
566   void SetRadioGroup();
567   // Sets the data for the media menus of the bubble.
568   void SetMediaMenus();
569   // Updates the camera and microphone setting with the passed |setting|.
570   void UpdateSettings(ContentSetting setting);
571   // Updates the camera and microphone default device with the passed |type|
572   // and device.
573   void UpdateDefaultDeviceForType(content::MediaStreamType type,
574                                   const std::string& device);
575
576   // ContentSettingBubbleModel implementation.
577   virtual void OnRadioClicked(int radio_index) OVERRIDE;
578   virtual void OnMediaMenuClicked(content::MediaStreamType type,
579                                   const std::string& selected_device) OVERRIDE;
580
581   // The index of the selected radio item.
582   int selected_item_;
583   // The content settings that are associated with the individual radio
584   // buttons.
585   ContentSetting radio_item_setting_[2];
586   // The state of the microphone and camera access.
587   TabSpecificContentSettings::MicrophoneCameraState state_;
588 };
589
590 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel(
591     Delegate* delegate,
592     WebContents* web_contents,
593     Profile* profile)
594     : ContentSettingTitleAndLinkModel(
595           delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM),
596       selected_item_(0),
597       state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED) {
598   DCHECK(profile);
599   // Initialize the content settings associated with the individual radio
600   // buttons.
601   radio_item_setting_[0] = CONTENT_SETTING_ASK;
602   radio_item_setting_[1] = CONTENT_SETTING_BLOCK;
603
604   TabSpecificContentSettings* content_settings =
605       TabSpecificContentSettings::FromWebContents(web_contents);
606   state_ = content_settings->GetMicrophoneCameraState();
607
608   SetTitle();
609   SetRadioGroup();
610   SetMediaMenus();
611 }
612
613 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() {
614   // On some platforms (e.g. MacOS X) it is possible to close a tab while the
615   // media stream bubble is open. This resets the web contents to NULL.
616   if (!web_contents())
617     return;
618
619   bool media_setting_changed = false;
620   for (MediaMenuMap::const_iterator it = bubble_content().media_menus.begin();
621       it != bubble_content().media_menus.end(); ++it) {
622     if (it->second.selected_device.id != it->second.default_device.id) {
623       UpdateDefaultDeviceForType(it->first, it->second.selected_device.id);
624       media_setting_changed = true;
625     }
626   }
627
628   // Update the media settings if the radio button selection was changed.
629   if (selected_item_ != bubble_content().radio_group.default_item) {
630     UpdateSettings(radio_item_setting_[selected_item_]);
631     media_setting_changed = true;
632   }
633
634   // Trigger the reload infobar if the media setting has been changed.
635   if (media_setting_changed) {
636     MediaSettingChangedInfoBarDelegate::Create(
637         InfoBarService::FromWebContents(web_contents()));
638   }
639 }
640
641 void ContentSettingMediaStreamBubbleModel::SetTitle() {
642   int title_id = 0;
643   switch (state_) {
644     case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED:
645       // If neither microphone nor camera stream was accessed, then there is no
646       // icon didplayed in the omnibox and no settings bubble availbale. Hence
647       // there is no title.
648       NOTREACHED();
649       return;
650     case TabSpecificContentSettings::MICROPHONE_ACCESSED:
651       title_id = IDS_MICROPHONE_ACCESSED;
652       break;
653     case TabSpecificContentSettings::CAMERA_ACCESSED:
654       title_id = IDS_CAMERA_ACCESSED;
655       break;
656     case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED:
657       title_id = IDS_MICROPHONE_CAMERA_ALLOWED;
658       break;
659     case TabSpecificContentSettings::MICROPHONE_BLOCKED:
660       title_id = IDS_MICROPHONE_BLOCKED;
661       break;
662     case TabSpecificContentSettings::CAMERA_BLOCKED:
663       title_id = IDS_CAMERA_BLOCKED;
664       break;
665     case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED:
666       title_id = IDS_MICROPHONE_CAMERA_BLOCKED;
667       break;
668   }
669   set_title(l10n_util::GetStringUTF8(title_id));
670 }
671
672 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() {
673   TabSpecificContentSettings* content_settings =
674       TabSpecificContentSettings::FromWebContents(web_contents());
675   GURL url = content_settings->media_stream_access_origin();
676   RadioGroup radio_group;
677   radio_group.url = url;
678
679   base::string16 display_host_utf16;
680   net::AppendFormattedHost(
681       url,
682       profile()->GetPrefs()->GetString(prefs::kAcceptLanguages),
683       &display_host_utf16);
684   std::string display_host(base::UTF16ToUTF8(display_host_utf16));
685   if (display_host.empty())
686     display_host = url.spec();
687
688   int radio_allow_label_id = 0;
689   int radio_block_label_id = 0;
690   switch (state_) {
691     case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED:
692       NOTREACHED();
693       return;
694     case TabSpecificContentSettings::MICROPHONE_ACCESSED:
695       radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION;
696       radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK;
697       selected_item_ = 0;
698       break;
699     case TabSpecificContentSettings::CAMERA_ACCESSED:
700       radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION;
701       radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK;
702       selected_item_ = 0;
703       break;
704     case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED:
705       radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION;
706       radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK;
707       selected_item_ = 0;
708       break;
709     case TabSpecificContentSettings::MICROPHONE_BLOCKED:
710       if (url.SchemeIsSecure()) {
711         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW;
712         radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
713       } else {
714         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ASK;
715       }
716
717       radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION;
718       selected_item_ = 1;
719       break;
720     case TabSpecificContentSettings::CAMERA_BLOCKED:
721       if (url.SchemeIsSecure()) {
722         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW;
723         radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
724       } else {
725         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK;
726       }
727
728       radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION;
729       selected_item_ = 1;
730       break;
731     case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED:
732       if (url.SchemeIsSecure()) {
733         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW;
734         radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
735       } else {
736         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK;
737       }
738
739       radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION;
740       selected_item_ = 1;
741       break;
742   }
743
744   std::string radio_allow_label = l10n_util::GetStringFUTF8(
745       radio_allow_label_id, base::UTF8ToUTF16(display_host));
746   std::string radio_block_label =
747       l10n_util::GetStringUTF8(radio_block_label_id);
748
749   radio_group.default_item = selected_item_;
750   radio_group.radio_items.push_back(radio_allow_label);
751   radio_group.radio_items.push_back(radio_block_label);
752
753   set_radio_group(radio_group);
754   set_radio_group_enabled(true);
755 }
756
757 void ContentSettingMediaStreamBubbleModel::UpdateSettings(
758     ContentSetting setting) {
759   if (profile()) {
760     HostContentSettingsMap* content_settings =
761         profile()->GetHostContentSettingsMap();
762     TabSpecificContentSettings* tab_content_settings =
763         TabSpecificContentSettings::FromWebContents(web_contents());
764     // The same patterns must be used as in other places (e.g. the infobar) in
765     // order to override the existing rule. Otherwise a new rule is created.
766     // TODO(markusheintz): Extract to a helper so that there is only a single
767     // place to touch.
768     ContentSettingsPattern primary_pattern =
769         ContentSettingsPattern::FromURLNoWildcard(
770             tab_content_settings->media_stream_access_origin());
771     ContentSettingsPattern secondary_pattern =
772         ContentSettingsPattern::Wildcard();
773     if (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED ||
774         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
775         state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED ||
776         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) {
777       content_settings->SetContentSetting(
778           primary_pattern, secondary_pattern,
779           CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
780     }
781     if (state_ == TabSpecificContentSettings::CAMERA_ACCESSED ||
782         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
783         state_ == TabSpecificContentSettings::CAMERA_BLOCKED ||
784         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) {
785       content_settings->SetContentSetting(
786           primary_pattern, secondary_pattern,
787           CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
788     }
789   }
790 }
791
792 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType(
793     content::MediaStreamType type,
794     const std::string& device) {
795   PrefService* prefs = profile()->GetPrefs();
796   if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
797     prefs->SetString(prefs::kDefaultAudioCaptureDevice, device);
798   } else {
799     DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE, type);
800     prefs->SetString(prefs::kDefaultVideoCaptureDevice, device);
801   }
802 }
803
804 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() {
805   TabSpecificContentSettings* content_settings =
806       TabSpecificContentSettings::FromWebContents(web_contents());
807   const std::string& requested_microphone =
808        content_settings->media_stream_requested_audio_device();
809   const std::string& requested_camera =
810       content_settings->media_stream_requested_video_device();
811
812   // Add microphone menu.
813   PrefService* prefs = profile()->GetPrefs();
814   MediaCaptureDevicesDispatcher* dispatcher =
815       MediaCaptureDevicesDispatcher::GetInstance();
816   const content::MediaStreamDevices& microphones =
817       dispatcher->GetAudioCaptureDevices();
818
819   bool show_mic_menu =
820       (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED ||
821        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
822        state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED ||
823        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED);
824   bool show_camera_menu =
825       (state_ == TabSpecificContentSettings::CAMERA_ACCESSED ||
826        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
827        state_ == TabSpecificContentSettings::CAMERA_BLOCKED ||
828        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED);
829   DCHECK(show_mic_menu || show_camera_menu);
830
831   if (show_mic_menu) {
832     MediaMenu mic_menu;
833     mic_menu.label = l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL);
834     if (!microphones.empty()) {
835       std::string preferred_mic;
836       if (requested_microphone.empty()) {
837         preferred_mic = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
838         mic_menu.disabled = false;
839       } else {
840         // Set the |disabled| to true in order to disable the device selection
841         // menu on the media settings bubble. This must be done if the website
842         // manages the microphone devices itself.
843         preferred_mic = requested_microphone;
844         mic_menu.disabled = true;
845       }
846
847       mic_menu.default_device = GetMediaDeviceById(preferred_mic, microphones);
848       mic_menu.selected_device = mic_menu.default_device;
849     }
850     add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE, mic_menu);
851   }
852
853   if (show_camera_menu) {
854     const content::MediaStreamDevices& cameras =
855         dispatcher->GetVideoCaptureDevices();
856     MediaMenu camera_menu;
857     camera_menu.label =
858         l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL);
859     if (!cameras.empty()) {
860       std::string preferred_camera;
861       if (requested_camera.empty()) {
862         preferred_camera = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
863         camera_menu.disabled = false;
864       } else {
865         // Disable the menu since the website is managing the camera devices
866         // itself.
867         preferred_camera = requested_camera;
868         camera_menu.disabled = true;
869       }
870
871       camera_menu.default_device =
872           GetMediaDeviceById(preferred_camera, cameras);
873       camera_menu.selected_device = camera_menu.default_device;
874     }
875     add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE, camera_menu);
876   }
877 }
878
879 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index) {
880   selected_item_ = radio_index;
881 }
882
883 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked(
884     content::MediaStreamType type,
885     const std::string& selected_device_id) {
886   DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
887          type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
888   DCHECK_EQ(1U, bubble_content().media_menus.count(type));
889   MediaCaptureDevicesDispatcher* dispatcher =
890       MediaCaptureDevicesDispatcher::GetInstance();
891   const content::MediaStreamDevices& devices =
892       (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) ?
893           dispatcher->GetAudioCaptureDevices() :
894           dispatcher->GetVideoCaptureDevices();
895   set_selected_device(GetMediaDeviceById(selected_device_id, devices));
896 }
897
898 class ContentSettingDomainListBubbleModel
899     : public ContentSettingTitleAndLinkModel {
900  public:
901   ContentSettingDomainListBubbleModel(Delegate* delegate,
902                                       WebContents* web_contents,
903                                       Profile* profile,
904                                       ContentSettingsType content_type);
905   virtual ~ContentSettingDomainListBubbleModel() {}
906
907  private:
908   void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
909   void SetDomainsAndCustomLink();
910   virtual void OnCustomLinkClicked() OVERRIDE;
911 };
912
913 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel(
914     Delegate* delegate,
915     WebContents* web_contents,
916     Profile* profile,
917     ContentSettingsType content_type)
918     : ContentSettingTitleAndLinkModel(
919         delegate, web_contents, profile, content_type) {
920   DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) <<
921       "SetDomains currently only supports geolocation content type";
922   SetDomainsAndCustomLink();
923 }
924
925 void ContentSettingDomainListBubbleModel::MaybeAddDomainList(
926     const std::set<std::string>& hosts, int title_id) {
927   if (!hosts.empty()) {
928     DomainList domain_list;
929     domain_list.title = l10n_util::GetStringUTF8(title_id);
930     domain_list.hosts = hosts;
931     add_domain_list(domain_list);
932   }
933 }
934
935 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() {
936   TabSpecificContentSettings* content_settings =
937       TabSpecificContentSettings::FromWebContents(web_contents());
938   const ContentSettingsUsagesState& usages =
939       content_settings->geolocation_usages_state();
940   ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
941   unsigned int tab_state_flags = 0;
942   usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
943   // Divide the tab's current geolocation users into sets according to their
944   // permission state.
945   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
946                      IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED);
947
948   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
949                      IDS_GEOLOCATION_BUBBLE_SECTION_DENIED);
950
951   if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
952     set_custom_link(l10n_util::GetStringUTF8(
953         IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
954     set_custom_link_enabled(true);
955   } else if (tab_state_flags &
956              ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
957     set_custom_link(l10n_util::GetStringUTF8(
958         IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
959   }
960 }
961
962 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() {
963   if (!web_contents())
964     return;
965   // Reset this embedder's entry to default for each of the requesting
966   // origins currently on the page.
967   const GURL& embedder_url = web_contents()->GetURL();
968   TabSpecificContentSettings* content_settings =
969       TabSpecificContentSettings::FromWebContents(web_contents());
970   const ContentSettingsUsagesState::StateMap& state_map =
971       content_settings->geolocation_usages_state().state_map();
972   HostContentSettingsMap* settings_map =
973       profile()->GetHostContentSettingsMap();
974
975   for (ContentSettingsUsagesState::StateMap::const_iterator it =
976        state_map.begin(); it != state_map.end(); ++it) {
977     settings_map->SetContentSetting(
978         ContentSettingsPattern::FromURLNoWildcard(it->first),
979         ContentSettingsPattern::FromURLNoWildcard(embedder_url),
980         CONTENT_SETTINGS_TYPE_GEOLOCATION,
981         std::string(),
982         CONTENT_SETTING_DEFAULT);
983   }
984 }
985
986 class ContentSettingMixedScriptBubbleModel
987     : public ContentSettingTitleLinkAndCustomModel {
988  public:
989   ContentSettingMixedScriptBubbleModel(Delegate* delegate,
990                                        WebContents* web_contents,
991                                        Profile* profile,
992                                        ContentSettingsType content_type);
993
994   virtual ~ContentSettingMixedScriptBubbleModel() {}
995
996  private:
997   virtual void OnCustomLinkClicked() OVERRIDE;
998 };
999
1000 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel(
1001     Delegate* delegate,
1002     WebContents* web_contents,
1003     Profile* profile,
1004     ContentSettingsType content_type)
1005     : ContentSettingTitleLinkAndCustomModel(
1006         delegate, web_contents, profile, content_type) {
1007   DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_MIXEDSCRIPT);
1008   set_custom_link_enabled(true);
1009 }
1010
1011 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
1012   content::RecordAction(UserMetricsAction("MixedScript_LoadAnyway_Bubble"));
1013   DCHECK(web_contents());
1014   web_contents()->SendToAllFrames(
1015       new ChromeViewMsg_SetAllowRunningInsecureContent(MSG_ROUTING_NONE, true));
1016   web_contents()->GetMainFrame()->Send(new ChromeViewMsg_ReloadFrame(
1017       web_contents()->GetMainFrame()->GetRoutingID()));
1018 }
1019
1020 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel(
1021     Delegate* delegate,
1022     WebContents* web_contents,
1023     Profile* profile,
1024     ProtocolHandlerRegistry* registry,
1025     ContentSettingsType content_type)
1026     : ContentSettingTitleAndLinkModel(
1027           delegate, web_contents, profile, content_type),
1028       selected_item_(0),
1029       registry_(registry),
1030       pending_handler_(ProtocolHandler::EmptyProtocolHandler()),
1031       previous_handler_(ProtocolHandler::EmptyProtocolHandler()) {
1032   DCHECK_EQ(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, content_type);
1033
1034   TabSpecificContentSettings* content_settings =
1035       TabSpecificContentSettings::FromWebContents(web_contents);
1036   pending_handler_ = content_settings->pending_protocol_handler();
1037   previous_handler_ = content_settings->previous_protocol_handler();
1038
1039   base::string16 protocol;
1040   if (pending_handler_.protocol() == "mailto") {
1041     protocol = l10n_util::GetStringUTF16(
1042         IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME);
1043   } else if (pending_handler_.protocol() == "webcal") {
1044     protocol = l10n_util::GetStringUTF16(
1045         IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME);
1046   } else {
1047     protocol = base::UTF8ToUTF16(pending_handler_.protocol());
1048   }
1049
1050   // Note that we ignore the |title| parameter.
1051   if (previous_handler_.IsEmpty()) {
1052     set_title(l10n_util::GetStringFUTF8(
1053         IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM,
1054         base::UTF8ToUTF16(pending_handler_.url().host()),
1055         protocol));
1056   } else {
1057     set_title(l10n_util::GetStringFUTF8(
1058         IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE,
1059         base::UTF8ToUTF16(pending_handler_.url().host()),
1060         protocol,
1061         base::UTF8ToUTF16(previous_handler_.url().host())));
1062   }
1063
1064   std::string radio_allow_label =
1065       l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT);
1066   std::string radio_deny_label =
1067       l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY);
1068   std::string radio_ignore_label =
1069       l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE);
1070
1071   GURL url = web_contents->GetURL();
1072   RadioGroup radio_group;
1073   radio_group.url = url;
1074
1075   radio_group.radio_items.push_back(radio_allow_label);
1076   radio_group.radio_items.push_back(radio_deny_label);
1077   radio_group.radio_items.push_back(radio_ignore_label);
1078   ContentSetting setting =
1079       content_settings->pending_protocol_handler_setting();
1080   if (setting == CONTENT_SETTING_ALLOW)
1081     radio_group.default_item = RPH_ALLOW;
1082   else if (setting == CONTENT_SETTING_BLOCK)
1083     radio_group.default_item = RPH_BLOCK;
1084   else
1085     radio_group.default_item = RPH_IGNORE;
1086
1087   selected_item_ = radio_group.default_item;
1088   set_radio_group_enabled(true);
1089   set_radio_group(radio_group);
1090 }
1091
1092 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index) {
1093   if (selected_item_ == radio_index)
1094     return;
1095
1096   selected_item_ = radio_index;
1097
1098   if (radio_index == RPH_ALLOW)
1099     RegisterProtocolHandler();
1100   else if (radio_index == RPH_BLOCK)
1101     UnregisterProtocolHandler();
1102   else if (radio_index == RPH_IGNORE)
1103     IgnoreProtocolHandler();
1104   else
1105     NOTREACHED();
1106 }
1107
1108 void ContentSettingRPHBubbleModel::OnDoneClicked() {
1109   // The user has one chance to deal with the RPH content setting UI,
1110   // then we remove it.
1111   TabSpecificContentSettings::FromWebContents(web_contents())->
1112       ClearPendingProtocolHandler();
1113   content::NotificationService::current()->Notify(
1114       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
1115       content::Source<WebContents>(web_contents()),
1116       content::NotificationService::NoDetails());
1117 }
1118
1119 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() {
1120   // A no-op if the handler hasn't been ignored, but needed in case the user
1121   // selects sequences like register/ignore/register.
1122   registry_->RemoveIgnoredHandler(pending_handler_);
1123
1124   registry_->OnAcceptRegisterProtocolHandler(pending_handler_);
1125   TabSpecificContentSettings::FromWebContents(web_contents())->
1126       set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW);
1127 }
1128
1129 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() {
1130   registry_->OnDenyRegisterProtocolHandler(pending_handler_);
1131   TabSpecificContentSettings::FromWebContents(web_contents())->
1132       set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK);
1133   ClearOrSetPreviousHandler();
1134 }
1135
1136 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() {
1137   registry_->OnIgnoreRegisterProtocolHandler(pending_handler_);
1138   TabSpecificContentSettings::FromWebContents(web_contents())->
1139       set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT);
1140   ClearOrSetPreviousHandler();
1141 }
1142
1143 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() {
1144   if (previous_handler_.IsEmpty()) {
1145     registry_->ClearDefault(pending_handler_.protocol());
1146   } else {
1147     registry_->OnAcceptRegisterProtocolHandler(previous_handler_);
1148   }
1149 }
1150
1151 class ContentSettingMidiSysExBubbleModel
1152     : public ContentSettingTitleAndLinkModel {
1153  public:
1154   ContentSettingMidiSysExBubbleModel(Delegate* delegate,
1155                                      WebContents* web_contents,
1156                                      Profile* profile,
1157                                      ContentSettingsType content_type);
1158   virtual ~ContentSettingMidiSysExBubbleModel() {}
1159
1160  private:
1161   void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
1162   void SetDomainsAndCustomLink();
1163   virtual void OnCustomLinkClicked() OVERRIDE;
1164 };
1165
1166 ContentSettingMidiSysExBubbleModel::ContentSettingMidiSysExBubbleModel(
1167     Delegate* delegate,
1168     WebContents* web_contents,
1169     Profile* profile,
1170     ContentSettingsType content_type)
1171     : ContentSettingTitleAndLinkModel(
1172         delegate, web_contents, profile, content_type) {
1173   DCHECK_EQ(CONTENT_SETTINGS_TYPE_MIDI_SYSEX, content_type);
1174   SetDomainsAndCustomLink();
1175 }
1176
1177 void ContentSettingMidiSysExBubbleModel::MaybeAddDomainList(
1178     const std::set<std::string>& hosts, int title_id) {
1179   if (!hosts.empty()) {
1180     DomainList domain_list;
1181     domain_list.title = l10n_util::GetStringUTF8(title_id);
1182     domain_list.hosts = hosts;
1183     add_domain_list(domain_list);
1184   }
1185 }
1186
1187 void ContentSettingMidiSysExBubbleModel::SetDomainsAndCustomLink() {
1188   TabSpecificContentSettings* content_settings =
1189       TabSpecificContentSettings::FromWebContents(web_contents());
1190   const ContentSettingsUsagesState& usages_state =
1191       content_settings->midi_usages_state();
1192   ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
1193   unsigned int tab_state_flags = 0;
1194   usages_state.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
1195   // Divide the tab's current MIDI sysex users into sets according to their
1196   // permission state.
1197   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
1198                      IDS_MIDI_SYSEX_BUBBLE_ALLOWED);
1199
1200   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
1201                      IDS_MIDI_SYSEX_BUBBLE_DENIED);
1202
1203   if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
1204     set_custom_link(l10n_util::GetStringUTF8(
1205         IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK));
1206     set_custom_link_enabled(true);
1207   } else if (tab_state_flags &
1208              ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
1209     set_custom_link(l10n_util::GetStringUTF8(
1210         IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
1211   }
1212 }
1213
1214 void ContentSettingMidiSysExBubbleModel::OnCustomLinkClicked() {
1215   if (!web_contents())
1216     return;
1217   // Reset this embedder's entry to default for each of the requesting
1218   // origins currently on the page.
1219   TabSpecificContentSettings* content_settings =
1220       TabSpecificContentSettings::FromWebContents(web_contents());
1221   const ContentSettingsUsagesState::StateMap& state_map =
1222       content_settings->midi_usages_state().state_map();
1223   HostContentSettingsMap* settings_map =
1224       profile()->GetHostContentSettingsMap();
1225
1226   for (ContentSettingsUsagesState::StateMap::const_iterator it =
1227        state_map.begin(); it != state_map.end(); ++it) {
1228     settings_map->SetContentSetting(
1229         ContentSettingsPattern::FromURLNoWildcard(it->first),
1230         ContentSettingsPattern::Wildcard(),
1231         CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
1232         std::string(),
1233         CONTENT_SETTING_DEFAULT);
1234   }
1235 }
1236
1237 // static
1238 ContentSettingBubbleModel*
1239     ContentSettingBubbleModel::CreateContentSettingBubbleModel(
1240         Delegate* delegate,
1241         WebContents* web_contents,
1242         Profile* profile,
1243         ContentSettingsType content_type) {
1244   if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
1245     return new ContentSettingCookiesBubbleModel(delegate, web_contents, profile,
1246                                                 content_type);
1247   }
1248   if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) {
1249     return new ContentSettingPopupBubbleModel(delegate, web_contents, profile,
1250                                               content_type);
1251   }
1252   if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
1253     return new ContentSettingDomainListBubbleModel(delegate, web_contents,
1254                                                    profile, content_type);
1255   }
1256   if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
1257     return new ContentSettingMediaStreamBubbleModel(delegate, web_contents,
1258                                                     profile);
1259   }
1260   if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
1261     return new ContentSettingPluginBubbleModel(delegate, web_contents, profile,
1262                                                content_type);
1263   }
1264   if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
1265     return new ContentSettingMixedScriptBubbleModel(delegate, web_contents,
1266                                                     profile, content_type);
1267   }
1268   if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
1269     ProtocolHandlerRegistry* registry =
1270         ProtocolHandlerRegistryFactory::GetForBrowserContext(profile);
1271     return new ContentSettingRPHBubbleModel(delegate, web_contents, profile,
1272                                             registry, content_type);
1273   }
1274   if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
1275     return new ContentSettingMidiSysExBubbleModel(delegate, web_contents,
1276                                                   profile, content_type);
1277   }
1278   return new ContentSettingSingleRadioGroup(delegate, web_contents, profile,
1279                                             content_type);
1280 }
1281
1282 ContentSettingBubbleModel::ContentSettingBubbleModel(
1283     WebContents* web_contents,
1284     Profile* profile,
1285     ContentSettingsType content_type)
1286     : web_contents_(web_contents),
1287       profile_(profile),
1288       content_type_(content_type),
1289       setting_is_managed_(false) {
1290   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
1291                  content::Source<WebContents>(web_contents));
1292   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
1293                  content::Source<Profile>(profile_));
1294 }
1295
1296 ContentSettingBubbleModel::~ContentSettingBubbleModel() {
1297 }
1298
1299 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {}
1300
1301 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {}
1302
1303 ContentSettingBubbleModel::DomainList::DomainList() {}
1304
1305 ContentSettingBubbleModel::DomainList::~DomainList() {}
1306
1307 ContentSettingBubbleModel::MediaMenu::MediaMenu() : disabled(false) {}
1308
1309 ContentSettingBubbleModel::MediaMenu::~MediaMenu() {}
1310
1311 ContentSettingBubbleModel::BubbleContent::BubbleContent()
1312     : radio_group_enabled(false),
1313       custom_link_enabled(false) {
1314 }
1315
1316 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {}
1317
1318 void ContentSettingBubbleModel::Observe(
1319     int type,
1320     const content::NotificationSource& source,
1321     const content::NotificationDetails& details) {
1322   if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
1323     DCHECK_EQ(web_contents_,
1324               content::Source<WebContents>(source).ptr());
1325     web_contents_ = NULL;
1326   } else {
1327     DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
1328     DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
1329     profile_ = NULL;
1330   }
1331 }