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