diff options
Diffstat (limited to 'chrome/browser/cocoa/content_settings_dialog_controller.mm')
-rw-r--r-- | chrome/browser/cocoa/content_settings_dialog_controller.mm | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.mm b/chrome/browser/cocoa/content_settings_dialog_controller.mm new file mode 100644 index 0000000..d98948d --- /dev/null +++ b/chrome/browser/cocoa/content_settings_dialog_controller.mm @@ -0,0 +1,526 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/content_settings_dialog_controller.h" + +#import <Cocoa/Cocoa.h> + +#include "app/l10n_util.h" +#include "base/mac_util.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#import "chrome/browser/cocoa/content_exceptions_window_controller.h" +#import "chrome/browser/cocoa/cookies_window_controller.h" +#import "chrome/browser/cocoa/simple_content_exceptions_window_controller.h" +#import "chrome/browser/cocoa/l10n_util.h" +#import "chrome/browser/cocoa/tab_view_picker_table.h" +#import "chrome/browser/geolocation/geolocation_content_settings_map.h" +#import "chrome/browser/geolocation/geolocation_exceptions_table_model.h" +#import "chrome/browser/host_content_settings_map.h" +#import "chrome/browser/notifications/desktop_notification_service.h" +#import "chrome/browser/notifications/notification_exceptions_table_model.h" +#include "chrome/browser/pref_service.h" +#include "chrome/browser/profile.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "grit/locale_settings.h" +#include "grit/generated_resources.h" + +namespace { + +// Stores the currently visible content settings dialog, if any. +ContentSettingsDialogController* g_instance = nil; + +} // namespace + + +@interface ContentSettingsDialogController(Private) +- (id)initWithProfile:(Profile*)profile; +- (void)selectTab:(ContentSettingsType)settingsType; +- (void)showExceptionsForType:(ContentSettingsType)settingsType; + +// Callback when preferences are changed. |prefName| is the name of the +// pref that has changed. +- (void)prefChanged:(std::wstring*)prefName; + +@end + +namespace ContentSettingsDialogControllerInternal { + +// A C++ class registered for changes in preferences. +class PrefObserverBridge : public NotificationObserver { + public: + PrefObserverBridge(ContentSettingsDialogController* controller) + : controller_(controller), disabled_(false) {} + + virtual ~PrefObserverBridge() {} + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (!disabled_ && type == NotificationType::PREF_CHANGED) { + [controller_ prefChanged:Details<std::wstring>(details).ptr()]; + } + } + + void SetDisabled(bool disabled) { + disabled_ = disabled; + } + + private: + ContentSettingsDialogController* controller_; // weak, owns us + bool disabled_; // true if notifications should be ignored. +}; + +// A C++ utility class to disable notifications for PrefsObserverBridge. +// The intended usage is to create on the stack. +class PrefObserverDisabler { + public: + PrefObserverDisabler(PrefObserverBridge *bridge) : bridge_(bridge) { + bridge_->SetDisabled(true); + } + + ~PrefObserverDisabler() { + bridge_->SetDisabled(false); + } + + private: + PrefObserverBridge *bridge_; +}; + +} // ContentSettingsDialogControllerInternal + +@implementation ContentSettingsDialogController + ++ (id)showContentSettingsForType:(ContentSettingsType)settingsType + profile:(Profile*)profile { + profile = profile->GetOriginalProfile(); + if (!g_instance) + g_instance = [[self alloc] initWithProfile:profile]; + + // The code doesn't expect multiple profiles. Check that support for that + // hasn't been added. + DCHECK(g_instance->profile_ == profile); + + // Select desired tab. + if (settingsType == CONTENT_SETTINGS_TYPE_DEFAULT) { + // Remember the last visited page from local state. + int value = g_instance->lastSelectedTab_.GetValue(); + if (value >= 0 && value < CONTENT_SETTINGS_NUM_TYPES) + settingsType = static_cast<ContentSettingsType>(value); + if (settingsType == CONTENT_SETTINGS_TYPE_DEFAULT) + settingsType = CONTENT_SETTINGS_TYPE_COOKIES; + } + // TODO(thakis): Autosave window pos. + + [g_instance selectTab:settingsType]; + [g_instance showWindow:nil]; + [g_instance closeExceptionsSheet]; + return g_instance; +} + +- (id)initWithProfile:(Profile*)profile { + DCHECK(profile); + NSString* nibpath = + [mac_util::MainAppBundle() pathForResource:@"ContentSettings" + ofType:@"nib"]; + if ((self = [super initWithWindowNibPath:nibpath owner:self])) { + profile_ = profile; + + observer_.reset( + new ContentSettingsDialogControllerInternal::PrefObserverBridge(self)); + clearSiteDataOnExit_.Init(prefs::kClearSiteDataOnExit, + profile_->GetPrefs(), observer_.get()); + + // Manually observe notifications for preferences that are grouped in + // the HostContentSettingsMap or GeolocationContentSettingsMap. + PrefService* prefs = profile_->GetPrefs(); + prefs->AddPrefObserver(prefs::kBlockThirdPartyCookies, observer_.get()); + prefs->AddPrefObserver(prefs::kDefaultContentSettings, observer_.get()); + prefs->AddPrefObserver(prefs::kGeolocationDefaultContentSetting, + observer_.get()); + + // We don't need to observe changes in this value. + lastSelectedTab_.Init(prefs::kContentSettingsWindowLastTabIndex, + profile_->GetPrefs(), NULL); + } + return self; +} + +- (void)dealloc { + if (profile_) { + PrefService* prefs = profile_->GetPrefs(); + prefs->RemovePrefObserver(prefs::kBlockThirdPartyCookies, observer_.get()); + prefs->RemovePrefObserver(prefs::kDefaultContentSettings, observer_.get()); + prefs->RemovePrefObserver(prefs::kGeolocationDefaultContentSetting, + observer_.get()); + } + + [super dealloc]; +} + +- (void)closeExceptionsSheet { + NSWindow* attachedSheet = [[self window] attachedSheet]; + if (attachedSheet) { + [NSApp endSheet:attachedSheet]; + } +} + +- (void)awakeFromNib { + DCHECK([self window]); + DCHECK(tabView_); + DCHECK(tabViewPicker_); + DCHECK_EQ(self, [[self window] delegate]); + + // Adapt views to potentially long localized strings. + CGFloat windowDelta = 0; + for (NSTabViewItem* tab in [tabView_ tabViewItems]) { + NSArray* subviews = [[tab view] subviews]; + windowDelta = MAX(windowDelta, + cocoa_l10n_util::VerticallyReflowGroup(subviews)); + + for (NSView* view in subviews) { + // Since the tab pane is in a horizontal resizer in IB, it's convenient + // to give all the subviews flexible width so that their sizes are + // autoupdated in IB. However, in chrome, the subviews shouldn't have + // flexible widths as this looks weird. + [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + } + } + + NSString* label = + l10n_util::GetNSStringWithFixup(IDS_CONTENT_SETTINGS_FEATURES_LABEL); + label = [label stringByReplacingOccurrencesOfString:@":" withString:@""]; + [tabViewPicker_ setHeading:label]; + + NSRect frame = [[self window] frame]; + frame.origin.y -= windowDelta; + frame.size.height += windowDelta; + [[self window] setFrame:frame display:NO]; +} + +// NSWindowDelegate method. +- (void)windowWillClose:(NSNotification*)notification { + [self autorelease]; + g_instance = nil; +} + +- (void)selectTab:(ContentSettingsType)settingsType { + [self window]; // Make sure the nib file is loaded. + DCHECK(tabView_); + [tabView_ selectTabViewItemAtIndex:settingsType]; +} + +// NSTabViewDelegate method. +- (void) tabView:(NSTabView*)tabView + didSelectTabViewItem:(NSTabViewItem*)tabViewItem { + DCHECK_EQ(tabView_, tabView); + NSInteger index = [tabView indexOfTabViewItem:tabViewItem]; + DCHECK_GT(index, CONTENT_SETTINGS_TYPE_DEFAULT); + DCHECK_LT(index, CONTENT_SETTINGS_NUM_TYPES); + if (index > CONTENT_SETTINGS_TYPE_DEFAULT && + index < CONTENT_SETTINGS_NUM_TYPES) + lastSelectedTab_.SetValue(index); +} + +// Let esc close the window. +- (void)cancel:(id)sender { + [self close]; +} + +- (void)setCookieSettingIndex:(NSInteger)value { + ContentSetting setting = CONTENT_SETTING_DEFAULT; + switch (value) { + case kCookieEnabledIndex: setting = CONTENT_SETTING_ALLOW; break; + case kCookieDisabledIndex: setting = CONTENT_SETTING_BLOCK; break; + default: + NOTREACHED(); + } + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_COOKIES, + setting); +} + +- (NSInteger)cookieSettingIndex { + switch (profile_->GetHostContentSettingsMap()->GetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_COOKIES)) { + case CONTENT_SETTING_ALLOW: return kCookieEnabledIndex; + case CONTENT_SETTING_BLOCK: return kCookieDisabledIndex; + default: + NOTREACHED(); + return kCookieEnabledIndex; + } +} + +- (BOOL)blockThirdPartyCookies { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + return settingsMap->BlockThirdPartyCookies(); +} + +- (void)setBlockThirdPartyCookies:(BOOL)value { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + settingsMap->SetBlockThirdPartyCookies(value); +} + +- (BOOL)clearSiteDataOnExit { + return clearSiteDataOnExit_.GetValue(); +} + +- (void)setClearSiteDataOnExit:(BOOL)value { + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + clearSiteDataOnExit_.SetValue(value); +} + +// Shows the cookies controller. +- (IBAction)showCookies:(id)sender { + // The cookie controller will autorelease itself when it's closed. + BrowsingDataDatabaseHelper* databaseHelper = + new BrowsingDataDatabaseHelper(profile_); + BrowsingDataLocalStorageHelper* storageHelper = + new BrowsingDataLocalStorageHelper(profile_); + BrowsingDataAppCacheHelper* appcacheHelper = + new BrowsingDataAppCacheHelper(profile_); + CookiesWindowController* controller = + [[CookiesWindowController alloc] initWithProfile:profile_ + databaseHelper:databaseHelper + storageHelper:storageHelper + appcacheHelper:appcacheHelper]; + [controller attachSheetTo:[self window]]; +} + +// Called when the user clicks the "Flash Player storage settings" button. +- (IBAction)openFlashPlayerSettings:(id)sender { + Browser* browser = Browser::Create(profile_); + browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)), + GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); + browser->window()->Show(); +} + +// Called when the user clicks the "Disable individual plug-ins..." button. +- (IBAction)openPluginsPage:(id)sender { + Browser* browser = Browser::Create(profile_); + browser->OpenURL(GURL(chrome::kChromeUIPluginsURL), + GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); + browser->window()->Show(); +} + +- (IBAction)showCookieExceptions:(id)sender { + [self showExceptionsForType:CONTENT_SETTINGS_TYPE_COOKIES]; +} + +- (IBAction)showImagesExceptions:(id)sender { + [self showExceptionsForType:CONTENT_SETTINGS_TYPE_IMAGES]; +} + +- (IBAction)showJavaScriptExceptions:(id)sender { + [self showExceptionsForType:CONTENT_SETTINGS_TYPE_JAVASCRIPT]; +} + +- (IBAction)showPluginsExceptions:(id)sender { + [self showExceptionsForType:CONTENT_SETTINGS_TYPE_PLUGINS]; +} + +- (IBAction)showPopupsExceptions:(id)sender { + [self showExceptionsForType:CONTENT_SETTINGS_TYPE_POPUPS]; +} + +- (IBAction)showGeolocationExceptions:(id)sender { + GeolocationContentSettingsMap* settingsMap = + profile_->GetGeolocationContentSettingsMap(); + GeolocationExceptionsTableModel* model = // Freed by window controller. + new GeolocationExceptionsTableModel(settingsMap); + [[SimpleContentExceptionsWindowController controllerWithTableModel:model] + attachSheetTo:[self window]]; +} + +- (IBAction)showNotificationsExceptions:(id)sender { + DesktopNotificationService* service = + profile_->GetDesktopNotificationService(); + NotificationExceptionsTableModel* model = // Freed by window controller. + new NotificationExceptionsTableModel(service); + [[SimpleContentExceptionsWindowController controllerWithTableModel:model] + attachSheetTo:[self window]]; +} + +- (void)showExceptionsForType:(ContentSettingsType)settingsType { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + HostContentSettingsMap* offTheRecordSettingsMap = + profile_->HasOffTheRecordProfile() ? + profile_->GetOffTheRecordProfile()->GetHostContentSettingsMap() : + NULL; + [[ContentExceptionsWindowController controllerForType:settingsType + settingsMap:settingsMap + otrSettingsMap:offTheRecordSettingsMap] + attachSheetTo:[self window]]; +} + +- (void)setImagesEnabledIndex:(NSInteger)value { + ContentSetting setting = value == kContentSettingsEnabledIndex ? + CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_IMAGES, setting); +} + +- (NSInteger)imagesEnabledIndex { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + bool enabled = + settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES) == + CONTENT_SETTING_ALLOW; + return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex; +} + +- (void)setJavaScriptEnabledIndex:(NSInteger)value { + ContentSetting setting = value == kContentSettingsEnabledIndex ? + CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_JAVASCRIPT, setting); +} + +- (NSInteger)javaScriptEnabledIndex { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + bool enabled = + settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT) == + CONTENT_SETTING_ALLOW; + return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex; +} + +- (void)setPluginsEnabledIndex:(NSInteger)value { + ContentSetting setting = value == kContentSettingsEnabledIndex ? + CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_PLUGINS, setting); +} + +- (NSInteger)pluginsEnabledIndex { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + bool enabled = + settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS) == + CONTENT_SETTING_ALLOW; + return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex; +} + +- (void)setPopupsEnabledIndex:(NSInteger)value { + ContentSetting setting = value == kContentSettingsEnabledIndex ? + CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_POPUPS, setting); +} + +- (NSInteger)popupsEnabledIndex { + HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + bool enabled = + settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS) == + CONTENT_SETTING_ALLOW; + return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex; +} + +- (void)setGeolocationSettingIndex:(NSInteger)value { + ContentSetting setting = CONTENT_SETTING_DEFAULT; + switch (value) { + case kGeolocationEnabledIndex: setting = CONTENT_SETTING_ALLOW; break; + case kGeolocationAskIndex: setting = CONTENT_SETTING_ASK; break; + case kGeolocationDisabledIndex: setting = CONTENT_SETTING_BLOCK; break; + default: + NOTREACHED(); + } + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetGeolocationContentSettingsMap()->SetDefaultContentSetting( + setting); +} + +- (NSInteger)geolocationSettingIndex { + ContentSetting setting = + profile_->GetGeolocationContentSettingsMap()->GetDefaultContentSetting(); + switch (setting) { + case CONTENT_SETTING_ALLOW: return kGeolocationEnabledIndex; + case CONTENT_SETTING_ASK: return kGeolocationAskIndex; + case CONTENT_SETTING_BLOCK: return kGeolocationDisabledIndex; + default: + NOTREACHED(); + return kGeolocationAskIndex; + } +} + +- (void)setNotificationsSettingIndex:(NSInteger)value { + ContentSetting setting = CONTENT_SETTING_DEFAULT; + switch (value) { + case kNotificationsEnabledIndex: setting = CONTENT_SETTING_ALLOW; break; + case kNotificationsAskIndex: setting = CONTENT_SETTING_ASK; break; + case kNotificationsDisabledIndex: setting = CONTENT_SETTING_BLOCK; break; + default: + NOTREACHED(); + } + ContentSettingsDialogControllerInternal::PrefObserverDisabler + disabler(observer_.get()); + profile_->GetDesktopNotificationService()->SetDefaultContentSetting( + setting); +} + +- (NSInteger)notificationsSettingIndex { + ContentSetting setting = + profile_->GetDesktopNotificationService()->GetDefaultContentSetting(); + switch (setting) { + case CONTENT_SETTING_ALLOW: return kNotificationsEnabledIndex; + case CONTENT_SETTING_ASK: return kNotificationsAskIndex; + case CONTENT_SETTING_BLOCK: return kNotificationsDisabledIndex; + default: + NOTREACHED(); + return kGeolocationAskIndex; + } +} + +// Callback when preferences are changed. |prefName| is the name of the +// pref that has changed and should not be NULL. +- (void)prefChanged:(std::wstring*)prefName { + DCHECK(prefName); + if (!prefName) return; + if (*prefName == prefs::kClearSiteDataOnExit) { + [self willChangeValueForKey:@"clearSiteDataOnExit"]; + [self didChangeValueForKey:@"clearSiteDataOnExit"]; + } + if (*prefName == prefs::kBlockThirdPartyCookies) { + [self willChangeValueForKey:@"blockThirdPartyCookies"]; + [self didChangeValueForKey:@"blockThirdPartyCookies"]; + } + if (*prefName == prefs::kDefaultContentSettings) { + // We don't know exactly which setting has changed, so we'll tickle all + // of the properties that apply to kDefaultContentSettings. This will + // keep the UI up-to-date. + [self willChangeValueForKey:@"cookieSettingIndex"]; + [self didChangeValueForKey:@"cookieSettingIndex"]; + [self willChangeValueForKey:@"imagesEnabledIndex"]; + [self didChangeValueForKey:@"imagesEnabledIndex"]; + [self willChangeValueForKey:@"javaScriptEnabledIndex"]; + [self didChangeValueForKey:@"javaScriptEnabledIndex"]; + [self willChangeValueForKey:@"pluginsEnabledIndex"]; + [self didChangeValueForKey:@"pluginsEnabledIndex"]; + [self willChangeValueForKey:@"popupsEnabledIndex"]; + [self didChangeValueForKey:@"popupsEnabledIndex"]; + } + if (*prefName == prefs::kGeolocationDefaultContentSetting) { + [self willChangeValueForKey:@"geolocationSettingIndex"]; + [self didChangeValueForKey:@"geolocationSettingIndex"]; + } + if (*prefName == prefs::kDesktopNotificationDefaultContentSetting) { + [self willChangeValueForKey:@"notificationsSettingIndex"]; + [self didChangeValueForKey:@"notificationsSettingIndex"]; + } +} + +@end |