diff options
Diffstat (limited to 'chrome/browser/ui/webui/options2')
111 files changed, 17733 insertions, 0 deletions
diff --git a/chrome/browser/ui/webui/options2/OWNERS b/chrome/browser/ui/webui/options2/OWNERS new file mode 100644 index 0000000..67257e6 --- /dev/null +++ b/chrome/browser/ui/webui/options2/OWNERS @@ -0,0 +1,4 @@ +csilv@chromium.org +estade@chromium.org +jhawkins@chromium.org +stuartmorgan@chromium.org diff --git a/chrome/browser/ui/webui/options2/advanced_options_browsertest.js b/chrome/browser/ui/webui/options2/advanced_options_browsertest.js new file mode 100644 index 0000000..a929bbb --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_browsertest.js @@ -0,0 +1,63 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for advanced options WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function AdvancedOptionsWebUITest() {} + +AdvancedOptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to advanced options. + **/ + browsePreload: 'chrome://settings/advanced', + + /** + * Register a mock handler. + * @type {Function} + * @override + */ + preLoad: function() { + this.makeAndRegisterMockHandler(['defaultZoomFactorAction']); + }, +}; + +/** + * The expected minimum length of the |defaultZoomFactor| element. + * @type {number} + * @const + */ +var defaultZoomFactorMinimumLength = 10; + +/** + * Test opening the advanced options has correct location. + */ +TEST_F('AdvancedOptionsWebUITest', 'testOpenAdvancedOptions', function() { + assertEquals(this.browsePreload, document.location.href); +}); + +/** + * Test the default zoom factor select element. + */ +TEST_F('AdvancedOptionsWebUITest', 'testDefaultZoomFactor', function() { + // Verify that the zoom factor element exists. + var defaultZoomFactor = $('defaultZoomFactor'); + assertNotEquals(defaultZoomFactor, null); + + // Verify that the zoom factor element has a reasonable number of choices. + expectGE(defaultZoomFactor.options.length, defaultZoomFactorMinimumLength); + + // Simulate a change event, selecting the highest zoom value. Verify that + // the javascript handler was invoked once. + this.mockHandler.expects(once()).defaultZoomFactorAction(NOT_NULL). + will(callFunction(function() { })); + defaultZoomFactor.selectedIndex = defaultZoomFactor.options.length - 1; + var event = { target: defaultZoomFactor }; + if (defaultZoomFactor.onchange) defaultZoomFactor.onchange(event); +}); + diff --git a/chrome/browser/ui/webui/options2/advanced_options_handler.cc b/chrome/browser/ui/webui/options2/advanced_options_handler.cc new file mode 100644 index 0000000..8bb8ee0 --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_handler.cc @@ -0,0 +1,641 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/advanced_options_handler.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_page_zoom.h" +#include "chrome/browser/download/download_prefs.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" +#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h" +#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h" +#include "chrome/browser/printing/cloud_print/cloud_print_url.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/service/service_process_control.h" +#include "chrome/browser/ui/options/options_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/browser/download/download_manager.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_view.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_types.h" +#include "content/public/common/page_zoom.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "ui/base/l10n/l10n_util.h" + +#if !defined(OS_CHROMEOS) +#include "chrome/browser/printing/cloud_print/cloud_print_setup_handler.h" +#include "chrome/browser/ui/webui/options2/advanced_options_utils.h" +#endif + +AdvancedOptionsHandler::AdvancedOptionsHandler() { + +#if(!defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)) + // On Windows, we need the PDF plugin which is only guaranteed to exist on + // Google Chrome builds. Use a command-line switch for Windows non-Google + // Chrome builds. + cloud_print_proxy_ui_enabled_ = CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableCloudPrintProxy); +#elif(!defined(OS_CHROMEOS)) + // Always enabled for Mac, Linux and Google Chrome Windows builds. + // Never enabled for Chrome OS, we don't even need to indicate it. + cloud_print_proxy_ui_enabled_ = true; +#endif +} + +AdvancedOptionsHandler::~AdvancedOptionsHandler() { + // There may be pending file dialogs, we need to tell them that we've gone + // away so they don't try and call back to us. + if (select_folder_dialog_.get()) + select_folder_dialog_->ListenerDestroyed(); +} + +void AdvancedOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "downloadLocationGroupName", + IDS_OPTIONS_DOWNLOADLOCATION_GROUP_NAME }, + { "downloadLocationChangeButton", + IDS_OPTIONS_DOWNLOADLOCATION_CHANGE_BUTTON }, + { "downloadLocationBrowseTitle", + IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_TITLE }, + { "downloadLocationBrowseWindowTitle", + IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_WINDOW_TITLE }, + { "downloadLocationAskForSaveLocation", + IDS_OPTIONS_DOWNLOADLOCATION_ASKFORSAVELOCATION }, + { "autoOpenFileTypesInfo", + IDS_OPTIONS_OPEN_FILE_TYPES_AUTOMATICALLY }, + { "autoOpenFileTypesResetToDefault", + IDS_OPTIONS_AUTOOPENFILETYPES_RESETTODEFAULT }, + { "translateEnableTranslate", + IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE }, + { "certificatesManageButton", + IDS_OPTIONS_CERTIFICATES_MANAGE_BUTTON }, + { "proxiesLabel", + IDS_OPTIONS_PROXIES_LABEL }, +#if !defined(OS_CHROMEOS) + { "proxiesConfigureButton", + IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON }, +#endif + { "safeBrowsingEnableProtection", + IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION }, + { "sslGroupDescription", + IDS_OPTIONS_SSL_GROUP_DESCRIPTION }, + { "sslCheckRevocation", + IDS_OPTIONS_SSL_CHECKREVOCATION }, + { "networkPredictionEnabledDescription", + IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION }, + { "privacyContentSettingsButton", + IDS_OPTIONS_PRIVACY_CONTENT_SETTINGS_BUTTON }, + { "privacyClearDataButton", + IDS_OPTIONS_PRIVACY_CLEAR_DATA_BUTTON }, + { "linkDoctorPref", + IDS_OPTIONS_LINKDOCTOR_PREF }, + { "suggestPref", + IDS_OPTIONS_SUGGEST_PREF }, + { "tabsToLinksPref", + IDS_OPTIONS_TABS_TO_LINKS_PREF }, + { "fontSettingsInfo", + IDS_OPTIONS_FONTSETTINGS_INFO }, + { "defaultZoomFactorLabel", + IDS_OPTIONS_DEFAULT_ZOOM_LEVEL_LABEL }, + { "defaultFontSizeLabel", + IDS_OPTIONS_DEFAULT_FONT_SIZE_LABEL }, + { "fontSizeLabelVerySmall", + IDS_OPTIONS_FONT_SIZE_LABEL_VERY_SMALL }, + { "fontSizeLabelSmall", + IDS_OPTIONS_FONT_SIZE_LABEL_SMALL }, + { "fontSizeLabelMedium", + IDS_OPTIONS_FONT_SIZE_LABEL_MEDIUM }, + { "fontSizeLabelLarge", + IDS_OPTIONS_FONT_SIZE_LABEL_LARGE }, + { "fontSizeLabelVeryLarge", + IDS_OPTIONS_FONT_SIZE_LABEL_VERY_LARGE }, + { "fontSizeLabelCustom", + IDS_OPTIONS_FONT_SIZE_LABEL_CUSTOM }, + { "fontSettingsCustomizeFontsButton", + IDS_OPTIONS_FONTSETTINGS_CUSTOMIZE_FONTS_BUTTON }, + { "languageAndSpellCheckSettingsButton", + IDS_OPTIONS_LANGUAGE_AND_SPELLCHECK_BUTTON }, + { "advancedSectionTitlePrivacy", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY }, + { "advancedSectionTitleContent", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_CONTENT }, + { "advancedSectionTitleSecurity", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_SECURITY }, + { "advancedSectionTitleNetwork", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_NETWORK }, + { "advancedSectionTitleTranslate", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_TRANSLATE }, + { "translateEnableTranslate", + IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE }, + { "enableLogging", + IDS_OPTIONS_ENABLE_LOGGING }, + { "improveBrowsingExperience", + IDS_OPTIONS_IMPROVE_BROWSING_EXPERIENCE }, + { "disableWebServices", + IDS_OPTIONS_DISABLE_WEB_SERVICES }, +#if defined(OS_CHROMEOS) + { "cloudPrintChromeosOptionLabel", + IDS_CLOUD_PRINT_CHROMEOS_OPTION_LABEL }, + { "cloudPrintChromeosOptionButton", + IDS_CLOUD_PRINT_CHROMEOS_OPTION_BUTTON }, +#endif + { "cloudPrintOptionsStaticLabel", + IDS_CLOUD_PRINT_SETUP_DIALOG_TITLE }, + { "cloudPrintProxyEnabledManageButton", + IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLED_MANAGE_BUTTON }, + { "advancedSectionTitleCloudPrint", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_CLOUD_PRINT }, +#if !defined(OS_CHROMEOS) + { "cloudPrintProxyDisabledLabel", + IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_LABEL }, + { "cloudPrintProxyDisabledButton", + IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_BUTTON }, + { "cloudPrintProxyEnabledButton", + IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLED_BUTTON }, + { "cloudPrintProxyEnablingButton", + IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLING_BUTTON }, +#endif +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + { "advancedSectionTitleBackground", + IDS_OPTIONS_ADVANCED_SECTION_TITLE_BACKGROUND }, + { "backgroundModeCheckbox", + IDS_OPTIONS_BACKGROUND_ENABLE_BACKGROUND_MODE }, +#endif + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "advancedPage", + IDS_OPTIONS_ADVANCED_TAB_LABEL); + + localized_strings->SetString("privacyLearnMoreURL", + google_util::AppendGoogleLocaleParam( + GURL(chrome::kPrivacyLearnMoreURL)).spec()); + +#if defined(OS_CHROMEOS) + localized_strings->SetString("cloudPrintLearnMoreURL", + google_util::AppendGoogleLocaleParam( + GURL(chrome::kCloudPrintLearnMoreURL)).spec()); +#endif +} + +void AdvancedOptionsHandler::Initialize() { + DCHECK(web_ui_); + SetupMetricsReportingCheckbox(); + SetupMetricsReportingSettingVisibility(); + SetupFontSizeSelector(); + SetupPageZoomSelector(); + SetupAutoOpenFileTypesDisabledAttribute(); + SetupProxySettingsSection(); + SetupSSLConfigSettings(); +#if !defined(OS_CHROMEOS) + if (cloud_print_proxy_ui_enabled_) { + SetupCloudPrintProxySection(); + RefreshCloudPrintStatusFromService(); + } else { + RemoveCloudPrintProxySection(); + } +#endif +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + SetupBackgroundModeSettings(); +#endif + +} + +WebUIMessageHandler* AdvancedOptionsHandler::Attach(WebUI* web_ui) { + // Call through to superclass. + WebUIMessageHandler* handler = OptionsPage2UIHandler::Attach(web_ui); + + // Register for preferences that we need to observe manually. These have + // special behaviors that aren't handled by the standard prefs UI. + DCHECK(web_ui_); + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); +#if !defined(OS_CHROMEOS) + enable_metrics_recording_.Init(prefs::kMetricsReportingEnabled, + g_browser_process->local_state(), this); + cloud_print_proxy_email_.Init(prefs::kCloudPrintEmail, prefs, this); + cloud_print_proxy_enabled_.Init(prefs::kCloudPrintProxyEnabled, prefs, this); +#endif + + rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled, + g_browser_process->local_state(), this); + +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + background_mode_enabled_.Init(prefs::kBackgroundModeEnabled, + g_browser_process->local_state(), + this); +#endif + + auto_open_files_.Init(prefs::kDownloadExtensionsToOpen, prefs, this); + default_font_size_.Init(prefs::kWebKitDefaultFontSize, prefs, this); + default_zoom_level_.Init(prefs::kDefaultZoomLevel, prefs, this); +#if !defined(OS_CHROMEOS) + proxy_prefs_.reset( + PrefSetObserver::CreateProxyPrefSetObserver(prefs, this)); +#endif // !defined(OS_CHROMEOS) + + // Return result from the superclass. + return handler; +} + +void AdvancedOptionsHandler::RegisterMessages() { + // Setup handlers specific to this panel. + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("selectDownloadLocation", + base::Bind(&AdvancedOptionsHandler::HandleSelectDownloadLocation, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("autoOpenFileTypesAction", + base::Bind(&AdvancedOptionsHandler::HandleAutoOpenButton, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("defaultFontSizeAction", + base::Bind(&AdvancedOptionsHandler::HandleDefaultFontSize, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("defaultZoomFactorAction", + base::Bind(&AdvancedOptionsHandler::HandleDefaultZoomFactor, + base::Unretained(this))); +#if !defined(OS_CHROMEOS) + web_ui_->RegisterMessageCallback("metricsReportingCheckboxAction", + base::Bind(&AdvancedOptionsHandler::HandleMetricsReportingCheckbox, + base::Unretained(this))); +#endif +#if !defined(USE_NSS) && !defined(USE_OPENSSL) + web_ui_->RegisterMessageCallback("showManageSSLCertificates", + base::Bind(&AdvancedOptionsHandler::ShowManageSSLCertificates, + base::Unretained(this))); +#endif + web_ui_->RegisterMessageCallback("showCloudPrintManagePage", + base::Bind(&AdvancedOptionsHandler::ShowCloudPrintManagePage, + base::Unretained(this))); +#if !defined(OS_CHROMEOS) + if (cloud_print_proxy_ui_enabled_) { + web_ui_->RegisterMessageCallback("showCloudPrintSetupDialog", + base::Bind(&AdvancedOptionsHandler::ShowCloudPrintSetupDialog, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("disableCloudPrintProxy", + base::Bind(&AdvancedOptionsHandler::HandleDisableCloudPrintProxy, + base::Unretained(this))); + } + web_ui_->RegisterMessageCallback("showNetworkProxySettings", + base::Bind(&AdvancedOptionsHandler::ShowNetworkProxySettings, + base::Unretained(this))); +#endif + web_ui_->RegisterMessageCallback("checkRevocationCheckboxAction", + base::Bind(&AdvancedOptionsHandler::HandleCheckRevocationCheckbox, + base::Unretained(this))); +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + web_ui_->RegisterMessageCallback("backgroundModeAction", + base::Bind(&AdvancedOptionsHandler::HandleBackgroundModeCheckbox, + base::Unretained(this))); +#endif +} + +void AdvancedOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PREF_CHANGED) { + std::string* pref_name = content::Details<std::string>(details).ptr(); + if (*pref_name == prefs::kDownloadExtensionsToOpen) { + SetupAutoOpenFileTypesDisabledAttribute(); +#if !defined(OS_CHROMEOS) + } else if (proxy_prefs_->IsObserved(*pref_name)) { + SetupProxySettingsSection(); +#endif // !defined(OS_CHROMEOS) + } else if ((*pref_name == prefs::kCloudPrintEmail) || + (*pref_name == prefs::kCloudPrintProxyEnabled)) { +#if !defined(OS_CHROMEOS) + if (cloud_print_proxy_ui_enabled_) + SetupCloudPrintProxySection(); +#endif + } else if (*pref_name == prefs::kWebKitDefaultFontSize) { + SetupFontSizeSelector(); + } else if (*pref_name == prefs::kDefaultZoomLevel) { + SetupPageZoomSelector(); +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + } else if (*pref_name == prefs::kBackgroundModeEnabled) { + SetupBackgroundModeSettings(); +#endif + } + } +} + +void AdvancedOptionsHandler::HandleSelectDownloadLocation( + const ListValue* args) { + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + select_folder_dialog_ = SelectFileDialog::Create(this); + select_folder_dialog_->SelectFile( + SelectFileDialog::SELECT_FOLDER, + l10n_util::GetStringUTF16(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_TITLE), + pref_service->GetFilePath(prefs::kDownloadDefaultDirectory), + NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), + web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); +} + +void AdvancedOptionsHandler::FileSelected(const FilePath& path, int index, + void* params) { + UserMetrics::RecordAction(UserMetricsAction("Options_SetDownloadDirectory")); + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + pref_service->SetFilePath(prefs::kDownloadDefaultDirectory, path); +} + +void AdvancedOptionsHandler::OnCloudPrintSetupClosed() { +#if !defined(OS_CHROMEOS) + if (cloud_print_proxy_ui_enabled_) + SetupCloudPrintProxySection(); +#endif +} + +void AdvancedOptionsHandler::HandleAutoOpenButton(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_ResetAutoOpenFiles")); + DownloadManager* manager = + web_ui_->tab_contents()->browser_context()->GetDownloadManager(); + if (manager) + DownloadPrefs::FromDownloadManager(manager)->ResetAutoOpen(); +} + +void AdvancedOptionsHandler::HandleMetricsReportingCheckbox( + const ListValue* args) { +#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS) + std::string checked_str = UTF16ToUTF8(ExtractStringValue(args)); + bool enabled = checked_str == "true"; + UserMetrics::RecordAction( + enabled ? + UserMetricsAction("Options_MetricsReportingCheckbox_Enable") : + UserMetricsAction("Options_MetricsReportingCheckbox_Disable")); + bool is_enabled = OptionsUtil::ResolveMetricsReportingEnabled(enabled); + enable_metrics_recording_.SetValue(is_enabled); + SetupMetricsReportingCheckbox(); +#endif +} + +void AdvancedOptionsHandler::HandleDefaultFontSize(const ListValue* args) { + int font_size; + if (ExtractIntegerValue(args, &font_size)) { + if (font_size > 0) { + default_font_size_.SetValue(font_size); + SetupFontSizeSelector(); + } + } +} + +void AdvancedOptionsHandler::HandleDefaultZoomFactor(const ListValue* args) { + double zoom_factor; + if (ExtractDoubleValue(args, &zoom_factor)) { + default_zoom_level_.SetValue( + WebKit::WebView::zoomFactorToZoomLevel(zoom_factor)); + } +} + +void AdvancedOptionsHandler::HandleCheckRevocationCheckbox( + const ListValue* args) { + std::string checked_str = UTF16ToUTF8(ExtractStringValue(args)); + bool enabled = checked_str == "true"; + UserMetrics::RecordAction( + enabled ? + UserMetricsAction("Options_CheckCertRevocation_Enable") : + UserMetricsAction("Options_CheckCertRevocation_Disable")); + rev_checking_enabled_.SetValue(enabled); +} + +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) +void AdvancedOptionsHandler::HandleBackgroundModeCheckbox( + const ListValue* args) { + std::string checked_str = UTF16ToUTF8(ExtractStringValue(args)); + bool enabled = checked_str == "true"; + UserMetrics::RecordAction(enabled ? + UserMetricsAction("Options_BackgroundMode_Enable") : + UserMetricsAction("Options_BackgroundMode_Disable")); + background_mode_enabled_.SetValue(enabled); +} + +void AdvancedOptionsHandler::SetupBackgroundModeSettings() { + base::FundamentalValue checked(background_mode_enabled_.GetValue()); + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetBackgroundModeCheckboxState", checked); +} +#endif + +#if !defined(OS_CHROMEOS) +void AdvancedOptionsHandler::ShowNetworkProxySettings(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_ShowProxySettings")); + AdvancedOptionsUtilities::ShowNetworkProxySettings(web_ui_->tab_contents()); +} +#endif + +#if !defined(USE_NSS) && !defined(USE_OPENSSL) +void AdvancedOptionsHandler::ShowManageSSLCertificates(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_ManageSSLCertificates")); + AdvancedOptionsUtilities::ShowManageSSLCertificates(web_ui_->tab_contents()); +} +#endif + +void AdvancedOptionsHandler::ShowCloudPrintManagePage(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_ManageCloudPrinters")); + // Open a new tab in the current window for the management page. + Profile* profile = Profile::FromWebUI(web_ui_); + web_ui_->tab_contents()->OpenURL( + CloudPrintURL(profile).GetCloudPrintServiceManageURL(), + GURL(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK); +} + +#if !defined(OS_CHROMEOS) +void AdvancedOptionsHandler::ShowCloudPrintSetupDialog(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_EnableCloudPrintProxy")); + // Open the connector enable page in the current tab. + Profile* profile = Profile::FromWebUI(web_ui_); + web_ui_->tab_contents()->OpenURL( + CloudPrintURL(profile).GetCloudPrintServiceEnableURL( + CloudPrintProxyServiceFactory::GetForProfile(profile)->proxy_id()), + GURL(), CURRENT_TAB, content::PAGE_TRANSITION_LINK); +} + +void AdvancedOptionsHandler::HandleDisableCloudPrintProxy( + const ListValue* args) { + UserMetrics::RecordAction( + UserMetricsAction("Options_DisableCloudPrintProxy")); + CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui_))-> + DisableForUser(); +} + +void AdvancedOptionsHandler::RefreshCloudPrintStatusFromService() { + if (cloud_print_proxy_ui_enabled_) + CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui_))-> + RefreshStatusFromService(); +} + +void AdvancedOptionsHandler::SetupCloudPrintProxySection() { + Profile* profile = Profile::FromWebUI(web_ui_); + if (!CloudPrintProxyServiceFactory::GetForProfile(profile)) { + cloud_print_proxy_ui_enabled_ = false; + RemoveCloudPrintProxySection(); + return; + } + + bool cloud_print_proxy_allowed = + !cloud_print_proxy_enabled_.IsManaged() || + cloud_print_proxy_enabled_.GetValue(); + base::FundamentalValue allowed(cloud_print_proxy_allowed); + + std::string email; + if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) && + cloud_print_proxy_allowed) { + email = profile->GetPrefs()->GetString(prefs::kCloudPrintEmail); + } + base::FundamentalValue disabled(email.empty()); + + string16 label_str; + if (email.empty()) { + label_str = l10n_util::GetStringUTF16( + IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_LABEL); + } else { + label_str = l10n_util::GetStringFUTF16( + IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLED_LABEL, UTF8ToUTF16(email)); + } + StringValue label(label_str); + + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetupCloudPrintProxySection", + disabled, label, allowed); +} + +void AdvancedOptionsHandler::RemoveCloudPrintProxySection() { + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.RemoveCloudPrintProxySection"); +} + +#endif + +void AdvancedOptionsHandler::SetupMetricsReportingCheckbox() { +#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS) + base::FundamentalValue checked(enable_metrics_recording_.GetValue()); + base::FundamentalValue disabled(enable_metrics_recording_.IsManaged()); + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetMetricsReportingCheckboxState", checked, + disabled); +#endif +} + +void AdvancedOptionsHandler::SetupMetricsReportingSettingVisibility() { +#if defined(GOOGLE_CHROME_BUILD) && defined(OS_CHROMEOS) + // Don't show the reporting setting if we are in the guest mode. + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) { + base::FundamentalValue visible(false); + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetMetricsReportingSettingVisibility", + visible); + } +#endif +} + +void AdvancedOptionsHandler::SetupFontSizeSelector() { + // We're only interested in integer values, so convert to int. + base::FundamentalValue font_size(default_font_size_.GetValue()); + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetFontSize", font_size); +} + +void AdvancedOptionsHandler::SetupPageZoomSelector() { + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + double default_zoom_level = pref_service->GetDouble(prefs::kDefaultZoomLevel); + double default_zoom_factor = + WebKit::WebView::zoomLevelToZoomFactor(default_zoom_level); + + // Generate a vector of zoom factors from an array of known presets along with + // the default factor added if necessary. + std::vector<double> zoom_factors = + chrome_page_zoom::PresetZoomFactors(default_zoom_factor); + + // Iterate through the zoom factors and and build the contents of the + // selector that will be sent to the javascript handler. + // Each item in the list has the following parameters: + // 1. Title (string). + // 2. Value (double). + // 3. Is selected? (bool). + ListValue zoom_factors_value; + for (std::vector<double>::const_iterator i = zoom_factors.begin(); + i != zoom_factors.end(); ++i) { + ListValue* option = new ListValue(); + double factor = *i; + int percent = static_cast<int>(factor * 100 + 0.5); + option->Append(Value::CreateStringValue( + l10n_util::GetStringFUTF16Int(IDS_ZOOM_PERCENT, percent))); + option->Append(Value::CreateDoubleValue(factor)); + bool selected = content::ZoomValuesEqual(factor, default_zoom_factor); + option->Append(Value::CreateBooleanValue(selected)); + zoom_factors_value.Append(option); + } + + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetupPageZoomSelector", zoom_factors_value); +} + +void AdvancedOptionsHandler::SetupAutoOpenFileTypesDisabledAttribute() { + // Set the enabled state for the AutoOpenFileTypesResetToDefault button. + // We enable the button if the user has any auto-open file types registered. + DownloadManager* manager = + web_ui_->tab_contents()->browser_context()->GetDownloadManager(); + bool disabled = !(manager && + DownloadPrefs::FromDownloadManager(manager)->IsAutoOpenUsed()); + base::FundamentalValue value(disabled); + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetAutoOpenFileTypesDisabledAttribute", value); +} + +void AdvancedOptionsHandler::SetupProxySettingsSection() { +#if !defined(OS_CHROMEOS) + // Disable the button if proxy settings are managed by a sysadmin or + // overridden by an extension. + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + const PrefService::Preference* proxy_config = + pref_service->FindPreference(prefs::kProxy); + bool is_extension_controlled = (proxy_config && + proxy_config->IsExtensionControlled()); + + base::FundamentalValue disabled(proxy_prefs_->IsManaged() || + is_extension_controlled); + + // Get the appropriate info string to describe the button. + string16 label_str; + if (is_extension_controlled) { + label_str = l10n_util::GetStringUTF16(IDS_OPTIONS_EXTENSION_PROXIES_LABEL); + } else { + label_str = l10n_util::GetStringFUTF16(IDS_OPTIONS_SYSTEM_PROXIES_LABEL, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); + } + StringValue label(label_str); + + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetupProxySettingsSection", disabled, label); +#endif // !defined(OS_CHROMEOS) +} + +void AdvancedOptionsHandler::SetupSSLConfigSettings() { + { + base::FundamentalValue checked(rev_checking_enabled_.GetValue()); + base::FundamentalValue disabled(rev_checking_enabled_.IsManaged()); + web_ui_->CallJavascriptFunction( + "options.AdvancedOptions.SetCheckRevocationCheckboxState", checked, + disabled); + } +} diff --git a/chrome/browser/ui/webui/options2/advanced_options_handler.h b/chrome/browser/ui/webui/options2/advanced_options_handler.h new file mode 100644 index 0000000..ed3a49b --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_handler.h @@ -0,0 +1,182 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_ADVANCED_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_ADVANCED_OPTIONS_HANDLER_H_ +#pragma once + +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/printing/cloud_print/cloud_print_setup_handler.h" +#include "chrome/browser/ui/select_file_dialog.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +#if !defined(OS_CHROMEOS) +#include "chrome/browser/prefs/pref_set_observer.h" +#endif // !defined(OS_CHROMEOS) + +class CloudPrintSetupHandler; + +// Chrome advanced options page UI handler. +class AdvancedOptionsHandler + : public OptionsPage2UIHandler, + public SelectFileDialog::Listener, + public CloudPrintSetupHandlerDelegate { + public: + AdvancedOptionsHandler(); + virtual ~AdvancedOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler implementation. + virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // SelectFileDialog::Listener implementation + virtual void FileSelected(const FilePath& path, + int index, + void* params) OVERRIDE; + + // CloudPrintSetupHandler::Delegate implementation. + virtual void OnCloudPrintSetupClosed() OVERRIDE; + + private: + // Callback for the "selectDownloadLocation" message. This will prompt the + // user for a destination folder using platform-specific APIs. + void HandleSelectDownloadLocation(const ListValue* args); + + // Callback for the "autoOpenFileTypesResetToDefault" message. This will + // remove all auto-open file-type settings. + void HandleAutoOpenButton(const ListValue* args); + + // Callback for the "metricsReportingCheckboxAction" message. This is called + // if the user toggles the metrics reporting checkbox. + void HandleMetricsReportingCheckbox(const ListValue* args); + + // Callback for the "defaultFontSizeAction" message. This is called if the + // user changes the default font size. |args| is an array that contains + // one item, the font size as a numeric value. + void HandleDefaultFontSize(const ListValue* args); + + // Callback for the "defaultZoomFactorAction" message. This is called if the + // user changes the default zoom factor. |args| is an array that contains + // one item, the zoom factor as a numeric value. + void HandleDefaultZoomFactor(const ListValue* args); + + // Callback for the "Check for server certificate revocation" checkbox. This + // is called if the user toggles the "Check for server certificate revocation" + // checkbox. + void HandleCheckRevocationCheckbox(const ListValue* args); + + // Callback for the "Use SSL 3.0" checkbox. This is called if the user toggles + // the "Use SSL 3.0" checkbox. + void HandleUseSSL3Checkbox(const ListValue* args); + + // Callback for the "Use TLS 1.0" checkbox. This is called if the user toggles + // the "Use TLS 1.0" checkbox. + void HandleUseTLS1Checkbox(const ListValue* args); + +#if !defined(OS_CHROMEOS) + // Callback for the "showNetworkProxySettings" message. This will invoke + // an appropriate dialog for configuring proxy settings. + void ShowNetworkProxySettings(const ListValue* args); +#endif + +#if !defined(USE_NSS) + // Callback for the "showManageSSLCertificates" message. This will invoke + // an appropriate certificate management action based on the platform. + void ShowManageSSLCertificates(const ListValue* args); +#endif + + // Callback for the Cloud Print manage button. This will open a new + // tab pointed at the management URL. + void ShowCloudPrintManagePage(const ListValue* args); + +#if !defined(OS_CHROMEOS) + // Callback for the Sign in to Cloud Print button. This will start + // the authentication process. + void ShowCloudPrintSetupDialog(const ListValue* args); + + // Callback for the Disable Cloud Print button. This will sign out + // of cloud print. + void HandleDisableCloudPrintProxy(const ListValue* args); + + // Pings the service to send us it's current notion of the enabled state. + void RefreshCloudPrintStatusFromService(); + + // Setup the enabled or disabled state of the cloud print proxy + // management UI. + void SetupCloudPrintProxySection(); + + // Remove cloud print proxy section if cloud print proxy management UI is + // disabled. + void RemoveCloudPrintProxySection(); + +#endif + +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + // Sets up the checked state for the "Continue running background apps..." + // checkbox. + void SetupBackgroundModeSettings(); + + // Callback for the "Continue running background apps..." checkbox. + void HandleBackgroundModeCheckbox(const ListValue* args); +#endif + + // Setup the checked state for the metrics reporting checkbox. + void SetupMetricsReportingCheckbox(); + + // Setup the visibility for the metrics reporting setting. + void SetupMetricsReportingSettingVisibility(); + + // Setup the font size selector control. + void SetupFontSizeSelector(); + + // Setup the page zoom selector control. + void SetupPageZoomSelector(); + + // Setup the enabled state of the reset button. + void SetupAutoOpenFileTypesDisabledAttribute(); + + // Setup the proxy settings section UI. + void SetupProxySettingsSection(); + + // Setup the checked state for SSL related checkboxes. + void SetupSSLConfigSettings(); + + scoped_refptr<SelectFileDialog> select_folder_dialog_; + +#if !defined(OS_CHROMEOS) + BooleanPrefMember enable_metrics_recording_; + StringPrefMember cloud_print_proxy_email_; + BooleanPrefMember cloud_print_proxy_enabled_; + bool cloud_print_proxy_ui_enabled_; + scoped_ptr<CloudPrintSetupHandler> cloud_print_setup_handler_; +#endif + + // SSLConfigService prefs. + BooleanPrefMember rev_checking_enabled_; + +#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) + BooleanPrefMember background_mode_enabled_; +#endif + + StringPrefMember auto_open_files_; + IntegerPrefMember default_font_size_; + DoublePrefMember default_zoom_level_; + +#if !defined(OS_CHROMEOS) + scoped_ptr<PrefSetObserver> proxy_prefs_; +#endif // !defined(OS_CHROMEOS) + + DISALLOW_COPY_AND_ASSIGN(AdvancedOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_ADVANCED_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/advanced_options_utils.h b/chrome/browser/ui/webui/options2/advanced_options_utils.h new file mode 100644 index 0000000..edaacf5 --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_utils.h @@ -0,0 +1,25 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_ADVANCED_OPTIONS_UTILS_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_ADVANCED_OPTIONS_UTILS_H_ + +#include "base/basictypes.h" + +class TabContents; + +// Chrome advanced options utility methods. +class AdvancedOptionsUtilities { + public: + // Invoke UI for network proxy settings. + static void ShowNetworkProxySettings(TabContents*); + + // Invoke UI for SSL certificates. + static void ShowManageSSLCertificates(TabContents*); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(AdvancedOptionsUtilities); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_ADVANCED_OPTIONS_UTILS_H_ diff --git a/chrome/browser/ui/webui/options2/advanced_options_utils_mac.mm b/chrome/browser/ui/webui/options2/advanced_options_utils_mac.mm new file mode 100644 index 0000000..c1e5b52 --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_utils_mac.mm @@ -0,0 +1,41 @@ +// Copyright (c) 2011 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 <Cocoa/Cocoa.h> + +#include "chrome/browser/ui/webui/options2/advanced_options_utils.h" + +#include "base/logging.h" +#include "base/mac/scoped_aedesc.h" + +void AdvancedOptionsUtilities::ShowNetworkProxySettings( + TabContents* tab_contents) { + NSArray* itemsToOpen = [NSArray arrayWithObject:[NSURL fileURLWithPath: + @"/System/Library/PreferencePanes/Network.prefPane"]]; + + const char* proxyPrefCommand = "Proxies"; + base::mac::ScopedAEDesc<> openParams; + OSStatus status = AECreateDesc('ptru', + proxyPrefCommand, + strlen(proxyPrefCommand), + openParams.OutPointer()); + LOG_IF(ERROR, status != noErr) << "Failed to create open params: " << status; + + LSLaunchURLSpec launchSpec = { 0 }; + launchSpec.itemURLs = (CFArrayRef)itemsToOpen; + launchSpec.passThruParams = openParams; + launchSpec.launchFlags = kLSLaunchAsync | kLSLaunchDontAddToRecents; + LSOpenFromURLSpec(&launchSpec, NULL); +} + +void AdvancedOptionsUtilities::ShowManageSSLCertificates( + TabContents* tab_contents) { + NSString* const kKeychainBundleId = @"com.apple.keychainaccess"; + [[NSWorkspace sharedWorkspace] + launchAppWithBundleIdentifier:kKeychainBundleId + options:0L + additionalEventParamDescriptor:nil + launchIdentifier:nil]; +} + diff --git a/chrome/browser/ui/webui/options2/advanced_options_utils_win.cc b/chrome/browser/ui/webui/options2/advanced_options_utils_win.cc new file mode 100644 index 0000000..5942ff9 --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_utils_win.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/advanced_options_utils.h" + +#include <windows.h> +#include <cryptuiapi.h> +#pragma comment(lib, "cryptui.lib") +#include <shellapi.h> + +#include "base/bind.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/threading/thread.h" +#include "chrome/browser/browser_process.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_view.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +// Callback that opens the Internet Options control panel dialog with the +// Connections tab selected. +void OpenConnectionDialogCallback() { + // Using rundll32 seems better than LaunchConnectionDialog which causes a + // new dialog to be made for each call. rundll32 uses the same global + // dialog and it seems to share with the shortcut in control panel. + FilePath rundll32; + PathService::Get(base::DIR_SYSTEM, &rundll32); + rundll32 = rundll32.AppendASCII("rundll32.exe"); + + FilePath shell32dll; + PathService::Get(base::DIR_SYSTEM, &shell32dll); + shell32dll = shell32dll.AppendASCII("shell32.dll"); + + FilePath inetcpl; + PathService::Get(base::DIR_SYSTEM, &inetcpl); + inetcpl = inetcpl.AppendASCII("inetcpl.cpl,,4"); + + std::wstring args(shell32dll.value()); + args.append(L",Control_RunDLL "); + args.append(inetcpl.value()); + + ShellExecute(NULL, L"open", rundll32.value().c_str(), args.c_str(), NULL, + SW_SHOWNORMAL); +} + +void AdvancedOptionsUtilities::ShowNetworkProxySettings( + TabContents* tab_contents) { + DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::FILE)); + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&OpenConnectionDialogCallback)); +} + +void AdvancedOptionsUtilities::ShowManageSSLCertificates( + TabContents* tab_contents) { + CRYPTUI_CERT_MGR_STRUCT cert_mgr = { 0 }; + cert_mgr.dwSize = sizeof(CRYPTUI_CERT_MGR_STRUCT); + cert_mgr.hwndParent = +#if defined(USE_AURA) + NULL; +#else + tab_contents->view()->GetTopLevelNativeWindow(); +#endif + ::CryptUIDlgCertMgr(&cert_mgr); +} diff --git a/chrome/browser/ui/webui/options2/advanced_options_utils_x11.cc b/chrome/browser/ui/webui/options2/advanced_options_utils_x11.cc new file mode 100644 index 0000000..20579b3 --- /dev/null +++ b/chrome/browser/ui/webui/options2/advanced_options_utils_x11.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 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. + +#if !defined(OS_CHROMEOS) + +#include "chrome/browser/ui/webui/options2/advanced_options_utils.h" + +#include "base/bind.h" +#include "base/environment.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/nix/xdg_util.h" +#include "base/process_util.h" +#include "base/string_util.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +// Command used to configure GNOME 2 proxy settings. +const char* kGNOME2ProxyConfigCommand[] = {"gnome-network-properties", NULL}; +// In GNOME 3, we might need to run gnome-control-center instead. We try this +// only after gnome-network-properties is not found, because older GNOME also +// has this but it doesn't do the same thing. See below where we use it. +const char* kGNOME3ProxyConfigCommand[] = {"gnome-control-center", "network", + NULL}; +// KDE3 and KDE4 are only slightly different, but incompatible. Go figure. +const char* kKDE3ProxyConfigCommand[] = {"kcmshell", "proxy", NULL}; +const char* kKDE4ProxyConfigCommand[] = {"kcmshell4", "proxy", NULL}; + +// The URL for Linux proxy configuration help when not running under a +// supported desktop environment. +const char kLinuxProxyConfigUrl[] = "about:linux-proxy-config"; + +namespace { + +// Show the proxy config URL in the given tab. +void ShowLinuxProxyConfigUrl(TabContents* tab_contents) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + scoped_ptr<base::Environment> env(base::Environment::Create()); + const char* name = base::nix::GetDesktopEnvironmentName(env.get()); + if (name) + LOG(ERROR) << "Could not find " << name << " network settings in $PATH"; + tab_contents->OpenURL(GURL(kLinuxProxyConfigUrl), GURL(), + NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK); +} + +// Start the given proxy configuration utility. +bool StartProxyConfigUtil(TabContents* tab_contents, const char* command[]) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + // base::LaunchProcess() returns true ("success") if the fork() + // succeeds, but not necessarily the exec(). We'd like to be able to + // use StartProxyConfigUtil() to search possible options and stop on + // success, so we search $PATH first to predict whether the exec is + // expected to succeed. + // TODO(mdm): this is a useful check, and is very similar to some + // code in proxy_config_service_linux.cc. It should probably be in + // base:: somewhere. + scoped_ptr<base::Environment> env(base::Environment::Create()); + std::string path; + if (!env->GetVar("PATH", &path)) { + LOG(ERROR) << "No $PATH variable. Assuming no " << command[0] << "."; + return false; + } + std::vector<std::string> paths; + Tokenize(path, ":", &paths); + bool found = false; + for (size_t i = 0; i < paths.size(); ++i) { + FilePath file(paths[i]); + if (file_util::PathExists(file.Append(command[0]))) { + found = true; + break; + } + } + if (!found) + return false; + std::vector<std::string> argv; + for (size_t i = 0; command[i]; ++i) + argv.push_back(command[i]); + base::ProcessHandle handle; + if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) { + LOG(ERROR) << "StartProxyConfigUtil failed to start " << command[0]; + return false; + } + base::EnsureProcessGetsReaped(handle); + return true; +} + +// Detect, and if possible, start the appropriate proxy config utility. On +// failure to do so, show the Linux proxy config URL in a new tab instead. +void DetectAndStartProxyConfigUtil(TabContents* tab_contents) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + scoped_ptr<base::Environment> env(base::Environment::Create()); + + bool launched = false; + switch (base::nix::GetDesktopEnvironment(env.get())) { + case base::nix::DESKTOP_ENVIRONMENT_GNOME: { + launched = StartProxyConfigUtil(tab_contents, kGNOME2ProxyConfigCommand); + if (!launched) { + // We try this second, even though it's the newer way, because this + // command existed in older versions of GNOME, but it didn't do the + // same thing. The older command is gone though, so this should do + // the right thing. (Also some distributions have blurred the lines + // between GNOME 2 and 3, so we can't necessarily detect what the + // right thing is based on indications of which version we have.) + launched = StartProxyConfigUtil(tab_contents, + kGNOME3ProxyConfigCommand); + } + break; + } + + case base::nix::DESKTOP_ENVIRONMENT_KDE3: + launched = StartProxyConfigUtil(tab_contents, kKDE3ProxyConfigCommand); + break; + + case base::nix::DESKTOP_ENVIRONMENT_KDE4: + launched = StartProxyConfigUtil(tab_contents, kKDE4ProxyConfigCommand); + break; + + case base::nix::DESKTOP_ENVIRONMENT_XFCE: + case base::nix::DESKTOP_ENVIRONMENT_OTHER: + break; + } + + if (launched) + return; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&ShowLinuxProxyConfigUrl, tab_contents)); +} + +} // anonymous namespace + +void AdvancedOptionsUtilities::ShowNetworkProxySettings( + TabContents* tab_contents) { + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&DetectAndStartProxyConfigUtil, tab_contents)); +} + +#endif // !defined(OS_CHROMEOS) diff --git a/chrome/browser/ui/webui/options2/autofill_options_browsertest.js b/chrome/browser/ui/webui/options2/autofill_options_browsertest.js new file mode 100644 index 0000000..d9a5c9b --- /dev/null +++ b/chrome/browser/ui/webui/options2/autofill_options_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for autofill options WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function AutofillOptionsWebUITest() {} + +AutofillOptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to autofill options. + **/ + browsePreload: 'chrome://settings/autofill', +}; + +// Test opening the autofill options has correct location. +TEST_F('AutofillOptionsWebUITest', 'testOpenAutofillOptions', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/autofill_options_handler.cc b/chrome/browser/ui/webui/options2/autofill_options_handler.cc new file mode 100644 index 0000000..f751e635 --- /dev/null +++ b/chrome/browser/ui/webui/options2/autofill_options_handler.cc @@ -0,0 +1,614 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/autofill_options_handler.h" + +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/autofill/autofill_country.h" +#include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/autofill/credit_card.h" +#include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/autofill/personal_data_manager_factory.h" +#include "chrome/browser/autofill/phone_number_i18n.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/web_ui_util.h" +#include "chrome/common/guid.h" +#include "grit/generated_resources.h" +#include "grit/webkit_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +// Converts a credit card type to the appropriate resource ID of the CC icon. +int CreditCardTypeToResourceID(const std::string& type) { + if (type == kAmericanExpressCard) + return IDR_AUTOFILL_CC_AMEX; + else if (type == kDinersCard) + return IDR_AUTOFILL_CC_DINERS; + else if (type == kDiscoverCard) + return IDR_AUTOFILL_CC_DISCOVER; + else if (type == kGenericCard) + return IDR_AUTOFILL_CC_GENERIC; + else if (type == kJCBCard) + return IDR_AUTOFILL_CC_JCB; + else if (type == kMasterCard) + return IDR_AUTOFILL_CC_MASTERCARD; + else if (type == kSoloCard) + return IDR_AUTOFILL_CC_SOLO; + else if (type == kVisaCard) + return IDR_AUTOFILL_CC_VISA; + + NOTREACHED(); + return 0; +} + +// Converts a credit card type to the appropriate localized card type. +string16 LocalizedCreditCardType(const std::string& type) { + if (type == kAmericanExpressCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX); + else if (type == kDinersCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS); + else if (type == kDiscoverCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER); + else if (type == kGenericCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GENERIC); + else if (type == kJCBCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB); + else if (type == kMasterCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD); + else if (type == kSoloCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_SOLO); + else if (type == kVisaCard) + return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA); + + NOTREACHED(); + return string16(); +} + +// Returns a dictionary that maps country codes to data for the country. +DictionaryValue* GetCountryData() { + std::string app_locale = AutofillCountry::ApplicationLocale(); + std::vector<std::string> country_codes; + AutofillCountry::GetAvailableCountries(&country_codes); + + DictionaryValue* country_data = new DictionaryValue(); + for (size_t i = 0; i < country_codes.size(); ++i) { + const AutofillCountry country(country_codes[i], app_locale); + + DictionaryValue* details = new DictionaryValue(); + details->SetString("name", country.name()); + details->SetString("postalCodeLabel", country.postal_code_label()); + details->SetString("stateLabel", country.state_label()); + + country_data->Set(country.country_code(), details); + } + + return country_data; +} + +// Get the multi-valued element for |type| and return it in |ListValue| form. +void GetValueList(const AutofillProfile& profile, + AutofillFieldType type, + scoped_ptr<ListValue>* list) { + list->reset(new ListValue); + + std::vector<string16> values; + profile.GetMultiInfo(type, &values); + + // |GetMultiInfo()| always returns at least one, potentially empty, item. + if (values.size() == 1 && values.front().empty()) + return; + + for (size_t i = 0; i < values.size(); ++i) { + (*list)->Set(i, Value::CreateStringValue(values[i])); + } +} + +// Set the multi-valued element for |type| from input |list| values. +void SetValueList(const ListValue* list, + AutofillFieldType type, + AutofillProfile* profile) { + std::vector<string16> values(list->GetSize()); + for (size_t i = 0; i < list->GetSize(); ++i) { + string16 value; + if (list->GetString(i, &value)) + values[i] = value; + } + profile->SetMultiInfo(type, values); +} + +// Get the multi-valued element for |type| and return it in |ListValue| form. +void GetNameList(const AutofillProfile& profile, + scoped_ptr<ListValue>* names) { + names->reset(new ListValue); + + std::vector<string16> first_names; + std::vector<string16> middle_names; + std::vector<string16> last_names; + profile.GetMultiInfo(NAME_FIRST, &first_names); + profile.GetMultiInfo(NAME_MIDDLE, &middle_names); + profile.GetMultiInfo(NAME_LAST, &last_names); + DCHECK_EQ(first_names.size(), middle_names.size()); + DCHECK_EQ(first_names.size(), last_names.size()); + + // |GetMultiInfo()| always returns at least one, potentially empty, item. + if (first_names.size() == 1 && first_names.front().empty() && + middle_names.front().empty() && last_names.front().empty()) { + return; + } + + for (size_t i = 0; i < first_names.size(); ++i) { + ListValue* name = new ListValue; // owned by |list| + name->Set(0, Value::CreateStringValue(first_names[i])); + name->Set(1, Value::CreateStringValue(middle_names[i])); + name->Set(2, Value::CreateStringValue(last_names[i])); + (*names)->Set(i, name); + } +} + +// Set the multi-valued element for |type| from input |list| values. +void SetNameList(const ListValue* names, + AutofillProfile* profile) { + const size_t size = names->GetSize(); + std::vector<string16> first_names(size); + std::vector<string16> middle_names(size); + std::vector<string16> last_names(size); + + for (size_t i = 0; i < size; ++i) { + ListValue* name; + bool success = names->GetList(i, &name); + DCHECK(success); + + string16 first_name; + success = name->GetString(0, &first_name); + DCHECK(success); + first_names[i] = first_name; + + string16 middle_name; + success = name->GetString(1, &middle_name); + DCHECK(success); + middle_names[i] = middle_name; + + string16 last_name; + success = name->GetString(2, &last_name); + DCHECK(success); + last_names[i] = last_name; + } + + profile->SetMultiInfo(NAME_FIRST, first_names); + profile->SetMultiInfo(NAME_MIDDLE, middle_names); + profile->SetMultiInfo(NAME_LAST, last_names); +} + +// Pulls the phone number |index|, |phone_number_list|, and |country_code| from +// the |args| input. +void ExtractPhoneNumberInformation(const ListValue* args, + size_t* index, + ListValue** phone_number_list, + std::string* country_code) { + // Retrieve index as a |double|, as that is how it comes across from + // JavaScript. + double number = 0.0; + if (!args->GetDouble(0, &number)) { + NOTREACHED(); + return; + } + *index = number; + + if (!args->GetList(1, phone_number_list)) { + NOTREACHED(); + return; + } + + if (!args->GetString(2, country_code)) { + NOTREACHED(); + return; + } +} + +// Searches the |list| for the value at |index|. If this value is present +// in any of the rest of the list, then the item (at |index|) is removed. +// The comparison of phone number values is done on normalized versions of the +// phone number values. +void RemoveDuplicatePhoneNumberAtIndex(size_t index, + const std::string& country_code, + ListValue* list) { + string16 new_value; + if (!list->GetString(index, &new_value)) { + NOTREACHED() << "List should have a value at index " << index; + return; + } + + bool is_duplicate = false; + for (size_t i = 0; i < list->GetSize() && !is_duplicate; ++i) { + if (i == index) + continue; + + string16 existing_value; + if (!list->GetString(i, &existing_value)) { + NOTREACHED() << "List should have a value at index " << i; + continue; + } + is_duplicate = autofill_i18n::PhoneNumbersMatch(new_value, + existing_value, + country_code); + } + + if (is_duplicate) + list->Remove(index, NULL); +} + +void ValidatePhoneArguments(const ListValue* args, ListValue** list) { + size_t index = 0; + std::string country_code; + ExtractPhoneNumberInformation(args, &index, list, &country_code); + + RemoveDuplicatePhoneNumberAtIndex(index, country_code, *list); +} + +} // namespace + +AutofillOptionsHandler::AutofillOptionsHandler() + : personal_data_(NULL) { +} + +AutofillOptionsHandler::~AutofillOptionsHandler() { + if (personal_data_) + personal_data_->RemoveObserver(this); +} + +///////////////////////////////////////////////////////////////////////////// +// OptionsPageUIHandler implementation: +void AutofillOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "autofillAddresses", IDS_AUTOFILL_ADDRESSES_GROUP_NAME }, + { "autofillCreditCards", IDS_AUTOFILL_CREDITCARDS_GROUP_NAME }, + { "autofillAddAddress", IDS_AUTOFILL_ADD_ADDRESS_BUTTON }, + { "autofillAddCreditCard", IDS_AUTOFILL_ADD_CREDITCARD_BUTTON }, + { "autofillEditProfileButton", IDS_AUTOFILL_EDIT_PROFILE_BUTTON }, + { "helpButton", IDS_AUTOFILL_HELP_LABEL }, + { "addAddressTitle", IDS_AUTOFILL_ADD_ADDRESS_CAPTION }, + { "editAddressTitle", IDS_AUTOFILL_EDIT_ADDRESS_CAPTION }, + { "addCreditCardTitle", IDS_AUTOFILL_ADD_CREDITCARD_CAPTION }, + { "editCreditCardTitle", IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION }, +#if defined(OS_MACOSX) + { "auxiliaryProfilesEnabled", IDS_AUTOFILL_USE_MAC_ADDRESS_BOOK }, +#endif // defined(OS_MACOSX) + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "autofillOptionsPage", + IDS_AUTOFILL_OPTIONS_TITLE); + + SetAddressOverlayStrings(localized_strings); + SetCreditCardOverlayStrings(localized_strings); +} + +void AutofillOptionsHandler::Initialize() { + personal_data_ = PersonalDataManagerFactory::GetForProfile( + Profile::FromWebUI(web_ui_)); + // personal_data_ is NULL in guest mode on Chrome OS. + if (personal_data_) { + personal_data_->SetObserver(this); + LoadAutofillData(); + } +} + +void AutofillOptionsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback( + "removeAddress", + base::Bind(&AutofillOptionsHandler::RemoveAddress, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "removeCreditCard", + base::Bind(&AutofillOptionsHandler::RemoveCreditCard, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "loadAddressEditor", + base::Bind(&AutofillOptionsHandler::LoadAddressEditor, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "loadCreditCardEditor", + base::Bind(&AutofillOptionsHandler::LoadCreditCardEditor, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "setAddress", + base::Bind(&AutofillOptionsHandler::SetAddress, base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "setCreditCard", + base::Bind(&AutofillOptionsHandler::SetCreditCard, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "validatePhoneNumbers", + base::Bind(&AutofillOptionsHandler::ValidatePhoneNumbers, + base::Unretained(this))); +} + +///////////////////////////////////////////////////////////////////////////// +// PersonalDataManagerObserver implementation: +void AutofillOptionsHandler::OnPersonalDataChanged() { + LoadAutofillData(); +} + +void AutofillOptionsHandler::SetAddressOverlayStrings( + DictionaryValue* localized_strings) { + localized_strings->SetString("autofillEditAddressTitle", + l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_CAPTION)); + localized_strings->SetString("autofillFirstNameLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_FIRST_NAME)); + localized_strings->SetString("autofillMiddleNameLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MIDDLE_NAME)); + localized_strings->SetString("autofillLastNameLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_LAST_NAME)); + localized_strings->SetString("autofillCompanyNameLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_COMPANY_NAME)); + localized_strings->SetString("autofillAddrLine1Label", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_1)); + localized_strings->SetString("autofillAddrLine2Label", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_2)); + localized_strings->SetString("autofillCityLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CITY)); + localized_strings->SetString("autofillCountryLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_COUNTRY)); + localized_strings->SetString("autofillPhoneLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PHONE)); + localized_strings->SetString("autofillEmailLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EMAIL)); + localized_strings->SetString("autofillAddFirstNamePlaceholder", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_FIRST_NAME)); + localized_strings->SetString("autofillAddMiddleNamePlaceholder", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_MIDDLE_NAME)); + localized_strings->SetString("autofillAddLastNamePlaceholder", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_LAST_NAME)); + localized_strings->SetString("autofillAddPhonePlaceholder", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_PHONE)); + localized_strings->SetString("autofillAddEmailPlaceholder", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_EMAIL)); + + std::string app_locale = AutofillCountry::ApplicationLocale(); + std::string default_country_code = + AutofillCountry::CountryCodeForLocale(app_locale); + localized_strings->SetString("defaultCountryCode", default_country_code); + localized_strings->Set("autofillCountryData", GetCountryData()); +} + +void AutofillOptionsHandler::SetCreditCardOverlayStrings( + DictionaryValue* localized_strings) { + localized_strings->SetString("autofillEditCreditCardTitle", + l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION)); + localized_strings->SetString("nameOnCardLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NAME_ON_CARD)); + localized_strings->SetString("creditCardNumberLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER)); + localized_strings->SetString("creditCardExpirationDateLabel", + l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EXPIRATION_DATE)); +} + +void AutofillOptionsHandler::LoadAutofillData() { + if (!personal_data_->IsDataLoaded()) + return; + + ListValue addresses; + for (std::vector<AutofillProfile*>::const_iterator i = + personal_data_->web_profiles().begin(); + i != personal_data_->web_profiles().end(); ++i) { + ListValue* entry = new ListValue(); + entry->Append(new StringValue((*i)->guid())); + entry->Append(new StringValue((*i)->Label())); + addresses.Append(entry); + } + + web_ui_->CallJavascriptFunction("AutofillOptions.setAddressList", addresses); + + ListValue credit_cards; + for (std::vector<CreditCard*>::const_iterator i = + personal_data_->credit_cards().begin(); + i != personal_data_->credit_cards().end(); ++i) { + ListValue* entry = new ListValue(); + entry->Append(new StringValue((*i)->guid())); + entry->Append(new StringValue((*i)->Label())); + int res = CreditCardTypeToResourceID((*i)->type()); + entry->Append( + new StringValue(web_ui_util::GetImageDataUrlFromResource(res))); + entry->Append(new StringValue(LocalizedCreditCardType((*i)->type()))); + credit_cards.Append(entry); + } + + web_ui_->CallJavascriptFunction("AutofillOptions.setCreditCardList", + credit_cards); +} + +void AutofillOptionsHandler::RemoveAddress(const ListValue* args) { + DCHECK(personal_data_->IsDataLoaded()); + + std::string guid; + if (!args->GetString(0, &guid)) { + NOTREACHED(); + return; + } + + personal_data_->RemoveProfile(guid); +} + +void AutofillOptionsHandler::RemoveCreditCard(const ListValue* args) { + DCHECK(personal_data_->IsDataLoaded()); + + std::string guid; + if (!args->GetString(0, &guid)) { + NOTREACHED(); + return; + } + + personal_data_->RemoveCreditCard(guid); +} + +void AutofillOptionsHandler::LoadAddressEditor(const ListValue* args) { + DCHECK(personal_data_->IsDataLoaded()); + + std::string guid; + if (!args->GetString(0, &guid)) { + NOTREACHED(); + return; + } + + AutofillProfile* profile = personal_data_->GetProfileByGUID(guid); + if (!profile) { + // There is a race where a user can click once on the close button and + // quickly click again on the list item before the item is removed (since + // the list is not updated until the model tells the list an item has been + // removed). This will activate the editor for a profile that has been + // removed. Do nothing in that case. + return; + } + + DictionaryValue address; + address.SetString("guid", profile->guid()); + scoped_ptr<ListValue> list; + GetNameList(*profile, &list); + address.Set("fullName", list.release()); + address.SetString("companyName", profile->GetInfo(COMPANY_NAME)); + address.SetString("addrLine1", profile->GetInfo(ADDRESS_HOME_LINE1)); + address.SetString("addrLine2", profile->GetInfo(ADDRESS_HOME_LINE2)); + address.SetString("city", profile->GetInfo(ADDRESS_HOME_CITY)); + address.SetString("state", profile->GetInfo(ADDRESS_HOME_STATE)); + address.SetString("postalCode", profile->GetInfo(ADDRESS_HOME_ZIP)); + address.SetString("country", profile->CountryCode()); + GetValueList(*profile, PHONE_HOME_WHOLE_NUMBER, &list); + address.Set("phone", list.release()); + GetValueList(*profile, EMAIL_ADDRESS, &list); + address.Set("email", list.release()); + + web_ui_->CallJavascriptFunction("AutofillOptions.editAddress", address); +} + +void AutofillOptionsHandler::LoadCreditCardEditor(const ListValue* args) { + DCHECK(personal_data_->IsDataLoaded()); + + std::string guid; + if (!args->GetString(0, &guid)) { + NOTREACHED(); + return; + } + + CreditCard* credit_card = personal_data_->GetCreditCardByGUID(guid); + if (!credit_card) { + // There is a race where a user can click once on the close button and + // quickly click again on the list item before the item is removed (since + // the list is not updated until the model tells the list an item has been + // removed). This will activate the editor for a profile that has been + // removed. Do nothing in that case. + return; + } + + DictionaryValue credit_card_data; + credit_card_data.SetString("guid", credit_card->guid()); + credit_card_data.SetString("nameOnCard", + credit_card->GetInfo(CREDIT_CARD_NAME)); + credit_card_data.SetString("creditCardNumber", + credit_card->GetInfo(CREDIT_CARD_NUMBER)); + credit_card_data.SetString("expirationMonth", + credit_card->GetInfo(CREDIT_CARD_EXP_MONTH)); + credit_card_data.SetString( + "expirationYear", + credit_card->GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); + + web_ui_->CallJavascriptFunction("AutofillOptions.editCreditCard", + credit_card_data); +} + +void AutofillOptionsHandler::SetAddress(const ListValue* args) { + if (!personal_data_->IsDataLoaded()) + return; + + std::string guid; + if (!args->GetString(0, &guid)) { + NOTREACHED(); + return; + } + + AutofillProfile profile(guid); + + std::string country_code; + string16 value; + ListValue* list_value; + if (args->GetList(1, &list_value)) + SetNameList(list_value, &profile); + if (args->GetString(2, &value)) + profile.SetInfo(COMPANY_NAME, value); + if (args->GetString(3, &value)) + profile.SetInfo(ADDRESS_HOME_LINE1, value); + if (args->GetString(4, &value)) + profile.SetInfo(ADDRESS_HOME_LINE2, value); + if (args->GetString(5, &value)) + profile.SetInfo(ADDRESS_HOME_CITY, value); + if (args->GetString(6, &value)) + profile.SetInfo(ADDRESS_HOME_STATE, value); + if (args->GetString(7, &value)) + profile.SetInfo(ADDRESS_HOME_ZIP, value); + if (args->GetString(8, &country_code)) + profile.SetCountryCode(country_code); + if (args->GetList(9, &list_value)) + SetValueList(list_value, PHONE_HOME_WHOLE_NUMBER, &profile); + if (args->GetList(10, &list_value)) + SetValueList(list_value, EMAIL_ADDRESS, &profile); + + if (!guid::IsValidGUID(profile.guid())) { + profile.set_guid(guid::GenerateGUID()); + personal_data_->AddProfile(profile); + } else { + personal_data_->UpdateProfile(profile); + } +} + +void AutofillOptionsHandler::SetCreditCard(const ListValue* args) { + if (!personal_data_->IsDataLoaded()) + return; + + std::string guid; + if (!args->GetString(0, &guid)) { + NOTREACHED(); + return; + } + + CreditCard credit_card(guid); + + string16 value; + if (args->GetString(1, &value)) + credit_card.SetInfo(CREDIT_CARD_NAME, value); + if (args->GetString(2, &value)) + credit_card.SetInfo(CREDIT_CARD_NUMBER, value); + if (args->GetString(3, &value)) + credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, value); + if (args->GetString(4, &value)) + credit_card.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, value); + + if (!guid::IsValidGUID(credit_card.guid())) { + credit_card.set_guid(guid::GenerateGUID()); + personal_data_->AddCreditCard(credit_card); + } else { + personal_data_->UpdateCreditCard(credit_card); + } +} + +void AutofillOptionsHandler::ValidatePhoneNumbers(const ListValue* args) { + if (!personal_data_->IsDataLoaded()) + return; + + ListValue* list_value = NULL; + ValidatePhoneArguments(args, &list_value); + + web_ui_->CallJavascriptFunction( + "AutofillEditAddressOverlay.setValidatedPhoneNumbers", *list_value); +} diff --git a/chrome/browser/ui/webui/options2/autofill_options_handler.h b/chrome/browser/ui/webui/options2/autofill_options_handler.h new file mode 100644 index 0000000..9c25074 --- /dev/null +++ b/chrome/browser/ui/webui/options2/autofill_options_handler.h @@ -0,0 +1,89 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_AUTOFILL_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_AUTOFILL_OPTIONS_HANDLER_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "chrome/browser/autofill/personal_data_manager_observer.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +class PersonalDataManager; + +namespace base { +class DictionaryValue; +class ListValue; +} + +class AutofillOptionsHandler : public OptionsPage2UIHandler, + public PersonalDataManagerObserver { + public: + AutofillOptionsHandler(); + virtual ~AutofillOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // PersonalDataManagerObserver implementation. + virtual void OnPersonalDataChanged() OVERRIDE; + + private: + // Loads the strings for the address and credit card overlays. + void SetAddressOverlayStrings(base::DictionaryValue* localized_strings); + void SetCreditCardOverlayStrings(base::DictionaryValue* localized_strings); + + // Loads Autofill addresses and credit cards using the PersonalDataManager. + void LoadAutofillData(); + + // Removes an address from the PersonalDataManager. + // |args| - A string, the GUID of the address to remove. + void RemoveAddress(const base::ListValue* args); + + // Removes a credit card from the PersonalDataManager. + // |args| - A string, the GUID of the credit card to remove. + void RemoveCreditCard(const base::ListValue* args); + + // Requests profile data for a specific address. Calls into WebUI with the + // loaded profile data to open the address editor. + // |args| - A string, the GUID of the address to load. + void LoadAddressEditor(const base::ListValue* args); + + // Requests profile data for a specific credit card. Calls into WebUI with the + // loaded profile data to open the credit card editor. + // |args| - A string, the GUID of the credit card to load. + void LoadCreditCardEditor(const base::ListValue* args); + + // Adds or updates an address, depending on the GUID of the profile. If the + // GUID is empty, a new address is added to the WebDatabase; otherwise, the + // address with the matching GUID is updated. Called from WebUI. + // |args| - an array containing the GUID of the address followed by the + // address data. + void SetAddress(const base::ListValue* args); + + // Adds or updates a credit card, depending on the GUID of the profile. If the + // GUID is empty, a new credit card is added to the WebDatabase; otherwise, + // the credit card with the matching GUID is updated. Called from WebUI. + // |args| - an array containing the GUID of the credit card followed by the + // credit card data. + void SetCreditCard(const base::ListValue* args); + + // Validates a list of phone numbers. The resulting validated list of + // numbers is then sent back to the WebUI. + // |args| - an array containing the index of the modified or added number, the + // array of numbers, and the country code string set on the profile. + void ValidatePhoneNumbers(const base::ListValue* args); + + // The personal data manager, used to load Autofill profiles and credit cards. + // Unowned pointer, may not be NULL. + PersonalDataManager* personal_data_; + + DISALLOW_COPY_AND_ASSIGN(AutofillOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_AUTOFILL_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/browser_options_browsertest.js b/chrome/browser/ui/webui/options2/browser_options_browsertest.js new file mode 100644 index 0000000..e983b27 --- /dev/null +++ b/chrome/browser/ui/webui/options2/browser_options_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for browser options WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function BrowserOptionsWebUITest() {} + +BrowserOptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to browser options. + **/ + browsePreload: 'chrome://settings/browser', +}; + +// Test opening the browser options has correct location. +TEST_F('BrowserOptionsWebUITest', 'testOpenBrowserOptions', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/browser_options_handler.cc b/chrome/browser/ui/webui/options2/browser_options_handler.cc new file mode 100644 index 0000000..23b1d46 --- /dev/null +++ b/chrome/browser/ui/webui/options2/browser_options_handler.cc @@ -0,0 +1,494 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/browser_options_handler.h" + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/singleton.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/autocomplete/autocomplete.h" +#include "chrome/browser/autocomplete/autocomplete_match.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/custom_home_pages_table_model.h" +#include "chrome/browser/instant/instant_confirm_dialog.h" +#include "chrome/browser/instant/instant_controller.h" +#include "chrome/browser/instant/instant_field_trial.h" +#include "chrome/browser/net/url_fixer_upper.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/session_startup_pref.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_service.h" +#include "chrome/browser/search_engines/template_url_service_factory.h" +#include "chrome/browser/ui/webui/favicon_source.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +BrowserOptionsHandler::BrowserOptionsHandler() + : template_url_service_(NULL), startup_custom_pages_table_model_(NULL) { +#if !defined(OS_MACOSX) + default_browser_worker_ = new ShellIntegration::DefaultBrowserWorker(this); +#endif +} + +BrowserOptionsHandler::~BrowserOptionsHandler() { + if (default_browser_worker_.get()) + default_browser_worker_->ObserverDestroyed(); + if (template_url_service_) + template_url_service_->RemoveObserver(this); +} + +void BrowserOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "startupGroupName", IDS_OPTIONS_STARTUP_GROUP_NAME }, + { "startupShowDefaultAndNewTab", + IDS_OPTIONS_STARTUP_SHOW_DEFAULT_AND_NEWTAB}, + { "startupShowLastSession", IDS_OPTIONS_STARTUP_SHOW_LAST_SESSION }, + { "startupShowPages", IDS_OPTIONS_STARTUP_SHOW_PAGES }, + { "startupAddLabel", IDS_OPTIONS_STARTUP_ADD_LABEL }, + { "startupUseCurrent", IDS_OPTIONS_STARTUP_USE_CURRENT }, + { "homepageGroupName", IDS_OPTIONS_HOMEPAGE_GROUP_NAME }, + { "homepageUseNewTab", IDS_OPTIONS_HOMEPAGE_USE_NEWTAB }, + { "homepageUseURL", IDS_OPTIONS_HOMEPAGE_USE_URL }, + { "toolbarGroupName", IDS_OPTIONS_TOOLBAR_GROUP_NAME }, + { "toolbarShowHomeButton", IDS_OPTIONS_TOOLBAR_SHOW_HOME_BUTTON }, + { "toolbarShowBookmarksBar", IDS_OPTIONS_TOOLBAR_SHOW_BOOKMARKS_BAR }, + { "defaultSearchGroupName", IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME }, + { "defaultSearchManageEngines", IDS_OPTIONS_DEFAULTSEARCH_MANAGE_ENGINES }, + { "instantName", IDS_INSTANT_PREF }, + { "instantWarningText", IDS_INSTANT_PREF_WARNING }, + { "instantConfirmTitle", IDS_INSTANT_OPT_IN_TITLE }, + { "instantConfirmMessage", IDS_INSTANT_OPT_IN_MESSAGE }, + { "defaultBrowserGroupName", IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "browserPage", + IDS_OPTIONS_GENERAL_TAB_LABEL); + + localized_strings->SetString("instantLearnMoreLink", + ASCIIToUTF16(browser::InstantLearnMoreURL().spec())); + localized_strings->SetString("defaultBrowserUnknown", + l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + localized_strings->SetString("defaultBrowserUseAsDefault", + l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); +} + +void BrowserOptionsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("becomeDefaultBrowser", + base::Bind(&BrowserOptionsHandler::BecomeDefaultBrowser, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setDefaultSearchEngine", + base::Bind(&BrowserOptionsHandler::SetDefaultSearchEngine, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeStartupPages", + base::Bind(&BrowserOptionsHandler::RemoveStartupPages, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("addStartupPage", + base::Bind(&BrowserOptionsHandler::AddStartupPage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("editStartupPage", + base::Bind(&BrowserOptionsHandler::EditStartupPage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setStartupPagesToCurrentPages", + base::Bind(&BrowserOptionsHandler::SetStartupPagesToCurrentPages, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("dragDropStartupPage", + base::Bind(&BrowserOptionsHandler::DragDropStartupPage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("requestAutocompleteSuggestions", + base::Bind(&BrowserOptionsHandler::RequestAutocompleteSuggestions, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("enableInstant", + base::Bind(&BrowserOptionsHandler::EnableInstant, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("disableInstant", + base::Bind(&BrowserOptionsHandler::DisableInstant, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("getInstantFieldTrialStatus", + base::Bind(&BrowserOptionsHandler::GetInstantFieldTrialStatus, + base::Unretained(this))); +} + +void BrowserOptionsHandler::Initialize() { + Profile* profile = Profile::FromWebUI(web_ui_); + + // Create our favicon data source. + profile->GetChromeURLDataManager()->AddDataSource( + new FaviconSource(profile, FaviconSource::FAVICON)); + + homepage_.Init(prefs::kHomePage, profile->GetPrefs(), NULL); + default_browser_policy_.Init(prefs::kDefaultBrowserSettingEnabled, + g_browser_process->local_state(), + this); + UpdateDefaultBrowserState(); + + startup_custom_pages_table_model_.reset( + new CustomHomePagesTableModel(profile)); + startup_custom_pages_table_model_->SetObserver(this); + UpdateStartupPages(); + + pref_change_registrar_.Init(profile->GetPrefs()); + pref_change_registrar_.Add(prefs::kURLsToRestoreOnStartup, this); + + UpdateSearchEngines(); + + autocomplete_controller_.reset(new AutocompleteController(profile, this)); +} + +void BrowserOptionsHandler::UpdateDefaultBrowserState() { + // Check for side-by-side first. + if (!ShellIntegration::CanSetAsDefaultBrowser()) { + SetDefaultBrowserUIString(IDS_OPTIONS_DEFAULTBROWSER_SXS); + return; + } + +#if defined(OS_MACOSX) + ShellIntegration::DefaultWebClientState state = + ShellIntegration::IsDefaultBrowser(); + int status_string_id; + if (state == ShellIntegration::IS_DEFAULT_WEB_CLIENT) + status_string_id = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT; + else if (state == ShellIntegration::NOT_DEFAULT_WEB_CLIENT) + status_string_id = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT; + else + status_string_id = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN; + + SetDefaultBrowserUIString(status_string_id); +#else + default_browser_worker_->StartCheckIsDefault(); +#endif +} + +void BrowserOptionsHandler::BecomeDefaultBrowser(const ListValue* args) { + // If the default browser setting is managed then we should not be able to + // call this function. + if (default_browser_policy_.IsManaged()) + return; + + UserMetrics::RecordAction(UserMetricsAction("Options_SetAsDefaultBrowser")); +#if defined(OS_MACOSX) + if (ShellIntegration::SetAsDefaultBrowser()) + UpdateDefaultBrowserState(); +#else + default_browser_worker_->StartSetAsDefault(); + // Callback takes care of updating UI. +#endif + + // If the user attempted to make Chrome the default browser, then he/she + // arguably wants to be notified when that changes. + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); + prefs->SetBoolean(prefs::kCheckDefaultBrowser, true); +} + +int BrowserOptionsHandler::StatusStringIdForState( + ShellIntegration::DefaultWebClientState state) { + if (state == ShellIntegration::IS_DEFAULT_WEB_CLIENT) + return IDS_OPTIONS_DEFAULTBROWSER_DEFAULT; + if (state == ShellIntegration::NOT_DEFAULT_WEB_CLIENT) + return IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT; + return IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN; +} + +void BrowserOptionsHandler::SetDefaultWebClientUIState( + ShellIntegration::DefaultWebClientUIState state) { + int status_string_id; + if (state == ShellIntegration::STATE_IS_DEFAULT) + status_string_id = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT; + else if (state == ShellIntegration::STATE_NOT_DEFAULT) + status_string_id = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT; + else if (state == ShellIntegration::STATE_UNKNOWN) + status_string_id = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN; + else + return; // Still processing. + + SetDefaultBrowserUIString(status_string_id); +} + +void BrowserOptionsHandler::SetDefaultBrowserUIString(int status_string_id) { + scoped_ptr<Value> status_string(Value::CreateStringValue( + l10n_util::GetStringFUTF16(status_string_id, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)))); + + scoped_ptr<Value> is_default(Value::CreateBooleanValue( + status_string_id == IDS_OPTIONS_DEFAULTBROWSER_DEFAULT)); + + scoped_ptr<Value> can_be_default(Value::CreateBooleanValue( + !default_browser_policy_.IsManaged() && + (status_string_id == IDS_OPTIONS_DEFAULTBROWSER_DEFAULT || + status_string_id == IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT))); + + web_ui_->CallJavascriptFunction("BrowserOptions.updateDefaultBrowserState", + *status_string, *is_default, *can_be_default); +} + +void BrowserOptionsHandler::OnTemplateURLServiceChanged() { + if (!template_url_service_ || !template_url_service_->loaded()) + return; + + const TemplateURL* default_url = + template_url_service_->GetDefaultSearchProvider(); + + int default_index = 0; + ListValue search_engines; + std::vector<const TemplateURL*> model_urls = + template_url_service_->GetTemplateURLs(); + for (size_t i = 0; i < model_urls.size(); ++i) { + if (!model_urls[i]->ShowInDefaultList()) + continue; + + DictionaryValue* entry = new DictionaryValue(); + entry->SetString("name", model_urls[i]->short_name()); + entry->SetInteger("index", i); + search_engines.Append(entry); + if (model_urls[i] == default_url) + default_index = i; + } + + scoped_ptr<Value> default_value(Value::CreateIntegerValue(default_index)); + scoped_ptr<Value> default_managed(Value::CreateBooleanValue( + template_url_service_->is_default_search_managed())); + + web_ui_->CallJavascriptFunction("BrowserOptions.updateSearchEngines", + search_engines, *default_value, + *default_managed); +} + +void BrowserOptionsHandler::SetDefaultSearchEngine(const ListValue* args) { + int selected_index = -1; + if (!ExtractIntegerValue(args, &selected_index)) { + NOTREACHED(); + return; + } + + std::vector<const TemplateURL*> model_urls = + template_url_service_->GetTemplateURLs(); + if (selected_index >= 0 && + selected_index < static_cast<int>(model_urls.size())) + template_url_service_->SetDefaultSearchProvider(model_urls[selected_index]); + + UserMetrics::RecordAction(UserMetricsAction("Options_SearchEngineChanged")); +} + +void BrowserOptionsHandler::UpdateSearchEngines() { + template_url_service_ = + TemplateURLServiceFactory::GetForProfile(Profile::FromWebUI(web_ui_)); + if (template_url_service_) { + template_url_service_->Load(); + template_url_service_->AddObserver(this); + OnTemplateURLServiceChanged(); + } +} + +void BrowserOptionsHandler::UpdateStartupPages() { + Profile* profile = Profile::FromWebUI(web_ui_); + const SessionStartupPref startup_pref = + SessionStartupPref::GetStartupPref(profile->GetPrefs()); + startup_custom_pages_table_model_->SetURLs(startup_pref.urls); +} + +void BrowserOptionsHandler::OnModelChanged() { + ListValue startup_pages; + int page_count = startup_custom_pages_table_model_->RowCount(); + std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs(); + for (int i = 0; i < page_count; ++i) { + DictionaryValue* entry = new DictionaryValue(); + entry->SetString("title", startup_custom_pages_table_model_->GetText(i, 0)); + entry->SetString("url", urls[i].spec()); + entry->SetString("tooltip", + startup_custom_pages_table_model_->GetTooltip(i)); + entry->SetString("modelIndex", base::IntToString(i)); + startup_pages.Append(entry); + } + + web_ui_->CallJavascriptFunction("BrowserOptions.updateStartupPages", + startup_pages); +} + +void BrowserOptionsHandler::OnItemsChanged(int start, int length) { + OnModelChanged(); +} + +void BrowserOptionsHandler::OnItemsAdded(int start, int length) { + OnModelChanged(); +} + +void BrowserOptionsHandler::OnItemsRemoved(int start, int length) { + OnModelChanged(); +} + +void BrowserOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PREF_CHANGED) { + std::string* pref = content::Details<std::string>(details).ptr(); + if (*pref == prefs::kDefaultBrowserSettingEnabled) { + UpdateDefaultBrowserState(); + } else if (*pref == prefs::kURLsToRestoreOnStartup) { + UpdateStartupPages(); + } else { + NOTREACHED(); + } + } else { + NOTREACHED(); + } +} + +void BrowserOptionsHandler::SetStartupPagesToCurrentPages( + const ListValue* args) { + startup_custom_pages_table_model_->SetToCurrentlyOpenPages(); + SaveStartupPagesPref(); +} + +void BrowserOptionsHandler::RemoveStartupPages(const ListValue* args) { + for (int i = args->GetSize() - 1; i >= 0; --i) { + std::string string_value; + CHECK(args->GetString(i, &string_value)); + + int selected_index; + base::StringToInt(string_value, &selected_index); + if (selected_index < 0 || + selected_index >= startup_custom_pages_table_model_->RowCount()) { + NOTREACHED(); + return; + } + startup_custom_pages_table_model_->Remove(selected_index); + } + + SaveStartupPagesPref(); +} + +void BrowserOptionsHandler::AddStartupPage(const ListValue* args) { + std::string url_string; + CHECK_EQ(args->GetSize(), 1U); + CHECK(args->GetString(0, &url_string)); + + GURL url = URLFixerUpper::FixupURL(url_string, std::string()); + if (!url.is_valid()) + return; + int index = startup_custom_pages_table_model_->RowCount(); + startup_custom_pages_table_model_->Add(index, url); + SaveStartupPagesPref(); +} + +void BrowserOptionsHandler::EditStartupPage(const ListValue* args) { + std::string url_string; + std::string index_string; + int index; + CHECK_EQ(args->GetSize(), 2U); + CHECK(args->GetString(0, &index_string)); + CHECK(base::StringToInt(index_string, &index)); + CHECK(args->GetString(1, &url_string)); + + if (index < 0 || index > startup_custom_pages_table_model_->RowCount()) { + NOTREACHED(); + return; + } + + std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs(); + urls[index] = URLFixerUpper::FixupURL(url_string, std::string()); + startup_custom_pages_table_model_->SetURLs(urls); + SaveStartupPagesPref(); +} + +void BrowserOptionsHandler::DragDropStartupPage(const ListValue* args) { + CHECK_EQ(args->GetSize(), 2U); + + std::string value; + int to_index; + + CHECK(args->GetString(0, &value)); + base::StringToInt(value, &to_index); + + ListValue* selected; + CHECK(args->GetList(1, &selected)); + + std::vector<int> index_list; + for (size_t i = 0; i < selected->GetSize(); ++i) { + int index; + CHECK(selected->GetString(i, &value)); + base::StringToInt(value, &index); + index_list.push_back(index); + } + + startup_custom_pages_table_model_->MoveURLs(to_index, index_list); + SaveStartupPagesPref(); +} + +void BrowserOptionsHandler::SaveStartupPagesPref() { + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); + + SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs); + pref.urls = startup_custom_pages_table_model_->GetURLs(); + + SessionStartupPref::SetStartupPref(prefs, pref); +} + +void BrowserOptionsHandler::RequestAutocompleteSuggestions( + const ListValue* args) { + string16 input; + CHECK_EQ(args->GetSize(), 1U); + CHECK(args->GetString(0, &input)); + + autocomplete_controller_->Start(input, string16(), true, false, false, + AutocompleteInput::ALL_MATCHES); +} + +void BrowserOptionsHandler::EnableInstant(const ListValue* args) { + InstantController::Enable(Profile::FromWebUI(web_ui_)); +} + +void BrowserOptionsHandler::DisableInstant(const ListValue* args) { + InstantController::Disable(Profile::FromWebUI(web_ui_)); +} + +void BrowserOptionsHandler::GetInstantFieldTrialStatus(const ListValue* args) { + Profile* profile = Profile::FromWebUI(web_ui_); + base::FundamentalValue enabled( + InstantFieldTrial::IsInstantExperiment(profile) && + !InstantFieldTrial::IsHiddenExperiment(profile)); + web_ui_->CallJavascriptFunction("BrowserOptions.setInstantFieldTrialStatus", + enabled); +} + +void BrowserOptionsHandler::OnResultChanged(bool default_match_changed) { + const AutocompleteResult& result = autocomplete_controller_->result(); + ListValue suggestions; + for (size_t i = 0; i < result.size(); ++i) { + const AutocompleteMatch& match = result.match_at(i); + AutocompleteMatch::Type type = match.type; + if (type != AutocompleteMatch::HISTORY_URL && + type != AutocompleteMatch::HISTORY_TITLE && + type != AutocompleteMatch::HISTORY_BODY && + type != AutocompleteMatch::HISTORY_KEYWORD && + type != AutocompleteMatch::NAVSUGGEST) + continue; + DictionaryValue* entry = new DictionaryValue(); + entry->SetString("title", match.description); + entry->SetString("displayURL", match.contents); + entry->SetString("url", match.destination_url.spec()); + suggestions.Append(entry); + } + + web_ui_->CallJavascriptFunction( + "BrowserOptions.updateAutocompleteSuggestions", suggestions); +} diff --git a/chrome/browser/ui/webui/options2/browser_options_handler.h b/chrome/browser/ui/webui/options2/browser_options_handler.h new file mode 100644 index 0000000..dcd8a86 --- /dev/null +++ b/chrome/browser/ui/webui/options2/browser_options_handler.h @@ -0,0 +1,136 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_BROWSER_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_BROWSER_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/autocomplete/autocomplete_controller_delegate.h" +#include "chrome/browser/prefs/pref_change_registrar.h" +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/search_engines/template_url_service_observer.h" +#include "chrome/browser/shell_integration.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "ui/base/models/table_model_observer.h" + +class AutocompleteController; +class CustomHomePagesTableModel; +class TemplateURLService; + +// Chrome browser options page UI handler. +class BrowserOptionsHandler : public OptionsPage2UIHandler, + public AutocompleteControllerDelegate, + public ShellIntegration::DefaultWebClientObserver, + public TemplateURLServiceObserver, + public ui::TableModelObserver { + public: + BrowserOptionsHandler(); + virtual ~BrowserOptionsHandler(); + + virtual void Initialize() OVERRIDE; + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // AutocompleteControllerDelegate implementation. + virtual void OnResultChanged(bool default_match_changed) OVERRIDE; + + // ShellIntegration::DefaultWebClientObserver implementation. + virtual void SetDefaultWebClientUIState( + ShellIntegration::DefaultWebClientUIState state) OVERRIDE; + + // TemplateURLServiceObserver implementation. + virtual void OnTemplateURLServiceChanged() OVERRIDE; + + // ui::TableModelObserver implementation. + virtual void OnModelChanged() OVERRIDE; + virtual void OnItemsChanged(int start, int length) OVERRIDE; + virtual void OnItemsAdded(int start, int length) OVERRIDE; + virtual void OnItemsRemoved(int start, int length) OVERRIDE; + + private: + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Makes this the default browser. Called from WebUI. + void BecomeDefaultBrowser(const ListValue* args); + + // Sets the search engine at the given index to be default. Called from WebUI. + void SetDefaultSearchEngine(const ListValue* args); + + // Removes the startup page at the given indexes. Called from WebUI. + void RemoveStartupPages(const ListValue* args); + + // Adds a startup page with the given URL after the given index. + // Called from WebUI. + void AddStartupPage(const ListValue* args); + + // Changes the startup page at the given index to the given URL. + // Called from WebUI. + void EditStartupPage(const ListValue* args); + + // Sets the startup page set to the current pages. Called from WebUI. + void SetStartupPagesToCurrentPages(const ListValue* args); + + // Writes the current set of startup pages to prefs. Called from WebUI. + void DragDropStartupPage(const ListValue* args); + + // Gets autocomplete suggestions asychronously for the given string. + // Called from WebUI. + void RequestAutocompleteSuggestions(const ListValue* args); + + // Enables/disables Instant. + void EnableInstant(const ListValue* args); + void DisableInstant(const ListValue* args); + + // Called to request information about the Instant field trial. + void GetInstantFieldTrialStatus(const ListValue* args); + + // Returns the string ID for the given default browser state. + int StatusStringIdForState(ShellIntegration::DefaultWebClientState state); + + // Gets the current default browser state, and asynchronously reports it to + // the WebUI page. + void UpdateDefaultBrowserState(); + + // Updates the UI with the given state for the default browser. + void SetDefaultBrowserUIString(int status_string_id); + + // Loads the current set of custom startup pages and reports it to the WebUI. + void UpdateStartupPages(); + + // Loads the possible default search engine list and reports it to the WebUI. + void UpdateSearchEngines(); + + // Writes the current set of startup pages to prefs. + void SaveStartupPagesPref(); + + scoped_refptr<ShellIntegration::DefaultBrowserWorker> + default_browser_worker_; + + StringPrefMember homepage_; + BooleanPrefMember default_browser_policy_; + + // Used to observe updates to the preference of the list of URLs to load + // on startup, which can be updated via sync. + PrefChangeRegistrar pref_change_registrar_; + + TemplateURLService* template_url_service_; // Weak. + + // TODO(stuartmorgan): Once there are no other clients of + // CustomHomePagesTableModel, consider changing it to something more like + // TemplateURLService. + scoped_ptr<CustomHomePagesTableModel> startup_custom_pages_table_model_; + + scoped_ptr<AutocompleteController> autocomplete_controller_; + + DISALLOW_COPY_AND_ASSIGN(BrowserOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_BROWSER_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/certificate_manager_browsertest.js b/chrome/browser/ui/webui/options2/certificate_manager_browsertest.js new file mode 100644 index 0000000..fdd2373 --- /dev/null +++ b/chrome/browser/ui/webui/options2/certificate_manager_browsertest.js @@ -0,0 +1,33 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for certificate manager WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function CertificateManagerWebUITest() {} + +CertificateManagerWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the certificate manager. + **/ + browsePreload: 'chrome://settings/certificates', +}; + +// Mac and Windows go to native certificate manager. +GEN('#if defined(OS_MACOSX) || defined(OS_WIN)'); +GEN('#define MAYBE_testOpenCertificateManager ' + + 'DISABLED_testOpenCertificateManager'); +GEN('#else'); +GEN('#define MAYBE_testOpenCertificateManager ' + + 'testOpenCertificateManager'); +GEN('#endif // defined(OS_MACOSX) || defined(OS_WIN)'); +// Test opening the certificate manager has correct location. +TEST_F('CertificateManagerWebUITest', + 'MAYBE_testOpenCertificateManager', function() { + assertEquals(this.browsePreload, document.location.href); + }); diff --git a/chrome/browser/ui/webui/options2/certificate_manager_handler.cc b/chrome/browser/ui/webui/options2/certificate_manager_handler.cc new file mode 100644 index 0000000..00d52f6 --- /dev/null +++ b/chrome/browser/ui/webui/options2/certificate_manager_handler.cc @@ -0,0 +1,1046 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/certificate_manager_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/file_util.h" // for FileAccessProvider +#include "base/memory/scoped_vector.h" +#include "base/safe_strerror_posix.h" +#include "base/string_number_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/certificate_viewer.h" +#include "chrome/browser/ui/certificate_dialogs.h" +#include "chrome/browser/ui/crypto_module_password_dialog.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_view.h" +#include "content/public/browser/browser_thread.h" // for FileAccessProvider +#include "grit/generated_resources.h" +#include "net/base/crypto_module.h" +#include "net/base/x509_certificate.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/l10n_util_collator.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/cryptohome_library.h" +#endif + +using content::BrowserThread; + +namespace { + +static const char kKeyId[] = "id"; +static const char kSubNodesId[] = "subnodes"; +static const char kNameId[] = "name"; +static const char kReadOnlyId[] = "readonly"; +static const char kUntrustedId[] = "untrusted"; +static const char kSecurityDeviceId[] = "device"; +static const char kErrorId[] = "error"; + +// Enumeration of different callers of SelectFile. (Start counting at 1 so +// if SelectFile is accidentally called with params=NULL it won't match any.) +enum { + EXPORT_PERSONAL_FILE_SELECTED = 1, + IMPORT_PERSONAL_FILE_SELECTED, + IMPORT_SERVER_FILE_SELECTED, + IMPORT_CA_FILE_SELECTED, +}; + +// TODO(mattm): These are duplicated from cookies_view_handler.cc +// Encodes a pointer value into a hex string. +std::string PointerToHexString(const void* pointer) { + return base::HexEncode(&pointer, sizeof(pointer)); +} + +// Decodes a pointer from a hex string. +void* HexStringToPointer(const std::string& str) { + std::vector<uint8> buffer; + if (!base::HexStringToBytes(str, &buffer) || + buffer.size() != sizeof(void*)) { + return NULL; + } + + return *reinterpret_cast<void**>(&buffer[0]); +} + +std::string OrgNameToId(const std::string& org) { + return "org-" + org; +} + +std::string CertToId(const net::X509Certificate& cert) { + return "cert-" + PointerToHexString(&cert); +} + +net::X509Certificate* IdToCert(const std::string& id) { + if (!StartsWithASCII(id, "cert-", true)) + return NULL; + return reinterpret_cast<net::X509Certificate*>( + HexStringToPointer(id.substr(5))); +} + +net::X509Certificate* CallbackArgsToCert(const ListValue* args) { + std::string node_id; + if (!args->GetString(0, &node_id)){ + return NULL; + } + net::X509Certificate* cert = IdToCert(node_id); + if (!cert) { + NOTREACHED(); + return NULL; + } + return cert; +} + +bool CallbackArgsToBool(const ListValue* args, int index, bool* result) { + std::string string_value; + if (!args->GetString(index, &string_value)) + return false; + + *result = string_value[0] == 't'; + return true; +} + +struct DictionaryIdComparator { + explicit DictionaryIdComparator(icu::Collator* collator) + : collator_(collator) { + } + + bool operator()(const Value* a, + const Value* b) const { + DCHECK(a->GetType() == Value::TYPE_DICTIONARY); + DCHECK(b->GetType() == Value::TYPE_DICTIONARY); + const DictionaryValue* a_dict = reinterpret_cast<const DictionaryValue*>(a); + const DictionaryValue* b_dict = reinterpret_cast<const DictionaryValue*>(b); + string16 a_str; + string16 b_str; + a_dict->GetString(kNameId, &a_str); + b_dict->GetString(kNameId, &b_str); + if (collator_ == NULL) + return a_str < b_str; + return l10n_util::CompareString16WithCollator( + collator_, a_str, b_str) == UCOL_LESS; + } + + icu::Collator* collator_; +}; + +std::string NetErrorToString(int net_error) { + switch (net_error) { + // TODO(mattm): handle more cases. + case net::ERR_IMPORT_CA_CERT_NOT_CA: + return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_ERROR_NOT_CA); + default: + return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR); + } +} + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// FileAccessProvider + +// TODO(mattm): Move to some shared location? +class FileAccessProvider + : public base::RefCountedThreadSafe<FileAccessProvider>, + public CancelableRequestProvider { + public: + // Reports 0 on success or errno on failure, and the data of the file upon + // success. + // TODO(mattm): don't pass std::string by value.. could use RefCountedBytes + // but it's a vector. Maybe do the derive from CancelableRequest thing + // described in cancelable_request.h? + typedef Callback2<int, std::string>::Type ReadCallback; + + // Reports 0 on success or errno on failure, and the number of bytes written, + // on success. + typedef Callback2<int, int>::Type WriteCallback; + + Handle StartRead(const FilePath& path, + CancelableRequestConsumerBase* consumer, + ReadCallback* callback); + Handle StartWrite(const FilePath& path, + const std::string& data, + CancelableRequestConsumerBase* consumer, + WriteCallback* callback); + + private: + void DoRead(scoped_refptr<CancelableRequest<ReadCallback> > request, + FilePath path); + void DoWrite(scoped_refptr<CancelableRequest<WriteCallback> > request, + FilePath path, + std::string data); +}; + +CancelableRequestProvider::Handle FileAccessProvider::StartRead( + const FilePath& path, + CancelableRequestConsumerBase* consumer, + FileAccessProvider::ReadCallback* callback) { + scoped_refptr<CancelableRequest<ReadCallback> > request( + new CancelableRequest<ReadCallback>(callback)); + AddRequest(request, consumer); + + // Send the parameters and the request to the file thread. + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&FileAccessProvider::DoRead, this, request, path)); + + // The handle will have been set by AddRequest. + return request->handle(); +} + +CancelableRequestProvider::Handle FileAccessProvider::StartWrite( + const FilePath& path, + const std::string& data, + CancelableRequestConsumerBase* consumer, + WriteCallback* callback) { + scoped_refptr<CancelableRequest<WriteCallback> > request( + new CancelableRequest<WriteCallback>(callback)); + AddRequest(request, consumer); + + // Send the parameters and the request to the file thWrite. + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&FileAccessProvider::DoWrite, this, request, path, data)); + + // The handle will have been set by AddRequest. + return request->handle(); +} + +void FileAccessProvider::DoRead( + scoped_refptr<CancelableRequest<ReadCallback> > request, + FilePath path) { + if (request->canceled()) + return; + + std::string data; + VLOG(1) << "DoRead starting read"; + bool success = file_util::ReadFileToString(path, &data); + int saved_errno = success ? 0 : errno; + VLOG(1) << "DoRead done read: " << success << " " << data.size(); + request->ForwardResult(ReadCallback::TupleType(saved_errno, data)); +} + +void FileAccessProvider::DoWrite( + scoped_refptr<CancelableRequest<WriteCallback> > request, + FilePath path, + std::string data) { + VLOG(1) << "DoWrite starting write"; + int bytes_written = file_util::WriteFile(path, data.data(), data.size()); + int saved_errno = bytes_written >= 0 ? 0 : errno; + VLOG(1) << "DoWrite done write " << bytes_written; + + if (request->canceled()) + return; + + request->ForwardResult(WriteCallback::TupleType(saved_errno, bytes_written)); +} + +/////////////////////////////////////////////////////////////////////////////// +// CertificateManagerHandler + +CertificateManagerHandler::CertificateManagerHandler() + : file_access_provider_(new FileAccessProvider) { + certificate_manager_model_.reset(new CertificateManagerModel(this)); +} + +CertificateManagerHandler::~CertificateManagerHandler() { +} + +void CertificateManagerHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "certificateManagerPage", + IDS_CERTIFICATE_MANAGER_TITLE); + + // Tabs. + localized_strings->SetString("personalCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL)); + localized_strings->SetString("serverCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL)); + localized_strings->SetString("caCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL)); + localized_strings->SetString("unknownCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TAB_LABEL)); + + // Tab descriptions. + localized_strings->SetString("personalCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION)); + localized_strings->SetString("serverCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION)); + localized_strings->SetString("caCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION)); + localized_strings->SetString("unknownCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION)); + + // Tree columns. + localized_strings->SetString("certNameColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_NAME_COLUMN_LABEL)); + localized_strings->SetString("certDeviceColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL)); + localized_strings->SetString("certSerialColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL)); + localized_strings->SetString("certExpiresColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL)); + + // Buttons. + localized_strings->SetString("view_certificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON)); + localized_strings->SetString("import_certificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON)); + localized_strings->SetString("export_certificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON)); + localized_strings->SetString("export_all_certificates", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_ALL_BUTTON)); + localized_strings->SetString("edit_certificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON)); + localized_strings->SetString("delete_certificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON)); + + // Certificate Delete overlay strings. + localized_strings->SetString("personalCertsTabDeleteConfirm", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT)); + localized_strings->SetString("personalCertsTabDeleteImpact", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION)); + localized_strings->SetString("serverCertsTabDeleteConfirm", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT)); + localized_strings->SetString("serverCertsTabDeleteImpact", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION)); + localized_strings->SetString("caCertsTabDeleteConfirm", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT)); + localized_strings->SetString("caCertsTabDeleteImpact", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION)); + localized_strings->SetString("unknownCertsTabDeleteConfirm", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_UNKNOWN_FORMAT)); + localized_strings->SetString("unknownCertsTabDeleteImpact", ""); + + // Certificate Restore overlay strings. + localized_strings->SetString("certificateRestorePasswordDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC)); + localized_strings->SetString("certificatePasswordLabel", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL)); + + // Personal Certificate Export overlay strings. + localized_strings->SetString("certificateExportPasswordDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC)); + localized_strings->SetString("certificateExportPasswordHelp", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP)); + localized_strings->SetString("certificateConfirmPasswordLabel", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL)); + + // Edit CA Trust & Import CA overlay strings. + localized_strings->SetString("certificateEditTrustLabel", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_TRUST_LABEL)); + localized_strings->SetString("certificateEditCaTrustDescriptionFormat", + l10n_util::GetStringUTF16( + IDS_CERT_MANAGER_EDIT_CA_TRUST_DESCRIPTION_FORMAT)); + localized_strings->SetString("certificateImportCaDescriptionFormat", + l10n_util::GetStringUTF16( + IDS_CERT_MANAGER_IMPORT_CA_DESCRIPTION_FORMAT)); + localized_strings->SetString("certificateCaTrustSSLLabel", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_SSL_LABEL)); + localized_strings->SetString("certificateCaTrustEmailLabel", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_EMAIL_LABEL)); + localized_strings->SetString("certificateCaTrustObjSignLabel", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_OBJSIGN_LABEL)); + localized_strings->SetString("certificateImportErrorFormat", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_ERROR_FORMAT)); + + // Badges next to certificates + localized_strings->SetString("badgeCertUntrusted", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNTRUSTED)); + +#if defined(OS_CHROMEOS) + localized_strings->SetString("importAndBindCertificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON)); + localized_strings->SetString("hardwareBackedKeyFormat", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT)); + localized_strings->SetString("chromeOSDeviceName", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); +#endif // defined(OS_CHROMEOS) +} + +void CertificateManagerHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback( + "viewCertificate", + base::Bind(&CertificateManagerHandler::View, base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "getCaCertificateTrust", + base::Bind(&CertificateManagerHandler::GetCATrust, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "editCaCertificateTrust", + base::Bind(&CertificateManagerHandler::EditCATrust, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "editServerCertificate", + base::Bind(&CertificateManagerHandler::EditServer, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "cancelImportExportCertificate", + base::Bind(&CertificateManagerHandler::CancelImportExportProcess, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "exportPersonalCertificate", + base::Bind(&CertificateManagerHandler::ExportPersonal, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "exportAllPersonalCertificates", + base::Bind(&CertificateManagerHandler::ExportAllPersonal, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "exportPersonalCertificatePasswordSelected", + base::Bind(&CertificateManagerHandler::ExportPersonalPasswordSelected, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "importPersonalCertificate", + base::Bind(&CertificateManagerHandler::StartImportPersonal, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "importPersonalCertificatePasswordSelected", + base::Bind(&CertificateManagerHandler::ImportPersonalPasswordSelected, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "importCaCertificate", + base::Bind(&CertificateManagerHandler::ImportCA, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "importCaCertificateTrustSelected", + base::Bind(&CertificateManagerHandler::ImportCATrustSelected, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "importServerCertificate", + base::Bind(&CertificateManagerHandler::ImportServer, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "exportCertificate", + base::Bind(&CertificateManagerHandler::Export, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "deleteCertificate", + base::Bind(&CertificateManagerHandler::Delete, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback( + "populateCertificateManager", + base::Bind(&CertificateManagerHandler::Populate, + base::Unretained(this))); + +#if defined(OS_CHROMEOS) + web_ui_->RegisterMessageCallback( + "checkTpmTokenReady", + base::Bind(&CertificateManagerHandler::CheckTpmTokenReady, + base::Unretained(this))); +#endif +} + +void CertificateManagerHandler::CertificatesRefreshed() { + PopulateTree("personalCertsTab", net::USER_CERT); + PopulateTree("serverCertsTab", net::SERVER_CERT); + PopulateTree("caCertsTab", net::CA_CERT); + PopulateTree("otherCertsTab", net::UNKNOWN_CERT); + VLOG(1) << "populating finished"; +} + +void CertificateManagerHandler::FileSelected(const FilePath& path, int index, + void* params) { + switch (reinterpret_cast<intptr_t>(params)) { + case EXPORT_PERSONAL_FILE_SELECTED: + ExportPersonalFileSelected(path); + break; + case IMPORT_PERSONAL_FILE_SELECTED: + ImportPersonalFileSelected(path); + break; + case IMPORT_SERVER_FILE_SELECTED: + ImportServerFileSelected(path); + break; + case IMPORT_CA_FILE_SELECTED: + ImportCAFileSelected(path); + break; + default: + NOTREACHED(); + } +} + +void CertificateManagerHandler::FileSelectionCanceled(void* params) { + switch (reinterpret_cast<intptr_t>(params)) { + case EXPORT_PERSONAL_FILE_SELECTED: + case IMPORT_PERSONAL_FILE_SELECTED: + case IMPORT_SERVER_FILE_SELECTED: + case IMPORT_CA_FILE_SELECTED: + ImportExportCleanup(); + break; + default: + NOTREACHED(); + } +} + +void CertificateManagerHandler::View(const ListValue* args) { + net::X509Certificate* cert = CallbackArgsToCert(args); + if (!cert) + return; + ShowCertificateViewer(GetParentWindow(), cert); +} + +void CertificateManagerHandler::GetCATrust(const ListValue* args) { + net::X509Certificate* cert = CallbackArgsToCert(args); + if (!cert) { + web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); + return; + } + + net::CertDatabase::TrustBits trust_bits = + certificate_manager_model_->cert_db().GetCertTrust(cert, net::CA_CERT); + base::FundamentalValue ssl_value( + static_cast<bool>(trust_bits & net::CertDatabase::TRUSTED_SSL)); + base::FundamentalValue email_value( + static_cast<bool>(trust_bits & net::CertDatabase::TRUSTED_EMAIL)); + base::FundamentalValue obj_sign_value( + static_cast<bool>(trust_bits & net::CertDatabase::TRUSTED_OBJ_SIGN)); + web_ui_->CallJavascriptFunction( + "CertificateEditCaTrustOverlay.populateTrust", + ssl_value, email_value, obj_sign_value); +} + +void CertificateManagerHandler::EditCATrust(const ListValue* args) { + net::X509Certificate* cert = CallbackArgsToCert(args); + bool fail = !cert; + bool trust_ssl = false; + bool trust_email = false; + bool trust_obj_sign = false; + fail |= !CallbackArgsToBool(args, 1, &trust_ssl); + fail |= !CallbackArgsToBool(args, 2, &trust_email); + fail |= !CallbackArgsToBool(args, 3, &trust_obj_sign); + if (fail) { + LOG(ERROR) << "EditCATrust args fail"; + web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); + return; + } + + bool result = certificate_manager_model_->SetCertTrust( + cert, + net::CA_CERT, + trust_ssl * net::CertDatabase::TRUSTED_SSL + + trust_email * net::CertDatabase::TRUSTED_EMAIL + + trust_obj_sign * net::CertDatabase::TRUSTED_OBJ_SIGN); + web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); + if (!result) { + // TODO(mattm): better error messages? + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); + } +} + +void CertificateManagerHandler::EditServer(const ListValue* args) { + NOTIMPLEMENTED(); +} + +void CertificateManagerHandler::ExportPersonal(const ListValue* args) { + net::X509Certificate* cert = CallbackArgsToCert(args); + if (!cert) + return; + + selected_cert_list_.push_back(cert); + + SelectFileDialog::FileTypeInfo file_type_info; + file_type_info.extensions.resize(1); + file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12")); + file_type_info.extension_description_overrides.push_back( + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES)); + file_type_info.include_all_files = true; + select_file_dialog_ = SelectFileDialog::Create(this); + select_file_dialog_->SelectFile( + SelectFileDialog::SELECT_SAVEAS_FILE, string16(), + FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"), + web_ui_->tab_contents(), GetParentWindow(), + reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED)); +} + +void CertificateManagerHandler::ExportAllPersonal(const ListValue* args) { + NOTIMPLEMENTED(); +} + +void CertificateManagerHandler::ExportPersonalFileSelected( + const FilePath& path) { + file_path_ = path; + web_ui_->CallJavascriptFunction( + "CertificateManager.exportPersonalAskPassword"); +} + +void CertificateManagerHandler::ExportPersonalPasswordSelected( + const ListValue* args) { + if (!args->GetString(0, &password_)){ + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + ImportExportCleanup(); + return; + } + + // Currently, we don't support exporting more than one at a time. If we do, + // this would need to either change this to use UnlockSlotsIfNecessary or + // change UnlockCertSlotIfNecessary to take a CertificateList. + DCHECK_EQ(selected_cert_list_.size(), 1U); + + // TODO(mattm): do something smarter about non-extractable keys + browser::UnlockCertSlotIfNecessary( + selected_cert_list_[0].get(), + browser::kCryptoModulePasswordCertExport, + "", // unused. + base::Bind(&CertificateManagerHandler::ExportPersonalSlotsUnlocked, + base::Unretained(this))); +} + +void CertificateManagerHandler::ExportPersonalSlotsUnlocked() { + std::string output; + int num_exported = certificate_manager_model_->cert_db().ExportToPKCS12( + selected_cert_list_, + password_, + &output); + if (!num_exported) { + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); + ImportExportCleanup(); + return; + } + file_access_provider_->StartWrite( + file_path_, + output, + &consumer_, + NewCallback(this, &CertificateManagerHandler::ExportPersonalFileWritten)); +} + +void CertificateManagerHandler::ExportPersonalFileWritten(int write_errno, + int bytes_written) { + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + ImportExportCleanup(); + if (write_errno) { + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE), + l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT, + UTF8ToUTF16(safe_strerror(write_errno)))); + } +} + +void CertificateManagerHandler::StartImportPersonal(const ListValue* args) { + SelectFileDialog::FileTypeInfo file_type_info; + if (!args->GetBoolean(0, &use_hardware_backed_)){ + // Unable to retrieve the hardware backed attribute from the args, + // so bail. + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + ImportExportCleanup(); + return; + } + file_type_info.extensions.resize(1); + file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12")); + file_type_info.extension_description_overrides.push_back( + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES)); + file_type_info.include_all_files = true; + select_file_dialog_ = SelectFileDialog::Create(this); + select_file_dialog_->SelectFile( + SelectFileDialog::SELECT_OPEN_FILE, string16(), + FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"), + web_ui_->tab_contents(), GetParentWindow(), + reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED)); +} + +void CertificateManagerHandler::ImportPersonalFileSelected( + const FilePath& path) { + file_path_ = path; + web_ui_->CallJavascriptFunction( + "CertificateManager.importPersonalAskPassword"); +} + +void CertificateManagerHandler::ImportPersonalPasswordSelected( + const ListValue* args) { + if (!args->GetString(0, &password_)){ + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + ImportExportCleanup(); + return; + } + file_access_provider_->StartRead( + file_path_, + &consumer_, + NewCallback(this, &CertificateManagerHandler::ImportPersonalFileRead)); +} + +void CertificateManagerHandler::ImportPersonalFileRead( + int read_errno, std::string data) { + if (read_errno) { + ImportExportCleanup(); + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE), + l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT, + UTF8ToUTF16(safe_strerror(read_errno)))); + return; + } + + file_data_ = data; + + if (use_hardware_backed_) { + module_ = certificate_manager_model_->cert_db().GetPrivateModule(); + } else { + module_ = certificate_manager_model_->cert_db().GetPublicModule(); + } + + net::CryptoModuleList modules; + modules.push_back(module_); + browser::UnlockSlotsIfNecessary( + modules, + browser::kCryptoModulePasswordCertImport, + "", // unused. + base::Bind(&CertificateManagerHandler::ImportPersonalSlotUnlocked, + base::Unretained(this))); +} + +void CertificateManagerHandler::ImportPersonalSlotUnlocked() { + // Determine if the private key should be unextractable after the import. + // We do this by checking the value of |use_hardware_backed_| which is set + // to true if importing into a hardware module. Currently, this only happens + // for Chrome OS when the "Import and Bind" option is chosen. + bool is_extractable = !use_hardware_backed_; + int result = certificate_manager_model_->ImportFromPKCS12( + module_, file_data_, password_, is_extractable); + ImportExportCleanup(); + web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); + int string_id; + switch (result) { + case net::OK: + return; + case net::ERR_PKCS12_IMPORT_BAD_PASSWORD: + // TODO(mattm): if the error was a bad password, we should reshow the + // password dialog after the user dismisses the error dialog. + string_id = IDS_CERT_MANAGER_BAD_PASSWORD; + break; + case net::ERR_PKCS12_IMPORT_INVALID_MAC: + string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_MAC; + break; + case net::ERR_PKCS12_IMPORT_INVALID_FILE: + string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_FILE; + break; + case net::ERR_PKCS12_IMPORT_UNSUPPORTED: + string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_UNSUPPORTED; + break; + default: + string_id = IDS_CERT_MANAGER_UNKNOWN_ERROR; + break; + } + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE), + l10n_util::GetStringUTF8(string_id)); +} + +void CertificateManagerHandler::CancelImportExportProcess( + const ListValue* args) { + ImportExportCleanup(); +} + +void CertificateManagerHandler::ImportExportCleanup() { + file_path_.clear(); + password_.clear(); + file_data_.clear(); + use_hardware_backed_ = false; + selected_cert_list_.clear(); + module_ = NULL; + + // There may be pending file dialogs, we need to tell them that we've gone + // away so they don't try and call back to us. + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); + select_file_dialog_ = NULL; +} + +void CertificateManagerHandler::ImportServer(const ListValue* args) { + select_file_dialog_ = SelectFileDialog::Create(this); + ShowCertSelectFileDialog( + select_file_dialog_.get(), + SelectFileDialog::SELECT_OPEN_FILE, + FilePath(), + web_ui_->tab_contents(), + GetParentWindow(), + reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED)); +} + +void CertificateManagerHandler::ImportServerFileSelected(const FilePath& path) { + file_path_ = path; + file_access_provider_->StartRead( + file_path_, + &consumer_, + NewCallback(this, &CertificateManagerHandler::ImportServerFileRead)); +} + +void CertificateManagerHandler::ImportServerFileRead(int read_errno, + std::string data) { + if (read_errno) { + ImportExportCleanup(); + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), + l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT, + UTF8ToUTF16(safe_strerror(read_errno)))); + return; + } + + selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes( + data.data(), data.size(), net::X509Certificate::FORMAT_AUTO); + if (selected_cert_list_.empty()) { + ImportExportCleanup(); + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR)); + return; + } + + net::CertDatabase::ImportCertFailureList not_imported; + bool result = certificate_manager_model_->ImportServerCert( + selected_cert_list_, + ¬_imported); + if (!result) { + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); + } else if (!not_imported.empty()) { + ShowImportErrors( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), + not_imported); + } + ImportExportCleanup(); +} + +void CertificateManagerHandler::ImportCA(const ListValue* args) { + select_file_dialog_ = SelectFileDialog::Create(this); + ShowCertSelectFileDialog(select_file_dialog_.get(), + SelectFileDialog::SELECT_OPEN_FILE, + FilePath(), + web_ui_->tab_contents(), + GetParentWindow(), + reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED)); +} + +void CertificateManagerHandler::ImportCAFileSelected(const FilePath& path) { + file_path_ = path; + file_access_provider_->StartRead( + file_path_, + &consumer_, + NewCallback(this, &CertificateManagerHandler::ImportCAFileRead)); +} + +void CertificateManagerHandler::ImportCAFileRead(int read_errno, + std::string data) { + if (read_errno) { + ImportExportCleanup(); + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), + l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT, + UTF8ToUTF16(safe_strerror(read_errno)))); + return; + } + + selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes( + data.data(), data.size(), net::X509Certificate::FORMAT_AUTO); + if (selected_cert_list_.empty()) { + ImportExportCleanup(); + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR)); + return; + } + + scoped_refptr<net::X509Certificate> root_cert = + certificate_manager_model_->cert_db().FindRootInList(selected_cert_list_); + + // TODO(mattm): check here if root_cert is not a CA cert and show error. + + StringValue cert_name(root_cert->subject().GetDisplayName()); + web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport", + cert_name); +} + +void CertificateManagerHandler::ImportCATrustSelected(const ListValue* args) { + bool fail = false; + bool trust_ssl = false; + bool trust_email = false; + bool trust_obj_sign = false; + fail |= !CallbackArgsToBool(args, 0, &trust_ssl); + fail |= !CallbackArgsToBool(args, 1, &trust_email); + fail |= !CallbackArgsToBool(args, 2, &trust_obj_sign); + if (fail) { + LOG(ERROR) << "ImportCATrustSelected args fail"; + ImportExportCleanup(); + web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); + return; + } + + net::CertDatabase::ImportCertFailureList not_imported; + bool result = certificate_manager_model_->ImportCACerts( + selected_cert_list_, + trust_ssl * net::CertDatabase::TRUSTED_SSL + + trust_email * net::CertDatabase::TRUSTED_EMAIL + + trust_obj_sign * net::CertDatabase::TRUSTED_OBJ_SIGN, + ¬_imported); + web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); + if (!result) { + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); + } else if (!not_imported.empty()) { + ShowImportErrors( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), + not_imported); + } + ImportExportCleanup(); +} + +void CertificateManagerHandler::Export(const ListValue* args) { + net::X509Certificate* cert = CallbackArgsToCert(args); + if (!cert) + return; + ShowCertExportDialog(web_ui_->tab_contents(), GetParentWindow(), + cert->os_cert_handle()); +} + +void CertificateManagerHandler::Delete(const ListValue* args) { + net::X509Certificate* cert = CallbackArgsToCert(args); + if (!cert) + return; + bool result = certificate_manager_model_->Delete(cert); + if (!result) { + // TODO(mattm): better error messages? + ShowError( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE), + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); + } +} + +void CertificateManagerHandler::Populate(const ListValue* args) { + certificate_manager_model_->Refresh(); +} + +void CertificateManagerHandler::PopulateTree(const std::string& tab_name, + net::CertType type) { + const std::string tree_name = tab_name + "-tree"; + + scoped_ptr<icu::Collator> collator; + UErrorCode error = U_ZERO_ERROR; + collator.reset( + icu::Collator::createInstance( + icu::Locale(g_browser_process->GetApplicationLocale().c_str()), + error)); + if (U_FAILURE(error)) + collator.reset(NULL); + DictionaryIdComparator comparator(collator.get()); + CertificateManagerModel::OrgGroupingMap map; + + certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map); + + { + ListValue* nodes = new ListValue; + for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin(); + i != map.end(); ++i) { + // Populate first level (org name). + DictionaryValue* dict = new DictionaryValue; + dict->SetString(kKeyId, OrgNameToId(i->first)); + dict->SetString(kNameId, i->first); + + // Populate second level (certs). + ListValue* subnodes = new ListValue; + for (net::CertificateList::const_iterator org_cert_it = i->second.begin(); + org_cert_it != i->second.end(); ++org_cert_it) { + DictionaryValue* cert_dict = new DictionaryValue; + net::X509Certificate* cert = org_cert_it->get(); + cert_dict->SetString(kKeyId, CertToId(*cert)); + cert_dict->SetString(kNameId, certificate_manager_model_->GetColumnText( + *cert, CertificateManagerModel::COL_SUBJECT_NAME)); + cert_dict->SetBoolean( + kReadOnlyId, + certificate_manager_model_->cert_db().IsReadOnly(cert)); + cert_dict->SetBoolean( + kUntrustedId, + certificate_manager_model_->cert_db().IsUntrusted(cert)); + // TODO(mattm): Other columns. + subnodes->Append(cert_dict); + } + std::sort(subnodes->begin(), subnodes->end(), comparator); + + dict->Set(kSubNodesId, subnodes); + nodes->Append(dict); + } + std::sort(nodes->begin(), nodes->end(), comparator); + + ListValue args; + args.Append(Value::CreateStringValue(tree_name)); + args.Append(nodes); + web_ui_->CallJavascriptFunction("CertificateManager.onPopulateTree", args); + } +} + +void CertificateManagerHandler::ShowError(const std::string& title, + const std::string& error) const { + ScopedVector<const Value> args; + args.push_back(Value::CreateStringValue(title)); + args.push_back(Value::CreateStringValue(error)); + args.push_back(Value::CreateStringValue(l10n_util::GetStringUTF8(IDS_OK))); + args.push_back(Value::CreateNullValue()); // cancelTitle + args.push_back(Value::CreateNullValue()); // okCallback + args.push_back(Value::CreateNullValue()); // cancelCallback + web_ui_->CallJavascriptFunction("AlertOverlay.show", args.get()); +} + +void CertificateManagerHandler::ShowImportErrors( + const std::string& title, + const net::CertDatabase::ImportCertFailureList& not_imported) const { + std::string error; + if (selected_cert_list_.size() == 1) + error = l10n_util::GetStringUTF8( + IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED); + else if (not_imported.size() == selected_cert_list_.size()) + error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED); + else + error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED); + + ListValue cert_error_list; + for (size_t i = 0; i < not_imported.size(); ++i) { + const net::CertDatabase::ImportCertFailure& failure = not_imported[i]; + DictionaryValue* dict = new DictionaryValue; + dict->SetString(kNameId, failure.certificate->subject().GetDisplayName()); + dict->SetString(kErrorId, NetErrorToString(failure.net_error)); + cert_error_list.Append(dict); + } + + StringValue title_value(title); + StringValue error_value(error); + web_ui_->CallJavascriptFunction("CertificateImportErrorOverlay.show", + title_value, + error_value, + cert_error_list); +} + +#if defined(OS_CHROMEOS) +void CertificateManagerHandler::CheckTpmTokenReady(const ListValue* args) { + chromeos::CryptohomeLibrary* cryptohome = + chromeos::CrosLibrary::Get()->GetCryptohomeLibrary(); + + // TODO(xiyuan): Use async way when underlying supports it. + base::FundamentalValue ready(cryptohome->Pkcs11IsTpmTokenReady()); + web_ui_->CallJavascriptFunction("CertificateManager.onCheckTpmTokenReady", + ready); +} +#endif + +gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const { + return web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(); +} diff --git a/chrome/browser/ui/webui/options2/certificate_manager_handler.h b/chrome/browser/ui/webui/options2/certificate_manager_handler.h new file mode 100644 index 0000000..0e26a17 --- /dev/null +++ b/chrome/browser/ui/webui/options2/certificate_manager_handler.h @@ -0,0 +1,171 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CERTIFICATE_MANAGER_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CERTIFICATE_MANAGER_HANDLER_H_ +#pragma once + +#include <string> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/certificate_manager_model.h" +#include "chrome/browser/ui/select_file_dialog.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "content/browser/cancelable_request.h" +#include "net/base/cert_database.h" +#include "ui/gfx/native_widget_types.h" + +class FileAccessProvider; + +class CertificateManagerHandler : public OptionsPage2UIHandler, + public CertificateManagerModel::Observer, + public SelectFileDialog::Listener { + public: + CertificateManagerHandler(); + virtual ~CertificateManagerHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // CertificateManagerModel::Observer implementation. + virtual void CertificatesRefreshed() OVERRIDE; + + // SelectFileDialog::Listener implementation. + virtual void FileSelected(const FilePath& path, + int index, + void* params) OVERRIDE; + virtual void FileSelectionCanceled(void* params) OVERRIDE; + + private: + // View certificate. + void View(const base::ListValue* args); + + // Edit server certificate trust values. + void EditServer(const base::ListValue* args); + + // Edit certificate authority trust values. The sequence goes like: + // 1. user clicks edit button -> CertificateEditCaTrustOverlay.show -> + // GetCATrust -> CertificateEditCaTrustOverlay.populateTrust + // 2. user clicks ok -> EditCATrust -> CertificateEditCaTrustOverlay.dismiss + void GetCATrust(const base::ListValue* args); + void EditCATrust(const base::ListValue* args); + + // Cleanup state stored during import or export process. + void CancelImportExportProcess(const base::ListValue* args); + void ImportExportCleanup(); + + // Export to PKCS #12 file. The sequence goes like: + // 1a. user click on export button -> ExportPersonal -> launches file + // selector + // 1b. user click on export all button -> ExportAllPersonal -> launches file + // selector + // 2. user selects file -> ExportPersonalFileSelected -> launches password + // dialog + // 3. user enters password -> ExportPersonalPasswordSelected -> unlock slots + // 4. slots unlocked -> ExportPersonalSlotsUnlocked -> exports to memory + // buffer -> starts async write operation + // 5. write finishes (or fails) -> ExportPersonalFileWritten + void ExportPersonal(const base::ListValue* args); + void ExportAllPersonal(const base::ListValue* args); + void ExportPersonalFileSelected(const FilePath& path); + void ExportPersonalPasswordSelected(const base::ListValue* args); + void ExportPersonalSlotsUnlocked(); + void ExportPersonalFileWritten(int write_errno, int bytes_written); + + // Import from PKCS #12 file. The sequence goes like: + // 1. user click on import button -> StartImportPersonal -> launches file + // selector + // 2. user selects file -> ImportPersonalFileSelected -> launches password + // dialog + // 3. user enters password -> ImportPersonalPasswordSelected -> starts async + // read operation + // 4. read operation completes -> ImportPersonalFileRead -> unlock slot + // 5. slot unlocked -> ImportPersonalSlotUnlocked attempts to + // import with previously entered password + // 6a. if import succeeds -> ImportExportCleanup + // 6b. if import fails -> show error, ImportExportCleanup + // TODO(mattm): allow retrying with different password + void StartImportPersonal(const base::ListValue* args); + void ImportPersonalFileSelected(const FilePath& path); + void ImportPersonalPasswordSelected(const base::ListValue* args); + void ImportPersonalFileRead(int read_errno, std::string data); + void ImportPersonalSlotUnlocked(); + + // Import Server certificates from file. Sequence goes like: + // 1. user clicks on import button -> ImportServer -> launches file selector + // 2. user selects file -> ImportServerFileSelected -> starts async read + // 3. read completes -> ImportServerFileRead -> parse certs -> attempt import + // 4a. if import succeeds -> ImportExportCleanup + // 4b. if import fails -> show error, ImportExportCleanup + void ImportServer(const base::ListValue* args); + void ImportServerFileSelected(const FilePath& path); + void ImportServerFileRead(int read_errno, std::string data); + + // Import Certificate Authorities from file. Sequence goes like: + // 1. user clicks on import button -> ImportCA -> launches file selector + // 2. user selects file -> ImportCAFileSelected -> starts async read + // 3. read completes -> ImportCAFileRead -> parse certs -> + // CertificateEditCaTrustOverlay.showImport + // 4. user clicks ok -> ImportCATrustSelected -> attempt import + // 5a. if import succeeds -> ImportExportCleanup + // 5b. if import fails -> show error, ImportExportCleanup + void ImportCA(const base::ListValue* args); + void ImportCAFileSelected(const FilePath& path); + void ImportCAFileRead(int read_errno, std::string data); + void ImportCATrustSelected(const base::ListValue* args); + + // Export a certificate. + void Export(const base::ListValue* args); + + // Delete certificate and private key (if any). + void Delete(const base::ListValue* args); + + // Populate the trees in all the tabs. + void Populate(const base::ListValue* args); + + // Populate the given tab's tree. + void PopulateTree(const std::string& tab_name, net::CertType type); + + // Display a WebUI error message box. + void ShowError(const std::string& title, const std::string& error) const; + + // Display a WebUI error message box for import failures. + // Depends on |selected_cert_list_| being set to the imports that we + // attempted to import. + void ShowImportErrors( + const std::string& title, + const net::CertDatabase::ImportCertFailureList& not_imported) const; + +#if defined(OS_CHROMEOS) + // Check whether Tpm token is ready and notifiy JS side. + void CheckTpmTokenReady(const base::ListValue* args); +#endif + + gfx::NativeWindow GetParentWindow() const; + + // The Certificates Manager model + scoped_ptr<CertificateManagerModel> certificate_manager_model_; + + // For multi-step import or export processes, we need to store the path, + // password, etc the user chose while we wait for them to enter a password, + // wait for file to be read, etc. + FilePath file_path_; + string16 password_; + bool use_hardware_backed_; + std::string file_data_; + net::CertificateList selected_cert_list_; + scoped_refptr<SelectFileDialog> select_file_dialog_; + scoped_refptr<net::CryptoModule> module_; + + // Used in reading and writing certificate files. + CancelableRequestConsumer consumer_; + scoped_refptr<FileAccessProvider> file_access_provider_; + + DISALLOW_COPY_AND_ASSIGN(CertificateManagerHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CERTIFICATE_MANAGER_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/about_page_handler.cc b/chrome/browser/ui/webui/options2/chromeos/about_page_handler.cc new file mode 100644 index 0000000..31d960e --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/about_page_handler.cc @@ -0,0 +1,419 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/about_page_handler.h" + +#include <vector> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/i18n/time_formatting.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h" +#include "chrome/browser/chromeos/dbus/power_manager_client.h" +#include "chrome/browser/chromeos/dbus/update_engine_client.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/login/wizard_controller.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/common/chrome_version_info.h" +#include "chrome/common/url_constants.h" +#include "content/public/common/content_client.h" +#include "googleurl/src/gurl.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "v8/include/v8.h" +#include "webkit/glue/user_agent.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/user_agent.h" + +namespace { + +// These are used as placeholder text around the links in the text in the +// license. +const char kBeginLink[] = "BEGIN_LINK"; +const char kEndLink[] = "END_LINK"; +const char kBeginLinkChr[] = "BEGIN_LINK_CHR"; +const char kBeginLinkOss[] = "BEGIN_LINK_OSS"; +const char kEndLinkChr[] = "END_LINK_CHR"; +const char kEndLinkOss[] = "END_LINK_OSS"; +const char kBeginLinkCrosOss[] = "BEGIN_LINK_CROS_OSS"; +const char kEndLinkCrosOss[] = "END_LINK_CROS_OSS"; + +// Returns a substring [start, end) from |text|. +std::string StringSubRange(const std::string& text, size_t start, + size_t end) { + DCHECK(end > start); + return text.substr(start, end - start); +} + +} // namespace + +namespace chromeos { + +class AboutPageHandler::UpdateObserver + : public UpdateEngineClient::Observer { + public: + explicit UpdateObserver(AboutPageHandler* handler) : page_handler_(handler) {} + virtual ~UpdateObserver() {} + + AboutPageHandler* page_handler() const { return page_handler_; } + + private: + virtual void UpdateStatusChanged( + const UpdateEngineClient::Status& status) OVERRIDE { + page_handler_->UpdateStatus(status); + } + + AboutPageHandler* page_handler_; + + DISALLOW_COPY_AND_ASSIGN(UpdateObserver); +}; + +AboutPageHandler::AboutPageHandler() + : progress_(-1), + sticky_(false), + started_(false) +{} + +AboutPageHandler::~AboutPageHandler() { + if (update_observer_.get()) { + DBusThreadManager::Get()->GetUpdateEngineClient()-> + RemoveObserver(update_observer_.get()); + } +} + +void AboutPageHandler::GetLocalizedValues(DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "firmware", IDS_ABOUT_PAGE_FIRMWARE }, + { "product", IDS_PRODUCT_OS_NAME }, + { "os", IDS_PRODUCT_OS_NAME }, + { "platform", IDS_PLATFORM_LABEL }, + { "loading", IDS_ABOUT_PAGE_LOADING }, + { "check_now", IDS_ABOUT_PAGE_CHECK_NOW }, + { "update_status", IDS_UPGRADE_CHECK_STARTED }, + { "restart_now", IDS_RELAUNCH_AND_UPDATE }, + { "browser", IDS_PRODUCT_NAME }, + { "more_info", IDS_ABOUT_PAGE_MORE_INFO }, + { "copyright", IDS_ABOUT_VERSION_COPYRIGHT }, + { "channel", IDS_ABOUT_PAGE_CHANNEL }, + { "stable", IDS_ABOUT_PAGE_CHANNEL_STABLE }, + { "beta", IDS_ABOUT_PAGE_CHANNEL_BETA }, + { "dev", IDS_ABOUT_PAGE_CHANNEL_DEVELOPMENT }, + { "canary", IDS_ABOUT_PAGE_CHANNEL_CANARY }, + { "channel_warning_header", IDS_ABOUT_PAGE_CHANNEL_WARNING_HEADER }, + { "channel_warning_text", IDS_ABOUT_PAGE_CHANNEL_WARNING_TEXT }, + { "user_agent", IDS_ABOUT_VERSION_USER_AGENT }, + { "command_line", IDS_ABOUT_VERSION_COMMAND_LINE }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "aboutPage", IDS_ABOUT_TAB_TITLE); + + // browser version + + chrome::VersionInfo version_info; + DCHECK(version_info.is_valid()); + + std::string browser_version = version_info.Version(); + std::string version_modifier = + chrome::VersionInfo::GetVersionStringModifier(); + if (!version_modifier.empty()) + browser_version += " " + version_modifier; + +#if !defined(GOOGLE_CHROME_BUILD) + browser_version += " ("; + browser_version += version_info.LastChange(); + browser_version += ")"; +#endif + + localized_strings->SetString("browser_version", browser_version); + + // license + + std::string text = l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_LICENSE); + + bool chromium_url_appears_first = + text.find(kBeginLinkChr) < text.find(kBeginLinkOss); + + size_t link1 = text.find(kBeginLink); + DCHECK(link1 != std::string::npos); + size_t link1_end = text.find(kEndLink, link1); + DCHECK(link1_end != std::string::npos); + size_t link2 = text.find(kBeginLink, link1_end); + DCHECK(link2 != std::string::npos); + size_t link2_end = text.find(kEndLink, link2); + DCHECK(link2_end != std::string::npos); + + localized_strings->SetString("license_content_0", text.substr(0, link1)); + localized_strings->SetString("license_content_1", + StringSubRange(text, link1_end + strlen(kEndLinkOss), link2)); + localized_strings->SetString("license_content_2", + text.substr(link2_end + strlen(kEndLinkOss))); + + // The Chromium link within the main text of the dialog. + localized_strings->SetString(chromium_url_appears_first ? + "license_link_content_0" : "license_link_content_1", + StringSubRange(text, + text.find(kBeginLinkChr) + strlen(kBeginLinkChr), + text.find(kEndLinkChr))); + GURL url = google_util::AppendGoogleLocaleParam( + GURL(chrome::kChromiumProjectURL)); + localized_strings->SetString(chromium_url_appears_first ? + "license_link_0" : "license_link_1", url.spec()); + + // The Open Source link within the main text of the dialog. + localized_strings->SetString(chromium_url_appears_first ? + "license_link_content_1" : "license_link_content_0", + StringSubRange(text, + text.find(kBeginLinkOss) + strlen(kBeginLinkOss), + text.find(kEndLinkOss))); + localized_strings->SetString(chromium_url_appears_first ? + "license_link_1" : "license_link_0", chrome::kChromeUICreditsURL); + + std::string cros_text = + l10n_util::GetStringUTF8(IDS_ABOUT_CROS_VERSION_LICENSE); + + size_t cros_link = cros_text.find(kBeginLinkCrosOss); + DCHECK(cros_link != std::string::npos); + size_t cros_link_end = cros_text.find(kEndLinkCrosOss, cros_link); + DCHECK(cros_link_end != std::string::npos); + + localized_strings->SetString("cros_license_content_0", + cros_text.substr(0, cros_link)); + localized_strings->SetString("cros_license_content_1", + cros_text.substr(cros_link_end + strlen(kEndLinkCrosOss))); + localized_strings->SetString("cros_license_link_content_0", + StringSubRange(cros_text, cros_link + strlen(kBeginLinkCrosOss), + cros_link_end)); + localized_strings->SetString("cros_license_link_0", + chrome::kChromeUIOSCreditsURL); + + // webkit + + localized_strings->SetString("webkit_version", + webkit_glue::GetWebKitVersion()); + + // javascript + + localized_strings->SetString("js_engine", "V8"); + localized_strings->SetString("js_engine_version", v8::V8::GetVersion()); + + // user agent + + localized_strings->SetString("user_agent_info", + content::GetUserAgent(GURL())); + + // command line + +#if defined(OS_WIN) + localized_strings->SetString("command_line_info", + WideToUTF16(CommandLine::ForCurrentProcess()->GetCommandLineString())); +#elif defined(OS_POSIX) + // TODO(viettrungluu): something horrible might happen if there are non-UTF-8 + // arguments (since |SetString()| requires Unicode). + std::string command_line = ""; + typedef std::vector<std::string> ArgvList; + const ArgvList& argv = CommandLine::ForCurrentProcess()->argv(); + for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++) + command_line += " " + *iter; + localized_strings->SetString("command_line_info", command_line); +#endif +} + +void AboutPageHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("PageReady", + base::Bind(&AboutPageHandler::PageReady, base::Unretained(this))); + web_ui_->RegisterMessageCallback("SetReleaseTrack", + base::Bind(&AboutPageHandler::SetReleaseTrack, base::Unretained(this))); + + web_ui_->RegisterMessageCallback("CheckNow", + base::Bind(&AboutPageHandler::CheckNow, base::Unretained(this))); + web_ui_->RegisterMessageCallback("RestartNow", + base::Bind(&AboutPageHandler::RestartNow, base::Unretained(this))); +} + +void AboutPageHandler::PageReady(const ListValue* args) { + // Version information is loaded from a callback + loader_.GetVersion(&consumer_, + base::Bind(&AboutPageHandler::OnOSVersion, + base::Unretained(this)), + VersionLoader::VERSION_FULL); + loader_.GetFirmware(&consumer_, + base::Bind(&AboutPageHandler::OnOSFirmware, + base::Unretained(this))); + + UpdateEngineClient* update_engine_client = + DBusThreadManager::Get()->GetUpdateEngineClient(); + + update_observer_.reset(new UpdateObserver(this)); + update_engine_client->AddObserver(update_observer_.get()); + + // Update the WebUI page with the current status. See comments below. + UpdateStatus(update_engine_client->GetLastStatus()); + + // Initiate update check. UpdateStatus() below will be called when we + // get update status via update_observer_. If the update has been + // already complete, update_observer_ won't receive a notification. + // This is why we manually update the WebUI page above. + CheckNow(NULL); + + // Request the channel information. Use the observer to track the about + // page handler and ensure it does not get deleted before the callback. + update_engine_client->GetReleaseTrack( + base::Bind(UpdateSelectedChannel, update_observer_.get())); +} + +void AboutPageHandler::SetReleaseTrack(const ListValue* args) { + if (!UserManager::Get()->current_user_is_owner()) { + LOG(WARNING) << "Non-owner tried to change release track."; + return; + } + const std::string channel = UTF16ToUTF8(ExtractStringValue(args)); + DBusThreadManager::Get()->GetUpdateEngineClient()->SetReleaseTrack(channel); +} + +void AboutPageHandler::CheckNow(const ListValue* args) { + // Make sure that libcros is loaded and OOBE is complete. + if (!WizardController::default_controller() || + WizardController::IsDeviceRegistered()) { + DBusThreadManager::Get()->GetUpdateEngineClient()-> + RequestUpdateCheck(UpdateEngineClient::EmptyUpdateCheckCallback()); + } +} + +void AboutPageHandler::RestartNow(const ListValue* args) { + DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); +} + +void AboutPageHandler::UpdateStatus( + const UpdateEngineClient::Status& status) { + string16 message; + std::string image = "up-to-date"; + bool enabled = false; + + switch (status.status) { + case UpdateEngineClient::UPDATE_STATUS_IDLE: + if (!sticky_) { + message = l10n_util::GetStringFUTF16(IDS_UPGRADE_ALREADY_UP_TO_DATE, + l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)); + enabled = true; + } + break; + case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE: + message = l10n_util::GetStringUTF16(IDS_UPGRADE_CHECK_STARTED); + sticky_ = false; + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: + message = l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE); + started_ = true; + break; + case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: + { + int progress = static_cast<int>(status.download_progress * 100.0); + if (progress != progress_) { + progress_ = progress; + message = l10n_util::GetStringFUTF16Int(IDS_UPDATE_DOWNLOADING, + progress_); + } + started_ = true; + } + break; + case UpdateEngineClient::UPDATE_STATUS_VERIFYING: + message = l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING); + started_ = true; + break; + case UpdateEngineClient::UPDATE_STATUS_FINALIZING: + message = l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING); + started_ = true; + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: + message = l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED); + image = "available"; + sticky_ = true; + break; + default: + // case UpdateEngineClient::UPDATE_STATUS_ERROR: + // case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT: + + // The error is only displayed if we were able to determine an + // update was available. + if (started_) { + message = l10n_util::GetStringUTF16(IDS_UPDATE_ERROR); + image = "fail"; + enabled = true; + sticky_ = true; + started_ = false; + } + break; + } + if (message.size()) { + scoped_ptr<Value> update_message(Value::CreateStringValue(message)); + // "Checking for update..." needs to be shown for a while, so users + // can read it, hence insert delay for this. + scoped_ptr<Value> insert_delay(Value::CreateBooleanValue( + status.status == + UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE)); + web_ui_->CallJavascriptFunction("AboutPage.updateStatusCallback", + *update_message, *insert_delay); + + scoped_ptr<Value> enabled_value(Value::CreateBooleanValue(enabled)); + web_ui_->CallJavascriptFunction("AboutPage.updateEnableCallback", + *enabled_value); + + scoped_ptr<Value> image_string(Value::CreateStringValue(image)); + web_ui_->CallJavascriptFunction("AboutPage.setUpdateImage", + *image_string); + } + // We'll change the "Check For Update" button to "Restart" button. + if (status.status == UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { + web_ui_->CallJavascriptFunction("AboutPage.changeToRestartButton"); + } +} + +void AboutPageHandler::OnOSVersion(VersionLoader::Handle handle, + std::string version) { + if (version.size()) { + scoped_ptr<Value> version_string(Value::CreateStringValue(version)); + web_ui_->CallJavascriptFunction("AboutPage.updateOSVersionCallback", + *version_string); + } +} + +void AboutPageHandler::OnOSFirmware(VersionLoader::Handle handle, + std::string firmware) { + if (firmware.size()) { + scoped_ptr<Value> firmware_string(Value::CreateStringValue(firmware)); + web_ui_->CallJavascriptFunction("AboutPage.updateOSFirmwareCallback", + *firmware_string); + } +} + +// Callback from UpdateEngine with channel information. +// static +void AboutPageHandler::UpdateSelectedChannel(UpdateObserver* observer, + const std::string& channel) { + if (DBusThreadManager::Get()->GetUpdateEngineClient() + ->HasObserver(observer)) { + // If UpdateEngineClient still has the observer, then the page handler + // is valid. + AboutPageHandler* handler = observer->page_handler(); + scoped_ptr<Value> channel_string(Value::CreateStringValue(channel)); + handler->web_ui_->CallJavascriptFunction( + "AboutPage.updateSelectedOptionCallback", *channel_string); + } +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/about_page_handler.h b/chrome/browser/ui/webui/options2/chromeos/about_page_handler.h new file mode 100644 index 0000000..69b6895 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/about_page_handler.h @@ -0,0 +1,74 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_ABOUT_PAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_ABOUT_PAGE_HANDLER_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "chrome/browser/chromeos/dbus/update_engine_client.h" +#include "chrome/browser/chromeos/version_loader.h" + +namespace chromeos { + +// ChromeOS about page UI handler. +class AboutPageHandler : public OptionsPage2UIHandler { + + public: + AboutPageHandler(); + virtual ~AboutPageHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + private: + class UpdateObserver; + + // The function is called from JavaScript when the about page is ready. + void PageReady(const base::ListValue* args); + + // The function is called from JavaScript to set the release track like + // "beta-channel" and "dev-channel". + void SetReleaseTrack(const base::ListValue* args); + + // Initiates update check. + void CheckNow(const base::ListValue* args); + + // Restarts the system. + void RestartNow(const base::ListValue* args); + + // Callback from VersionLoader giving the version. + void OnOSVersion(VersionLoader::Handle handle, + std::string version); + void OnOSFirmware(VersionLoader::Handle handle, + std::string firmware); + void UpdateStatus(const UpdateEngineClient::Status& status); + + // UpdateEngine Callback handler. + static void UpdateSelectedChannel(UpdateObserver* observer, + const std::string& channel); + + // Handles asynchronously loading the version. + VersionLoader loader_; + + // Used to request the version. + CancelableRequestConsumer consumer_; + + // Update Observer + scoped_ptr<UpdateObserver> update_observer_; + + int progress_; + bool sticky_; + bool started_; + + DISALLOW_COPY_AND_ASSIGN(AboutPageHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_ABOUT_PAGE_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.cc new file mode 100644 index 0000000..396dcec --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/json/json_reader.h" +#include "base/memory/scoped_ptr.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/cros_settings.h" +#include "chrome/browser/chromeos/cros_settings_names.h" +#include "chrome/browser/chromeos/login/authenticator.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/policy/browser_policy_connector.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chromeos { + +namespace { + +// Adds specified user to the whitelist. Returns false if that user is already +// in the whitelist. +bool WhitelistUser(const std::string& username) { + CrosSettings* cros_settings = CrosSettings::Get(); + if (cros_settings->FindEmailInList(kAccountsPrefUsers, username)) + return false; + base::StringValue username_value(username); + cros_settings->AppendToList(kAccountsPrefUsers, &username_value); + return true; +} + +} // namespace + +AccountsOptionsHandler::AccountsOptionsHandler() { +} + +AccountsOptionsHandler::~AccountsOptionsHandler() { +} + +void AccountsOptionsHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("whitelistUser", + base::Bind(&AccountsOptionsHandler::HandleWhitelistUser, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("unwhitelistUser", + base::Bind(&AccountsOptionsHandler::HandleUnwhitelistUser, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("whitelistExistingUsers", + base::Bind(&AccountsOptionsHandler::HandleWhitelistExistingUsers, + base::Unretained(this))); +} + +void AccountsOptionsHandler::GetLocalizedValues( + base::DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "accountsPage", + IDS_OPTIONS_ACCOUNTS_TAB_LABEL); + + localized_strings->SetString("allow_BWSI", l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_ALLOW_BWSI_DESCRIPTION)); + localized_strings->SetString("use_whitelist",l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_USE_WHITELIST_DESCRIPTION)); + localized_strings->SetString("show_user_on_signin",l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_SHOW_USER_NAMES_ON_SINGIN_DESCRIPTION)); + localized_strings->SetString("username_edit_hint",l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_USERNAME_EDIT_HINT)); + localized_strings->SetString("username_format",l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_USERNAME_FORMAT)); + localized_strings->SetString("add_users",l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_ADD_USERS)); + localized_strings->SetString("owner_only", l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_OWNER_ONLY)); + + std::string owner_email; + CrosSettings::Get()->GetString(kDeviceOwner, &owner_email); + // Translate owner's email to the display email. + std::string display_email = + UserManager::Get()->GetUserDisplayEmail(owner_email); + localized_strings->SetString("owner_user_id", UTF8ToUTF16(display_email)); + + localized_strings->SetString("current_user_is_owner", + UserManager::Get()->current_user_is_owner() ? + ASCIIToUTF16("true") : ASCIIToUTF16("false")); + localized_strings->SetString("logged_in_as_guest", + UserManager::Get()->IsLoggedInAsGuest() ? + ASCIIToUTF16("true") : ASCIIToUTF16("false")); + localized_strings->SetString("whitelist_is_managed", + g_browser_process->browser_policy_connector()->IsEnterpriseManaged() ? + ASCIIToUTF16("true") : ASCIIToUTF16("false")); +} + +void AccountsOptionsHandler::HandleWhitelistUser(const base::ListValue* args) { + std::string typed_email; + std::string name; + if (!args->GetString(0, &typed_email) || + !args->GetString(1, &name)) { + return; + } + + WhitelistUser(Authenticator::Canonicalize(typed_email)); +} + +void AccountsOptionsHandler::HandleUnwhitelistUser( + const base::ListValue* args) { + std::string email; + if (!args->GetString(0, &email)) { + return; + } + + base::StringValue canonical_email(Authenticator::Canonicalize(email)); + CrosSettings::Get()->RemoveFromList(kAccountsPrefUsers, &canonical_email); + UserManager::Get()->RemoveUser(email, NULL); +} + +void AccountsOptionsHandler::HandleWhitelistExistingUsers( + const base::ListValue* args) { + DCHECK(args && args->empty()); + + const UserList& users = UserManager::Get()->GetUsers(); + for (UserList::const_iterator it = users.begin(); it < users.end(); ++it) { + WhitelistUser((*it)->email()); + } +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.h new file mode 100644 index 0000000..61c2487 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.h @@ -0,0 +1,40 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_ACCOUNTS_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_ACCOUNTS_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace chromeos { + +// ChromeOS accounts options page handler. +class AccountsOptionsHandler : public OptionsPage2UIHandler { + public: + AccountsOptionsHandler(); + virtual ~AccountsOptionsHandler(); + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + private: + // Javascript callbacks to whitelist/unwhitelist user. + void HandleWhitelistUser(const base::ListValue* args); + void HandleUnwhitelistUser(const base::ListValue* args); + + // Javascript callback to auto add existing users to white list. + void HandleWhitelistExistingUsers(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(AccountsOptionsHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_ACCOUNTS_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.cc new file mode 100644 index 0000000..f8f6a28 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.cc @@ -0,0 +1,411 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/bluetooth/bluetooth_device.h" +#include "chrome/browser/chromeos/system/runtime_environment.h" +#include "chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h" +#include "chrome/common/chrome_switches.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +// |UpdateDeviceCallback| takes a variable length list as an argument. The +// value stored in each list element is indicated by the following constants. +const int kUpdateDeviceAddressIndex = 0; +const int kUpdateDeviceCommandIndex = 1; +const int kUpdateDevicePasskeyIndex = 2; + +} // namespace + +namespace chromeos { + +BluetoothOptionsHandler::BluetoothOptionsHandler() { +} + +BluetoothOptionsHandler::~BluetoothOptionsHandler() { + if (!CommandLine::ForCurrentProcess() + ->HasSwitch(switches::kEnableBluetooth)) { + return; + } + + chromeos::BluetoothManager* bluetooth_manager = + chromeos::BluetoothManager::GetInstance(); + DCHECK(bluetooth_manager); + + chromeos::BluetoothAdapter* default_adapter = + bluetooth_manager->DefaultAdapter(); + + if (default_adapter != NULL) { + default_adapter->RemoveObserver(this); + } + + bluetooth_manager->RemoveObserver(this); +} + +void BluetoothOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + localized_strings->SetString("bluetooth", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH)); + localized_strings->SetString("disableBluetooth", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_DISABLE)); + localized_strings->SetString("enableBluetooth", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_ENABLE)); + localized_strings->SetString("noBluetoothDevicesFound", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_NO_BLUETOOTH_DEVICES_FOUND)); + localized_strings->SetString("findBluetoothDevices", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_FIND_BLUETOOTH_DEVICES)); + localized_strings->SetString("bluetoothScanning", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_SCANNING)); + localized_strings->SetString("bluetoothDeviceConnected", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTED)); + localized_strings->SetString("bluetoothDeviceConnecting", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING)); + localized_strings->SetString("bluetoothDeviceNotPaired", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_NOT_PAIRED)); + localized_strings->SetString("bluetoothDevicePaired", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_PAIRED)); + localized_strings->SetString("bluetoothDeviceFailedPairing", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_FAILED_PAIRING)); + localized_strings->SetString("bluetoothConnectDevice", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT)); + localized_strings->SetString("bluetoothDisconnectDevice", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT)); + localized_strings->SetString("bluetoothForgetDevice", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET)); + localized_strings->SetString("bluetoothCancel", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL)); + localized_strings->SetString("bluetoothAcceptPasskey", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY)); + localized_strings->SetString("bluetoothRejectPasskey", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY)); + localized_strings->SetString("bluetoothConfirmPasskey", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY_REQUEST)); + localized_strings->SetString("bluetoothEnterPasskey", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PASSKEY_REQUEST)); + localized_strings->SetString("bluetoothRemotePasskey", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PASSKEY_REQUEST)); + localized_strings->SetString("bluetoothFailedPairingInstructions", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BLUETOOTH_FAILED_PAIRING_INSTRUCTIONS)); +} + +void BluetoothOptionsHandler::Initialize() { + DCHECK(web_ui_); + // Bluetooth support is a work in progress. Supress the feature unless + // explicitly enabled via a command line flag. + if (!CommandLine::ForCurrentProcess() + ->HasSwitch(switches::kEnableBluetooth)) { + return; + } + + web_ui_->CallJavascriptFunction( + "options.SystemOptions.showBluetoothSettings"); + + // TODO(kevers): Determine whether bluetooth adapter is powered. + bool bluetooth_on = false; + base::FundamentalValue checked(bluetooth_on); + web_ui_->CallJavascriptFunction( + "options.SystemOptions.setBluetoothState", checked); + + chromeos::BluetoothManager* bluetooth_manager = + chromeos::BluetoothManager::GetInstance(); + DCHECK(bluetooth_manager); + bluetooth_manager->AddObserver(this); + + chromeos::BluetoothAdapter* default_adapter = + bluetooth_manager->DefaultAdapter(); + DefaultAdapterChanged(default_adapter); +} + +void BluetoothOptionsHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("bluetoothEnableChange", + base::Bind(&BluetoothOptionsHandler::EnableChangeCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("findBluetoothDevices", + base::Bind(&BluetoothOptionsHandler::FindDevicesCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("updateBluetoothDevice", + base::Bind(&BluetoothOptionsHandler::UpdateDeviceCallback, + base::Unretained(this))); +} + +void BluetoothOptionsHandler::EnableChangeCallback( + const ListValue* args) { + bool bluetooth_enabled; + args->GetBoolean(0, &bluetooth_enabled); + // TODO(kevers): Call Bluetooth API to enable or disable. + base::FundamentalValue checked(bluetooth_enabled); + web_ui_->CallJavascriptFunction( + "options.SystemOptions.setBluetoothState", checked); +} + +void BluetoothOptionsHandler::FindDevicesCallback( + const ListValue* args) { + // We only initiate a scan if we're running on Chrome OS. Otherwise, we + // generate a fake device list. + if (!chromeos::system::runtime_environment::IsRunningOnChromeOS()) { + GenerateFakeDeviceList(); + return; + } + + chromeos::BluetoothManager* bluetooth_manager = + chromeos::BluetoothManager::GetInstance(); + DCHECK(bluetooth_manager); + + chromeos::BluetoothAdapter* default_adapter = + bluetooth_manager->DefaultAdapter(); + + ValidateDefaultAdapter(default_adapter); + + if (default_adapter == NULL) { + VLOG(1) << "FindDevicesCallback: no default adapter"; + return; + } + + default_adapter->StartDiscovery(); +} + +void BluetoothOptionsHandler::UpdateDeviceCallback( + const ListValue* args) { + // TODO(kevers): Trigger connect/disconnect. + int size = args->GetSize(); + std::string address; + std::string command; + args->GetString(kUpdateDeviceAddressIndex, &address); + args->GetString(kUpdateDeviceCommandIndex, &command); + if (size > kUpdateDevicePasskeyIndex) { + // Passkey confirmation as part of the pairing process. + std::string passkey; + args->GetString(kUpdateDevicePasskeyIndex, &passkey); + DVLOG(1) << "UpdateDeviceCallback: " << address << ": " << command + << " [" << passkey << "]"; + } else { + // Initiating a device connection or disconnecting + DVLOG(1) << "UpdateDeviceCallback: " << address << ": " << command; + } +} + +void BluetoothOptionsHandler::SendDeviceNotification( + chromeos::BluetoothDevice* device, + base::DictionaryValue* params) { + // Retrieve properties of the bluetooth device. The properties names are + // in title case. Convert to camel case in accordance with our Javascript + // naming convention. + const DictionaryValue& properties = device->AsDictionary(); + base::DictionaryValue js_properties; + for (DictionaryValue::key_iterator it = properties.begin_keys(); + it != properties.end_keys(); ++it) { + base::Value* child = NULL; + properties.GetWithoutPathExpansion(*it, &child); + if (child) { + std::string js_key = *it; + js_key[0] = tolower(js_key[0]); + js_properties.SetWithoutPathExpansion(js_key, child->DeepCopy()); + } + } + if (params) { + js_properties.MergeDictionary(params); + } + web_ui_->CallJavascriptFunction( + "options.SystemOptions.addBluetoothDevice", + js_properties); +} + +void BluetoothOptionsHandler::RequestConfirmation( + chromeos::BluetoothDevice* device, + int passkey) { + DictionaryValue params; + params.SetString("pairing", "bluetoothConfirmPasskey"); + params.SetInteger("passkey", passkey); + SendDeviceNotification(device, ¶ms); +} + +void BluetoothOptionsHandler::DisplayPasskey( + chromeos::BluetoothDevice* device, + int passkey, + int entered) { + DictionaryValue params; + params.SetString("pairing", "bluetoothRemotePasskey"); + params.SetInteger("passkey", passkey); + params.SetInteger("entered", entered); + SendDeviceNotification(device, ¶ms); +} + +void BluetoothOptionsHandler::RequestPasskey( + chromeos::BluetoothDevice* device) { + DictionaryValue params; + params.SetString("pairing", "bluetoothEnterPasskey"); + SendDeviceNotification(device, ¶ms); +} + +void BluetoothOptionsHandler::ValidatePasskeyCallback( + const base::ListValue* args) { + // TODO(kevers): Implement me. +} + +void BluetoothOptionsHandler::DefaultAdapterChanged( + chromeos::BluetoothAdapter* adapter) { + std::string old_default_adapter_id = default_adapter_id_; + + if (adapter == NULL) { + default_adapter_id_.clear(); + VLOG(2) << "DefaultAdapterChanged: no default bluetooth adapter"; + } else { + default_adapter_id_ = adapter->Id(); + VLOG(2) << "DefaultAdapterChanged: " << default_adapter_id_; + } + + if (default_adapter_id_ == old_default_adapter_id) { + return; + } + + if (adapter != NULL) { + adapter->AddObserver(this); + } + + // TODO(vlaviano): Respond to adapter change. +} + +void BluetoothOptionsHandler::DiscoveryStarted(const std::string& adapter_id) { + VLOG(2) << "Discovery started on " << adapter_id; +} + +void BluetoothOptionsHandler::DiscoveryEnded(const std::string& adapter_id) { + VLOG(2) << "Discovery ended on " << adapter_id; + web_ui_->CallJavascriptFunction( + "options.SystemOptions.notifyBluetoothSearchComplete"); + + // Stop the discovery session. + // TODO(vlaviano): We may want to expose DeviceDisappeared, remove the + // "Find devices" button, and let the discovery session continue throughout + // the time that the page is visible rather than just doing a single discovery + // cycle in response to a button click. + chromeos::BluetoothManager* bluetooth_manager = + chromeos::BluetoothManager::GetInstance(); + DCHECK(bluetooth_manager); + + chromeos::BluetoothAdapter* default_adapter = + bluetooth_manager->DefaultAdapter(); + + ValidateDefaultAdapter(default_adapter); + + if (default_adapter == NULL) { + VLOG(1) << "DiscoveryEnded: no default adapter"; + return; + } + + default_adapter->StopDiscovery(); +} + +void BluetoothOptionsHandler::DeviceFound(const std::string& adapter_id, + chromeos::BluetoothDevice* device) { + VLOG(2) << "Device found on " << adapter_id; + DCHECK(device); + SendDeviceNotification(device, NULL); +} + +void BluetoothOptionsHandler::ValidateDefaultAdapter( + chromeos::BluetoothAdapter* adapter) { + if ((adapter == NULL && !default_adapter_id_.empty()) || + (adapter != NULL && default_adapter_id_ != adapter->Id())) { + VLOG(1) << "unexpected default adapter change from \"" + << default_adapter_id_ << "\" to \"" << adapter->Id() << "\""; + DefaultAdapterChanged(adapter); + } +} + +void BluetoothOptionsHandler::GenerateFakeDeviceList() { + GenerateFakeDevice( + "Fake Wireless Keyboard", + "01-02-03-04-05-06", + "input-keyboard", + true, + true, + ""); + GenerateFakeDevice( + "Fake Wireless Mouse", + "02-03-04-05-06-01", + "input-mouse", + true, + false, + ""); + GenerateFakeDevice( + "Fake Wireless Headset", + "03-04-05-06-01-02", + "headset", + false, + false, + ""); + GenerateFakeDevice( + "Fake Connecting Keyboard", + "04-05-06-01-02-03", + "input-keyboard", + false, + false, + "bluetoothRemotePasskey"); + GenerateFakeDevice( + "Fake Connecting Phone", + "05-06-01-02-03-04", + "phone", + false, + false, + "bluetoothConfirmPasskey"); + GenerateFakeDevice( + "Fake Connecting Headset", + "06-01-02-03-04-05", + "headset", + false, + false, + "bluetoothEnterPasskey"); + web_ui_->CallJavascriptFunction( + "options.SystemOptions.notifyBluetoothSearchComplete"); +} + +void BluetoothOptionsHandler::GenerateFakeDevice( + const std::string& name, + const std::string& address, + const std::string& icon, + bool paired, + bool connected, + const std::string& pairing) { + DictionaryValue properties; + properties.SetString(bluetooth_device::kNameProperty, name); + properties.SetString(bluetooth_device::kAddressProperty, address); + properties.SetString(bluetooth_device::kIconProperty, icon); + properties.SetBoolean(bluetooth_device::kPairedProperty, paired); + properties.SetBoolean(bluetooth_device::kConnectedProperty, connected); + properties.SetInteger(bluetooth_device::kClassProperty, 0); + chromeos::BluetoothDevice* device = + chromeos::BluetoothDevice::Create(properties); + DeviceFound("FakeAdapter", device); + if (pairing.compare("bluetoothRemotePasskey") == 0) { + DisplayPasskey(device, 12345, 2); + } else if (pairing.compare("bluetoothConfirmPasskey") == 0) { + RequestConfirmation(device, 12345); + } else if (pairing.compare("bluetoothEnterPasskey") == 0) { + RequestPasskey(device); + } + delete device; +} + +} // namespace chromeos + diff --git a/chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.h new file mode 100644 index 0000000..c57dbb7 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.h @@ -0,0 +1,138 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_BLUETOOTH_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_BLUETOOTH_OPTIONS_HANDLER_H_ +#pragma once + +#include <string> + +#include "base/compiler_specific.h" +#include "chrome/browser/chromeos/bluetooth/bluetooth_adapter.h" +#include "chrome/browser/chromeos/bluetooth/bluetooth_manager.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +} + +namespace chromeos { + +// Handler for Bluetooth options on the system options page. +class BluetoothOptionsHandler : public OptionsPage2UIHandler, + public chromeos::BluetoothManager::Observer, + public chromeos::BluetoothAdapter::Observer { + public: + BluetoothOptionsHandler(); + virtual ~BluetoothOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // Called when the 'Enable bluetooth' checkbox value is changed. + // |args| will contain the checkbox checked state as a string + // ("true" or "false"). + void EnableChangeCallback(const base::ListValue* args); + + // Called when the 'Find Devices' button is pressed from the Bluetooth + // ssettings. + // |args| will be an empty list. + void FindDevicesCallback(const base::ListValue* args); + + // Called when the user requests to connect to or disconnect from a Bluetooth + // device. + // |args| will be a list containing two or three arguments, the first argument + // is the device ID and the second is the requested action. If a third + // argument is present, it is the passkey for pairing confirmation. + void UpdateDeviceCallback(const base::ListValue* args); + + // Sends a notification to the Web UI of the status of a Bluetooth device. + // |device| is the Bluetooth device. + // |params| is an optional set of parameters. + void SendDeviceNotification(chromeos::BluetoothDevice* device, + base::DictionaryValue* params); + + // Displays a passkey for a device, requesting user confirmation that the + // key matches an expected value (value displayed on a smartphone for + // example). + // |device| is the Bluetooth device being paired. + // |passkey| is the passkey to display for confirmation. + void RequestConfirmation(chromeos::BluetoothDevice* device, + int passkey); + + // Displays a passkey for a device, which is being typed remotely. During + // the pairing process, this method may be called repeatedly to track the + // number of characters entered. This method is commonly used for pairing + // keyboards. + // |device| is the Bluetooth device being paired. + // |passkey| is the required passkey. + // |entered| is the number of characters that have already been entered on + // the remote device. + void DisplayPasskey(chromeos::BluetoothDevice* device, + int passkey, + int entered); + + // Displays a blank field for entering a passkey. The passkey may be + // a set value specified by the manufacturer of the Bluetooth device, or + // on a remote display. The validation is asychronous, and a call is made + // to |ValidatePasskeyCallback| when the passkey entry is complete. + // |device| is the Bluetooth device being paired. + void RequestPasskey(chromeos::BluetoothDevice* device); + + // Callback to validate a user entered passkey. + // |args| is a list containing the device address and entered passkey. + void ValidatePasskeyCallback(const base::ListValue* args); + + // chromeos::BluetoothManager::Observer override. + virtual void DefaultAdapterChanged( + chromeos::BluetoothAdapter* adapter) OVERRIDE; + + // chromeos::BluetoothAdapter::Observer override. + virtual void DiscoveryStarted(const std::string& adapter_id) OVERRIDE; + + // chromeos::BluetoothAdapter::Observer override. + virtual void DiscoveryEnded(const std::string& adapter_id) OVERRIDE; + + // chromeos::BluetoothAdapter::Observer override. + virtual void DeviceFound(const std::string& adapter_id, + chromeos::BluetoothDevice* device) OVERRIDE; + + private: + // Compares |adapter| with our cached default adapter ID and calls + // DefaultAdapterChanged if there has been an unexpected change. + void ValidateDefaultAdapter(chromeos::BluetoothAdapter* adapter); + + // Simulates extracting a list of available bluetooth devices. + // Called when emulating ChromeOS from a desktop environment. + void GenerateFakeDeviceList(); + + // Simulates the discovery or pairing of a Bluetooth device. Used when + // emulating ChromeOS from a desktop environment. + // |name| is the display name for the device. + // |address| is the unique Mac address of the device. + // |icon| is the base name of the icon to use for the device and corresponds + // to the general device category (e.g. mouse or keyboard). + // |paired| indicates if the device is paired. + // |connected| indicates if the device is connected. + // |pairing| indicates the type of pairing operation. + void GenerateFakeDevice(const std::string& name, + const std::string& address, + const std::string& icon, + bool paired, + bool connected, + const std::string& pairing); + + // The id of the current default bluetooth adapter. + // The empty string represents "none". + std::string default_adapter_id_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothOptionsHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_BLUETOOTH_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.cc new file mode 100644 index 0000000..88019ac --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.cc @@ -0,0 +1,344 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/metrics/histogram.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/chromeos/login/camera_detector.h" +#include "chrome/browser/chromeos/login/default_user_images.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/options2/take_photo_dialog.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/dialog_style.h" +#include "chrome/browser/ui/views/window.h" +#include "chrome/browser/ui/webui/web_ui_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/notification_service.h" +#include "content/public/common/url_constants.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/widget/widget.h" + +namespace chromeos { + +namespace { + +// Returns info about extensions for files we support as user images. +SelectFileDialog::FileTypeInfo GetUserImageFileTypeInfo() { + SelectFileDialog::FileTypeInfo file_type_info; + file_type_info.extensions.resize(5); + + file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("bmp")); + + file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("gif")); + + file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("jpg")); + file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("jpeg")); + + file_type_info.extensions[3].push_back(FILE_PATH_LITERAL("png")); + + file_type_info.extensions[4].push_back(FILE_PATH_LITERAL("tif")); + file_type_info.extensions[4].push_back(FILE_PATH_LITERAL("tiff")); + + return file_type_info; +} + +} // namespace + +ChangePictureOptionsHandler::ChangePictureOptionsHandler() + : previous_image_data_url_(chrome::kAboutBlankURL), + previous_image_index_(User::kInvalidImageIndex), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, + content::NotificationService::AllSources()); + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, + content::NotificationService::AllSources()); +} + +ChangePictureOptionsHandler::~ChangePictureOptionsHandler() { + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); +} + +void ChangePictureOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + localized_strings->SetString("changePicturePage", + l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TITLE)); + localized_strings->SetString("changePicturePageDescription", + l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT)); + localized_strings->SetString("takePhoto", + l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_TAKE_PHOTO)); + localized_strings->SetString("chooseFile", + l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_CHOOSE_FILE)); + localized_strings->SetString("profilePhoto", + l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_PROFILE_PHOTO)); + localized_strings->SetString("profilePhotoLoading", + l10n_util::GetStringUTF16( + IDS_OPTIONS_CHANGE_PICTURE_PROFILE_LOADING_PHOTO)); +} + +void ChangePictureOptionsHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("chooseFile", + base::Bind(&ChangePictureOptionsHandler::HandleChooseFile, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("takePhoto", + base::Bind(&ChangePictureOptionsHandler::HandleTakePhoto, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("onChangePicturePageShown", + base::Bind(&ChangePictureOptionsHandler::HandlePageShown, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("onChangePicturePageInitialized", + base::Bind(&ChangePictureOptionsHandler::HandlePageInitialized, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("selectImage", + base::Bind(&ChangePictureOptionsHandler::HandleSelectImage, + base::Unretained(this))); +} + +void ChangePictureOptionsHandler::SendDefaultImages() { + ListValue image_urls; + for (int i = 0; i < kDefaultImagesCount; ++i) { + image_urls.Append(new StringValue(GetDefaultImageUrl(i))); + } + web_ui_->CallJavascriptFunction("ChangePictureOptions.setDefaultImages", + image_urls); +} + +void ChangePictureOptionsHandler::HandleChooseFile(const ListValue* args) { + DCHECK(args && args->empty()); + if (!select_file_dialog_.get()) + select_file_dialog_ = SelectFileDialog::Create(this); + + FilePath downloads_path; + if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &downloads_path)) { + NOTREACHED(); + return; + } + + // Static so we initialize it only once. + CR_DEFINE_STATIC_LOCAL(SelectFileDialog::FileTypeInfo, file_type_info, + (GetUserImageFileTypeInfo())); + + select_file_dialog_->SelectFile( + SelectFileDialog::SELECT_OPEN_FILE, + l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE), + downloads_path, + &file_type_info, + 0, + FILE_PATH_LITERAL(""), + web_ui_->tab_contents(), + GetBrowserWindow(), + NULL); +} + +void ChangePictureOptionsHandler::HandleTakePhoto(const ListValue* args) { + DCHECK(args && args->empty()); + views::Widget* window = browser::CreateViewsWindow( + GetBrowserWindow(), + new TakePhotoDialog(this), + STYLE_GENERIC); + window->SetAlwaysOnTop(true); + window->Show(); +} + +void ChangePictureOptionsHandler::HandlePageInitialized( + const base::ListValue* args) { + DCHECK(args && args->empty()); + // If no camera presence check has been performed in this session, + // start one now. + if (CameraDetector::camera_presence() == + CameraDetector::kCameraPresenceUnknown) { + CheckCameraPresence(); + } + + // While the check is in progress, use previous camera presence state and + // presume it is present if no check has been performed yet. + SetCameraPresent(CameraDetector::camera_presence() != + CameraDetector::kCameraAbsent); + + SendDefaultImages(); +} + +void ChangePictureOptionsHandler::HandlePageShown(const base::ListValue* args) { + DCHECK(args && args->empty()); + // TODO(ivankr): If user opens settings and goes to Change Picture page right + // after the check started |HandlePageInitialized| has been completed, + // |CheckCameraPresence| will be called twice, should be throttled. + CheckCameraPresence(); + SendSelectedImage(); + UpdateProfileImage(); +} + +void ChangePictureOptionsHandler::SendSelectedImage() { + const User& user = UserManager::Get()->logged_in_user(); + DCHECK(!user.email().empty()); + + previous_image_index_ = user.image_index(); + switch (previous_image_index_) { + case User::kExternalImageIndex: { + // User has image from camera/file, record it and add to the image list. + previous_image_ = user.image(); + previous_image_data_url_ = web_ui_util::GetImageDataUrl(previous_image_); + web_ui_->CallJavascriptFunction("ChangePictureOptions.setOldImage"); + break; + } + case User::kProfileImageIndex: { + // User has his/her Profile image as the current image. + SendProfileImage(user.image(), true); + break; + } + default: { + DCHECK(previous_image_index_ >= 0 && + previous_image_index_ < kDefaultImagesCount); + // User has image from the set of default images. + base::StringValue image_url(GetDefaultImageUrl(previous_image_index_)); + web_ui_->CallJavascriptFunction("ChangePictureOptions.setSelectedImage", + image_url); + } + } +} + +void ChangePictureOptionsHandler::SendProfileImage(const SkBitmap& image, + bool should_select) { + base::StringValue data_url(web_ui_util::GetImageDataUrl(image)); + base::FundamentalValue select(should_select); + web_ui_->CallJavascriptFunction("ChangePictureOptions.setProfileImage", + data_url, select); +} + +void ChangePictureOptionsHandler::UpdateProfileImage() { + UserManager* user_manager = UserManager::Get(); + + // If we have a downloaded profile image and haven't sent it in + // |SendSelectedImage|, send it now (without selecting). + if (previous_image_index_ != User::kProfileImageIndex && + !user_manager->downloaded_profile_image().empty()) + SendProfileImage(user_manager->downloaded_profile_image(), false); + + user_manager->DownloadProfileImage(); +} + +void ChangePictureOptionsHandler::HandleSelectImage(const ListValue* args) { + std::string image_url; + if (!args || + args->GetSize() != 1 || + !args->GetString(0, &image_url)) { + NOTREACHED(); + return; + } + DCHECK(!image_url.empty()); + + UserManager* user_manager = UserManager::Get(); + const User& user = user_manager->logged_in_user(); + int image_index = User::kInvalidImageIndex; + + if (StartsWithASCII(image_url, chrome::kChromeUIUserImageURL, false)) { + // Image from file/camera uses kChromeUIUserImageURL as URL while + // current profile image always has a full data URL. + // This way transition from (current profile image) to + // (profile image, current image from file) is easier. + + DCHECK(!previous_image_.empty()); + user_manager->SaveUserImage(user.email(), previous_image_); + + UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice", + kHistogramImageOld, + kHistogramImagesCount); + VLOG(1) << "Selected old user image"; + } else if (IsDefaultImageUrl(image_url, &image_index)) { + // One of the default user images. + user_manager->SaveUserDefaultImageIndex(user.email(), image_index); + + UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice", + image_index, + kHistogramImagesCount); + VLOG(1) << "Selected default user image: " << image_index; + } else { + // Profile image selected. Could be previous (old) user image. + user_manager->SaveUserImageFromProfileImage(user.email()); + + if (previous_image_index_ == User::kProfileImageIndex) { + UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice", + kHistogramImageOld, + kHistogramImagesCount); + VLOG(1) << "Selected old (profile) user image"; + } else { + UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice", + kHistogramImageFromProfile, + kHistogramImagesCount); + VLOG(1) << "Selected profile image"; + } + } +} + +void ChangePictureOptionsHandler::FileSelected(const FilePath& path, + int index, + void* params) { + UserManager* user_manager = UserManager::Get(); + user_manager->SaveUserImageFromFile(user_manager->logged_in_user().email(), + path); + UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice", + kHistogramImageFromFile, + kHistogramImagesCount); +} + +void ChangePictureOptionsHandler::OnPhotoAccepted(const SkBitmap& photo) { + UserManager* user_manager = UserManager::Get(); + user_manager->SaveUserImage(user_manager->logged_in_user().email(), photo); + UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice", + kHistogramImageFromCamera, + kHistogramImagesCount); +} + +void ChangePictureOptionsHandler::CheckCameraPresence() { + CameraDetector::StartPresenceCheck( + base::Bind(&ChangePictureOptionsHandler::OnCameraPresenceCheckDone, + weak_factory_.GetWeakPtr())); +} + +void ChangePictureOptionsHandler::SetCameraPresent(bool present) { + base::FundamentalValue present_value(present); + web_ui_->CallJavascriptFunction("ChangePictureOptions.setCameraPresent", + present_value); +} + +void ChangePictureOptionsHandler::OnCameraPresenceCheckDone() { + SetCameraPresent(CameraDetector::camera_presence() == + CameraDetector::kCameraPresent); +} + +void ChangePictureOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + OptionsPageUIHandler::Observe(type, source, details); + if (type == chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED) { + // User profile image has been updated. + SendProfileImage(*content::Details<const SkBitmap>(details).ptr(), false); + } +} + +gfx::NativeWindow ChangePictureOptionsHandler::GetBrowserWindow() const { + Browser* browser = + BrowserList::FindBrowserWithProfile(Profile::FromWebUI(web_ui_)); + if (!browser) + return NULL; + return browser->window()->GetNativeHandle(); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.h new file mode 100644 index 0000000..c71ce01 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.h @@ -0,0 +1,113 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CHANGE_PICTURE_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CHANGE_PICTURE_OPTIONS_HANDLER_H_ + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/options2/take_photo_dialog.h" +#include "chrome/browser/ui/select_file_dialog.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "content/public/browser/notification_registrar.h" +#include "ui/gfx/native_widget_types.h" + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace chromeos { + +// ChromeOS user image options page UI handler. +class ChangePictureOptionsHandler : public OptionsPage2UIHandler, + public SelectFileDialog::Listener, + public TakePhotoDialog::Delegate { + public: + ChangePictureOptionsHandler(); + virtual ~ChangePictureOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + private: + // Sends list of available default images to the page. + void SendDefaultImages(); + + // Sends current selection to the page. + void SendSelectedImage(); + + // Sends the profile image to the page. If |should_select| is true then + // the profile image element is selected. + void SendProfileImage(const SkBitmap& image, bool should_select); + + // Starts profile image update and shows the last downloaded profile image, + // if any, on the page. Shouldn't be called before |SendProfileImage|. + void UpdateProfileImage(); + + // Starts camera presence check. + void CheckCameraPresence(); + + // Updates UI with camera presence state. + void SetCameraPresent(bool present); + + // Opens a file selection dialog to choose user image from file. + void HandleChooseFile(const base::ListValue* args); + + // Opens the camera capture dialog. + void HandleTakePhoto(const base::ListValue* args); + + // Gets the list of available user images and sends it to the page. + void HandleGetAvailableImages(const base::ListValue* args); + + // Handles page initialized event. + void HandlePageInitialized(const base::ListValue* args); + + // Handles page shown event. + void HandlePageShown(const base::ListValue* args); + + // Selects one of the available images as user's. + void HandleSelectImage(const base::ListValue* args); + + // SelectFileDialog::Delegate implementation. + virtual void FileSelected( + const FilePath& path, + int index, void* params) OVERRIDE; + + // TakePhotoDialog::Delegate implementation. + virtual void OnPhotoAccepted(const SkBitmap& photo) OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Called when the camera presence check has been completed. + void OnCameraPresenceCheckDone(); + + // Returns handle to browser window or NULL if it can't be found. + gfx::NativeWindow GetBrowserWindow() const; + + scoped_refptr<SelectFileDialog> select_file_dialog_; + + // Previous user image from camera/file and its data URL. + SkBitmap previous_image_; + std::string previous_image_data_url_; + + // Index of the previous user image. + int previous_image_index_; + + content::NotificationRegistrar registrar_; + + base::WeakPtrFactory<ChangePictureOptionsHandler> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ChangePictureOptionsHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CHANGE_PICTURE_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.cc new file mode 100644 index 0000000..7018e02 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.cc @@ -0,0 +1,268 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.h" + +#include <string> + +#include "base/bind.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/cros_settings.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/proxy_config_service_impl.h" +#include "chrome/browser/chromeos/proxy_cros_settings_parser.h" +#include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/prefs/pref_set_observer.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" + +namespace chromeos { + +namespace { + +// Create a settings value with "managed" and "disabled" property. +// "managed" property is true if the setting is managed by administrator. +// "disabled" property is true if the UI for the setting should be disabled. +base::Value* CreateSettingsValue(base::Value *value, + bool managed, + bool disabled) { + DictionaryValue* dict = new DictionaryValue; + dict->Set("value", value); + dict->Set("managed", base::Value::CreateBooleanValue(managed)); + dict->Set("disabled", base::Value::CreateBooleanValue(disabled)); + return dict; +} + +// Returns true if |username| is the logged-in owner. +bool IsLoggedInOwner(const std::string& username) { + UserManager* user_manager = UserManager::Get(); + return user_manager->current_user_is_owner() && + user_manager->logged_in_user().email() == username; +} + +// Creates a user info dictionary to be stored in the |ListValue| that is +// passed to Javascript for the |kAccountsPrefUsers| preference. +base::DictionaryValue* CreateUserInfo(const std::string& username, + const std::string& display_email, + const std::string& display_name) { + base::DictionaryValue* user_dict = new DictionaryValue; + user_dict->SetString("username", username); + user_dict->SetString("name", display_email); + user_dict->SetString("email", display_name); + user_dict->SetBoolean("owner", IsLoggedInOwner(username)); + return user_dict; +} + +// This function decorates the bare list of emails with some more information +// needed by the UI to properly display the Accounts page. +base::Value* CreateUsersWhitelist(const base::Value *pref_value) { + const base::ListValue* list_value = + static_cast<const base::ListValue*>(pref_value); + base::ListValue* user_list = new base::ListValue(); + UserManager* user_manager = UserManager::Get(); + + for (base::ListValue::const_iterator i = list_value->begin(); + i != list_value->end(); ++i) { + std::string email; + if ((*i)->GetAsString(&email)) { + // Translate email to the display email. + std::string display_email = user_manager->GetUserDisplayEmail(email); + // TODO(ivankr): fetch display name for existing users. + user_list->Append(CreateUserInfo(email, display_email, std::string())); + } + } + return user_list; +} + +} // namespace + +CoreChromeOSOptionsHandler::CoreChromeOSOptionsHandler() + : handling_change_(false), + pointer_factory_(this) { +} + +CoreChromeOSOptionsHandler::~CoreChromeOSOptionsHandler() { + PrefProxyConfigTracker* proxy_tracker = + Profile::FromWebUI(web_ui_)->GetProxyConfigTracker(); + proxy_tracker->RemoveNotificationCallback( + base::Bind(&CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged, + pointer_factory_.GetWeakPtr())); +} + +void CoreChromeOSOptionsHandler::Initialize() { + proxy_prefs_.reset(PrefSetObserver::CreateProxyPrefSetObserver( + Profile::FromWebUI(web_ui_)->GetPrefs(), this)); + // Observe the chromeos::ProxyConfigServiceImpl for changes from the UI. + PrefProxyConfigTracker* proxy_tracker = + Profile::FromWebUI(web_ui_)->GetProxyConfigTracker(); + proxy_tracker->AddNotificationCallback( + base::Bind(&CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged, + pointer_factory_.GetWeakPtr())); +} + +base::Value* CoreChromeOSOptionsHandler::FetchPref( + const std::string& pref_name) { + if (proxy_cros_settings_parser::IsProxyPref(pref_name)) { + base::Value *value = NULL; + proxy_cros_settings_parser::GetProxyPrefValue(Profile::FromWebUI(web_ui_), + pref_name, &value); + if (!value) + return base::Value::CreateNullValue(); + + return value; + } + if (!CrosSettings::IsCrosSettings(pref_name)) { + // Specially handle kUseSharedProxies because kProxy controls it to + // determine if it's managed by policy/extension. + if (pref_name == prefs::kUseSharedProxies) { + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + const PrefService::Preference* pref = + pref_service->FindPreference(prefs::kUseSharedProxies); + if (!pref) + return base::Value::CreateNullValue(); + const PrefService::Preference* controlling_pref = + pref_service->FindPreference(prefs::kProxy); + return CreateValueForPref(pref, controlling_pref); + } + return ::CoreOptionsHandler::FetchPref(pref_name); + } + + const base::Value* pref_value = CrosSettings::Get()->GetPref(pref_name); + if (!pref_value) + return base::Value::CreateNullValue(); + + // Lists don't get the standard pref decoration. + if (pref_value->GetType() == base::Value::TYPE_LIST) { + if (pref_name == kAccountsPrefUsers) + return CreateUsersWhitelist(pref_value); + // Return a copy because the UI will take ownership of this object. + return pref_value->DeepCopy(); + } + // All other prefs are decorated the same way. + return CreateSettingsValue( + pref_value->DeepCopy(), // The copy will be owned by the dictionary. + g_browser_process->browser_policy_connector()->IsEnterpriseManaged(), + !UserManager::Get()->current_user_is_owner()); +} + +void CoreChromeOSOptionsHandler::ObservePref(const std::string& pref_name) { + if (proxy_cros_settings_parser::IsProxyPref(pref_name)) { + // We observe those all the time. + return; + } + if (!CrosSettings::IsCrosSettings(pref_name)) + return ::CoreOptionsHandler::ObservePref(pref_name); + CrosSettings::Get()->AddSettingsObserver(pref_name.c_str(), this); +} + +void CoreChromeOSOptionsHandler::SetPref(const std::string& pref_name, + const base::Value* value, + const std::string& metric) { + if (proxy_cros_settings_parser::IsProxyPref(pref_name)) { + proxy_cros_settings_parser::SetProxyPrefValue(Profile::FromWebUI(web_ui_), + pref_name, value); + ProcessUserMetric(value, metric); + return; + } + if (!CrosSettings::IsCrosSettings(pref_name)) + return ::CoreOptionsHandler::SetPref(pref_name, value, metric); + handling_change_ = true; + CrosSettings::Get()->Set(pref_name, *value); + handling_change_ = false; + + ProcessUserMetric(value, metric); +} + +void CoreChromeOSOptionsHandler::StopObservingPref(const std::string& path) { + if (proxy_cros_settings_parser::IsProxyPref(path)) + return; // We unregister those in the destructor. + // Unregister this instance from observing prefs of chrome os settings. + if (CrosSettings::IsCrosSettings(path)) + CrosSettings::Get()->RemoveSettingsObserver(path.c_str(), this); + else // Call base class to handle regular preferences. + ::CoreOptionsHandler::StopObservingPref(path); +} + +void CoreChromeOSOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + // Ignore the notification if this instance had caused it. + if (handling_change_) + return; + if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED) { + NotifySettingsChanged(content::Details<std::string>(details).ptr()); + return; + } + // Special handling for preferences kUseSharedProxies and kProxy, the latter + // controls the former and decides if it's managed by policy/extension. + if (type == chrome::NOTIFICATION_PREF_CHANGED) { + const PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + std::string* pref_name = content::Details<std::string>(details).ptr(); + if (content::Source<PrefService>(source).ptr() == pref_service && + (proxy_prefs_->IsObserved(*pref_name) || + *pref_name == prefs::kUseSharedProxies)) { + NotifyPrefChanged(prefs::kUseSharedProxies, prefs::kProxy); + return; + } + } + ::CoreOptionsHandler::Observe(type, source, details); +} + +void CoreChromeOSOptionsHandler::NotifySettingsChanged( + const std::string* setting_name) { + DCHECK(web_ui_); + DCHECK(CrosSettings::Get()->IsCrosSettings(*setting_name)); + const base::Value* value = FetchPref(*setting_name); + if (!value) { + NOTREACHED(); + return; + } + std::pair<PreferenceCallbackMap::const_iterator, + PreferenceCallbackMap::const_iterator> range = + pref_callback_map_.equal_range(*setting_name); + for (PreferenceCallbackMap::const_iterator iter = range.first; + iter != range.second; ++iter) { + const std::wstring& callback_function = iter->second; + ListValue result_value; + result_value.Append(base::Value::CreateStringValue(setting_name->c_str())); + result_value.Append(value->DeepCopy()); + web_ui_->CallJavascriptFunction(WideToASCII(callback_function), + result_value); + } + if (value) + delete value; +} + +void CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged() { + DCHECK(web_ui_); + for (size_t i = 0; i < kProxySettingsCount; ++i) { + base::Value* value = NULL; + proxy_cros_settings_parser::GetProxyPrefValue( + Profile::FromWebUI(web_ui_), kProxySettings[i], &value); + DCHECK(value); + PreferenceCallbackMap::const_iterator iter = + pref_callback_map_.find(kProxySettings[i]); + for (; iter != pref_callback_map_.end(); ++iter) { + const std::wstring& callback_function = iter->second; + ListValue result_value; + result_value.Append(base::Value::CreateStringValue(kProxySettings[i])); + result_value.Append(value->DeepCopy()); + web_ui_->CallJavascriptFunction(WideToASCII(callback_function), + result_value); + } + if (value) + delete value; + } +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.h new file mode 100644 index 0000000..48aa029 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CORE_CHROMEOS_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CORE_CHROMEOS_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/webui/options2/core_options_handler.h" + +class PrefSetObserver; + +namespace chromeos { + +// CoreChromeOSOptionsHandler handles ChromeOS settings. +class CoreChromeOSOptionsHandler : public CoreOptionsHandler { + public: + CoreChromeOSOptionsHandler(); + virtual ~CoreChromeOSOptionsHandler(); + + protected: + // ::CoreOptionsHandler overrides + virtual void Initialize() OVERRIDE; + virtual base::Value* FetchPref(const std::string& pref_name) OVERRIDE; + virtual void ObservePref(const std::string& pref_name) OVERRIDE; + virtual void SetPref(const std::string& pref_name, + const base::Value* value, + const std::string& metric) OVERRIDE; + virtual void StopObservingPref(const std::string& path) OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + // Notifies registered JS callbacks on ChromeOS setting change. + void NotifySettingsChanged(const std::string* setting_name); + void NotifyProxyPrefsChanged(); + + // Keeps the track of change caused by the handler to make sure + // it does not signal itself again. + bool handling_change_; + + scoped_ptr<PrefSetObserver> proxy_prefs_; + base::WeakPtrFactory<CoreChromeOSOptionsHandler> pointer_factory_; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CORE_CHROMEOS_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.cc new file mode 100644 index 0000000..ff772d3 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.cc @@ -0,0 +1,242 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h" + +#include <map> +#include <set> +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/input_method/input_method_manager.h" +#include "chrome/browser/chromeos/input_method/input_method_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/user_metrics.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chromeos { + +CrosLanguageOptionsHandler::CrosLanguageOptionsHandler() { +} + +CrosLanguageOptionsHandler::~CrosLanguageOptionsHandler() { +} + +void CrosLanguageOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + LanguageOptionsHandlerCommon::GetLocalizedValues(localized_strings); + + RegisterTitle(localized_strings, "languagePage", + IDS_OPTIONS_SETTINGS_LANGUAGES_AND_INPUT_DIALOG_TITLE); + localized_strings->SetString("ok_button", l10n_util::GetStringUTF16(IDS_OK)); + localized_strings->SetString("configure", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE)); + localized_strings->SetString("input_method", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD)); + localized_strings->SetString("please_add_another_input_method", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD)); + localized_strings->SetString("input_method_instructions", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS)); + localized_strings->SetString("switch_input_methods_hint", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT)); + localized_strings->SetString("select_previous_input_method_hint", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT)); + localized_strings->SetString("restart_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_SIGN_OUT_BUTTON)); + localized_strings->SetString("virtual_keyboard_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_VIRTUAL_KEYBOARD_BUTTON)); + + input_method::InputMethodManager* manager = + input_method::InputMethodManager::GetInstance(); + // GetSupportedInputMethods() never return NULL. + scoped_ptr<input_method::InputMethodDescriptors> descriptors( + manager->GetSupportedInputMethods()); + localized_strings->Set("languageList", GetLanguageList(*descriptors)); + localized_strings->Set("inputMethodList", GetInputMethodList(*descriptors)); +} + +void CrosLanguageOptionsHandler::RegisterMessages() { + LanguageOptionsHandlerCommon::RegisterMessages(); + + web_ui_->RegisterMessageCallback("inputMethodDisable", + base::Bind(&CrosLanguageOptionsHandler::InputMethodDisableCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("inputMethodEnable", + base::Bind(&CrosLanguageOptionsHandler::InputMethodEnableCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("inputMethodOptionsOpen", + base::Bind(&CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("uiLanguageRestart", + base::Bind(&CrosLanguageOptionsHandler::RestartCallback, + base::Unretained(this))); +} + +ListValue* CrosLanguageOptionsHandler::GetInputMethodList( + const input_method::InputMethodDescriptors& descriptors) { + input_method::InputMethodManager* manager = + input_method::InputMethodManager::GetInstance(); + + ListValue* input_method_list = new ListValue(); + + for (size_t i = 0; i < descriptors.size(); ++i) { + const input_method::InputMethodDescriptor& descriptor = + descriptors[i]; + const std::string language_code = + manager->GetInputMethodUtil()->GetLanguageCodeFromDescriptor( + descriptor); + const std::string display_name = + manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId( + descriptor.id()); + + DictionaryValue* dictionary = new DictionaryValue(); + dictionary->SetString("id", descriptor.id()); + dictionary->SetString("displayName", display_name); + + // One input method can be associated with multiple languages, hence + // we use a dictionary here. + DictionaryValue* language_codes = new DictionaryValue(); + language_codes->SetBoolean(language_code, true); + // Check kExtraLanguages to see if there are languages associated with + // this input method. If these are present, add these. + for (size_t j = 0; j < input_method::kExtraLanguagesLength; ++j) { + const std::string extra_input_method_id = + input_method::kExtraLanguages[j].input_method_id; + const std::string extra_language_code = + input_method::kExtraLanguages[j].language_code; + if (extra_input_method_id == descriptor.id()) { + language_codes->SetBoolean(extra_language_code, true); + } + } + dictionary->Set("languageCodeSet", language_codes); + + input_method_list->Append(dictionary); + } + + return input_method_list; +} + +ListValue* CrosLanguageOptionsHandler::GetLanguageList( + const input_method::InputMethodDescriptors& descriptors) { + input_method::InputMethodManager* manager = + input_method::InputMethodManager::GetInstance(); + + std::set<std::string> language_codes; + // Collect the language codes from the supported input methods. + for (size_t i = 0; i < descriptors.size(); ++i) { + const input_method::InputMethodDescriptor& descriptor = descriptors[i]; + const std::string language_code = + manager->GetInputMethodUtil()->GetLanguageCodeFromDescriptor( + descriptor); + language_codes.insert(language_code); + } + // Collect the language codes from kExtraLanguages. + for (size_t i = 0; i < input_method::kExtraLanguagesLength; ++i) { + const char* language_code = + input_method::kExtraLanguages[i].language_code; + language_codes.insert(language_code); + } + + // Map of display name -> {language code, native_display_name}. + // In theory, we should be able to create a map that is sorted by + // display names using ICU comparator, but doing it is hard, thus we'll + // use an auxiliary vector to achieve the same result. + typedef std::pair<std::string, string16> LanguagePair; + typedef std::map<string16, LanguagePair> LanguageMap; + LanguageMap language_map; + // The auxiliary vector mentioned above. + std::vector<string16> display_names; + + // Build the list of display names, and build the language map. + for (std::set<std::string>::const_iterator iter = language_codes.begin(); + iter != language_codes.end(); ++iter) { + const string16 display_name = + input_method::InputMethodUtil::GetLanguageDisplayNameFromCode(*iter); + const string16 native_display_name = + input_method::InputMethodUtil::GetLanguageNativeDisplayNameFromCode( + *iter); + display_names.push_back(display_name); + language_map[display_name] = + std::make_pair(*iter, native_display_name); + } + DCHECK_EQ(display_names.size(), language_map.size()); + + // Sort display names using locale specific sorter. + l10n_util::SortStrings16(g_browser_process->GetApplicationLocale(), + &display_names); + + // Build the language list from the language map. + ListValue* language_list = new ListValue(); + for (size_t i = 0; i < display_names.size(); ++i) { + const LanguagePair& pair = language_map[display_names[i]]; + DictionaryValue* dictionary = new DictionaryValue(); + dictionary->SetString("code", pair.first); + dictionary->SetString("displayName", display_names[i]); + dictionary->SetString("nativeDisplayName", pair.second); + language_list->Append(dictionary); + } + + return language_list; +} + +string16 CrosLanguageOptionsHandler::GetProductName() { + return l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME); +} + +void CrosLanguageOptionsHandler::SetApplicationLocale( + const std::string& language_code) { + Profile::FromWebUI(web_ui_)->ChangeAppLocale( + language_code, Profile::APP_LOCALE_CHANGED_VIA_SETTINGS); +} + +void CrosLanguageOptionsHandler::RestartCallback(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("LanguageOptions_SignOut")); + + Browser* browser = Browser::GetBrowserForController( + &web_ui_->tab_contents()->controller(), NULL); + if (browser) + browser->ExecuteCommand(IDC_EXIT); +} + +void CrosLanguageOptionsHandler::InputMethodDisableCallback( + const ListValue* args) { + const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args)); + const std::string action = base::StringPrintf( + "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str()); + UserMetrics::RecordComputedAction(action); +} + +void CrosLanguageOptionsHandler::InputMethodEnableCallback( + const ListValue* args) { + const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args)); + const std::string action = base::StringPrintf( + "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str()); + UserMetrics::RecordComputedAction(action); +} + +void CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback( + const ListValue* args) { + const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args)); + const std::string action = base::StringPrintf( + "InputMethodOptions_Open_%s", input_method_id.c_str()); + UserMetrics::RecordComputedAction(action); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h new file mode 100644 index 0000000..aa0464b --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h @@ -0,0 +1,73 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CROS_LANGUAGE_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CROS_LANGUAGE_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/chromeos/input_method/ibus_controller.h" +#include "chrome/browser/ui/webui/options2/language_options_handler.h" + +namespace chromeos { + +// Language options page UI handler for Chrome OS. For non-Chrome OS, +// see LanguageOptionsHnadler. +class CrosLanguageOptionsHandler : public LanguageOptionsHandlerCommon { + public: + CrosLanguageOptionsHandler(); + virtual ~CrosLanguageOptionsHandler(); + + // OptionsPageUIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // DOMMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // The following static methods are public for ease of testing. + + // Gets the list of input methods from the given input descriptors. + // The return value will look like: + // [{'id': 'pinyin', 'displayName': 'Pinyin', + // 'languageCodeSet': {'zh-CW': true}}, ...] + // + // Note that true in languageCodeSet does not mean anything. We just use + // the dictionary as a set. + static base::ListValue* GetInputMethodList( + const input_method::InputMethodDescriptors& descriptors); + + // Gets the list of languages from the given input descriptors. + // The return value will look like: + // [{'code': 'fi', 'displayName': 'Finnish', 'nativeDisplayName': 'suomi'}, + // ...] + static base::ListValue* GetLanguageList( + const input_method::InputMethodDescriptors& descriptors); + + private: + // LanguageOptionsHandlerCommon implementation. + virtual string16 GetProductName() OVERRIDE; + virtual void SetApplicationLocale(const std::string& language_code) OVERRIDE; + + // Called when the sign-out button is clicked. + void RestartCallback(const base::ListValue* args); + + // Called when the input method is disabled. + // |args| will contain the input method ID as string (ex. "mozc"). + void InputMethodDisableCallback(const base::ListValue* args); + + // Called when the input method is enabled. + // |args| will contain the input method ID as string (ex. "mozc"). + void InputMethodEnableCallback(const base::ListValue* args); + + // Called when the input method options page is opened. + // |args| will contain the input method ID as string (ex. "mozc"). + void InputMethodOptionsOpenCallback(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(CrosLanguageOptionsHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_CROS_LANGUAGE_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/guest_mode_options_ui_uitest.cc b/chrome/browser/ui/webui/options2/chromeos/guest_mode_options_ui_uitest.cc new file mode 100644 index 0000000..e001d63 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/guest_mode_options_ui_uitest.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/options_ui_uitest.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/automation/automation_proxy.h" +#include "chrome/test/automation/browser_proxy.h" +#include "chrome/test/automation/tab_proxy.h" +#include "chrome/test/ui/ui_test.h" + +namespace { + +// Same as OptionsUITest but launches with Guest mode command line switches. +class GuestModeOptionsUITest : public OptionsUITest { + public: + GuestModeOptionsUITest() : OptionsUITest() { + launch_arguments_.AppendSwitch(switches::kGuestSession); + launch_arguments_.AppendSwitch(switches::kIncognito); + } +}; + +// See bug 104393. +#if defined(USE_AURA) +#define MAYBE_LoadOptionsByURL FAILS_LoadOptionsByURL +#else +#define MAYBE_LoadOptionsByURL LoadOptionsByURL +#endif + +TEST_F(GuestModeOptionsUITest, MAYBE_LoadOptionsByURL) { + scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); + ASSERT_TRUE(browser.get()); + + scoped_refptr<TabProxy> tab = browser->GetActiveTab(); + ASSERT_TRUE(tab.get()); + + NavigateToSettings(tab); + VerifyTitle(tab); + VerifyNavbar(tab); + VerifySections(tab); +} + +} // namespace diff --git a/chrome/browser/ui/webui/options2/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler.cc new file mode 100644 index 0000000..ed42aac --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler.cc @@ -0,0 +1,1372 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/internet_options_handler.h" + +#include <ctype.h> + +#include <map> +#include <string> +#include <vector> + +#include "base/base64.h" +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/i18n/time_formatting.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/stringprintf.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/choose_mobile_network_dialog.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/cros_settings.h" +#include "chrome/browser/chromeos/mobile_config.h" +#include "chrome/browser/chromeos/options2/network_config_view.h" +#include "chrome/browser/chromeos/proxy_config_service_impl.h" +#include "chrome/browser/chromeos/sim_dialog_delegate.h" +#include "chrome/browser/chromeos/status/network_menu_icon.h" +#include "chrome/browser/net/pref_proxy_config_tracker.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/dialog_style.h" +#include "chrome/browser/ui/views/window.h" +#include "chrome/browser/ui/webui/web_ui_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/time_format.h" +#include "content/public/browser/notification_service.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/widget/widget.h" + +namespace { + +static const char kOtherNetworksFakePath[] = "?"; + +// Keys for the network description dictionary passed to the web ui. Make sure +// to keep the strings in sync with what the Javascript side uses. +const char kNetworkInfoKeyActivationState[] = "activation_state"; +const char kNetworkInfoKeyConnectable[] = "connectable"; +const char kNetworkInfoKeyConnected[] = "connected"; +const char kNetworkInfoKeyConnecting[] = "connecting"; +const char kNetworkInfoKeyIconURL[] = "iconURL"; +const char kNetworkInfoKeyNeedsNewPlan[] = "needs_new_plan"; +const char kNetworkInfoKeyNetworkName[] = "networkName"; +const char kNetworkInfoKeyNetworkStatus[] = "networkStatus"; +const char kNetworkInfoKeyNetworkType[] = "networkType"; +const char kNetworkInfoKeyRemembered[] = "remembered"; +const char kNetworkInfoKeyServicePath[] = "servicePath"; +const char kNetworkInfoKeyPolicyManaged[] = "policyManaged"; + +// A helper class for building network information dictionaries to be sent to +// the webui code. +class NetworkInfoDictionary { + public: + // Initializes the dictionary with default values. + NetworkInfoDictionary(); + + // Copies in service path, connect{ing|ed|able} flags and connection type from + // the provided network object. Also chooses an appropriate icon based on the + // network type. + explicit NetworkInfoDictionary(const chromeos::Network* network); + + // Initializes a remembered network entry, pulling information from the passed + // network object and the corresponding remembered network object. |network| + // may be NULL. + NetworkInfoDictionary(const chromeos::Network* network, + const chromeos::Network* remembered); + + // Setters for filling in information. + void set_service_path(const std::string& service_path) { + service_path_ = service_path; + } + void set_icon(const SkBitmap& icon) { + icon_url_ = icon.isNull() ? "" : web_ui_util::GetImageDataUrl(icon); + } + void set_name(const std::string& name) { + name_ = name; + } + void set_connecting(bool connecting) { + connecting_ = connecting; + } + void set_connected(bool connected) { + connected_ = connected; + } + void set_connectable(bool connectable) { + connectable_ = connectable; + } + void set_connection_type(chromeos::ConnectionType connection_type) { + connection_type_ = connection_type; + } + void set_remembered(bool remembered) { + remembered_ = remembered; + } + void set_shared(bool shared) { + shared_ = shared; + } + void set_activation_state(chromeos::ActivationState activation_state) { + activation_state_ = activation_state; + } + void set_needs_new_plan(bool needs_new_plan) { + needs_new_plan_ = needs_new_plan; + } + void set_policy_managed(bool policy_managed) { + policy_managed_ = policy_managed; + } + + // Builds the DictionaryValue representation from the previously set + // parameters. Ownership of the returned pointer is transferred to the caller. + DictionaryValue* BuildDictionary(); + + private: + // Values to be filled into the dictionary. + std::string service_path_; + std::string icon_url_; + std::string name_; + bool connecting_; + bool connected_; + bool connectable_; + chromeos::ConnectionType connection_type_; + bool remembered_; + bool shared_; + chromeos::ActivationState activation_state_; + bool needs_new_plan_; + bool policy_managed_; + + DISALLOW_COPY_AND_ASSIGN(NetworkInfoDictionary); +}; + +NetworkInfoDictionary::NetworkInfoDictionary() { + set_connecting(false); + set_connected(false); + set_connectable(false); + set_remembered(false); + set_shared(false); + set_activation_state(chromeos::ACTIVATION_STATE_UNKNOWN); + set_needs_new_plan(false); + set_policy_managed(false); +} + +NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network) { + set_service_path(network->service_path()); + set_icon(chromeos::NetworkMenuIcon::GetBitmap(network)); + set_name(network->name()); + set_connecting(network->connecting()); + set_connected(network->connected()); + set_connectable(network->connectable()); + set_connection_type(network->type()); + set_remembered(false); + set_shared(false); + set_needs_new_plan(false); + set_policy_managed(chromeos::NetworkUIData::IsManaged(network)); +} + +NetworkInfoDictionary::NetworkInfoDictionary( + const chromeos::Network* network, + const chromeos::Network* remembered) { + set_service_path(remembered->service_path()); + set_icon( + chromeos::NetworkMenuIcon::GetBitmap(network ? network : remembered)); + set_name(remembered->name()); + set_connecting(network ? network->connecting() : false); + set_connected(network ? network->connected() : false); + set_connectable(true); + set_connection_type(remembered->type()); + set_remembered(true); + set_shared(remembered->profile_type() == chromeos::PROFILE_SHARED); + set_needs_new_plan(false); + set_policy_managed( + network ? chromeos::NetworkUIData::IsManaged(network) : false); +} + +DictionaryValue* NetworkInfoDictionary::BuildDictionary() { + std::string status; + + if (remembered_) { + if (shared_) + status = l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SHARED_NETWORK); + } else { + // 802.1X networks can be connected but not have saved credentials, and + // hence be "not configured". Give preference to the "connected" and + // "connecting" states. http://crosbug.com/14459 + int connection_state = IDS_STATUSBAR_NETWORK_DEVICE_DISCONNECTED; + if (connected_) + connection_state = IDS_STATUSBAR_NETWORK_DEVICE_CONNECTED; + else if (connecting_) + connection_state = IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING; + else if (!connectable_) + connection_state = IDS_STATUSBAR_NETWORK_DEVICE_NOT_CONFIGURED; + status = l10n_util::GetStringUTF8(connection_state); + if (connection_type_ == chromeos::TYPE_CELLULAR) { + if (needs_new_plan_) { + status = l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_NO_PLAN_LABEL); + } else if (activation_state_ != chromeos::ACTIVATION_STATE_ACTIVATED) { + status.append(" / "); + status.append(chromeos::CellularNetwork::ActivationStateToString( + activation_state_)); + } + } + } + + scoped_ptr<DictionaryValue> network_info(new DictionaryValue()); + network_info->SetInteger(kNetworkInfoKeyActivationState, + static_cast<int>(activation_state_)); + network_info->SetBoolean(kNetworkInfoKeyConnectable, connectable_); + network_info->SetBoolean(kNetworkInfoKeyConnected, connected_); + network_info->SetBoolean(kNetworkInfoKeyConnecting, connecting_); + network_info->SetString(kNetworkInfoKeyIconURL, icon_url_); + network_info->SetBoolean(kNetworkInfoKeyNeedsNewPlan, needs_new_plan_); + network_info->SetString(kNetworkInfoKeyNetworkName, name_); + network_info->SetString(kNetworkInfoKeyNetworkStatus, status); + network_info->SetInteger(kNetworkInfoKeyNetworkType, + static_cast<int>(connection_type_)); + network_info->SetBoolean(kNetworkInfoKeyRemembered, remembered_); + network_info->SetString(kNetworkInfoKeyServicePath, service_path_); + network_info->SetBoolean(kNetworkInfoKeyPolicyManaged, policy_managed_); + + return network_info.release(); +} + +} // namespace + +InternetOptionsHandler::InternetOptionsHandler() { + registrar_.Add(this, chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED, + content::NotificationService::AllSources()); + registrar_.Add(this, chrome::NOTIFICATION_ENTER_PIN_ENDED, + content::NotificationService::AllSources()); + cros_ = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); + if (cros_) { + cros_->AddNetworkManagerObserver(this); + cros_->AddCellularDataPlanObserver(this); + MonitorNetworks(); + } +} + +InternetOptionsHandler::~InternetOptionsHandler() { + if (cros_) { + cros_->RemoveNetworkManagerObserver(this); + cros_->RemoveCellularDataPlanObserver(this); + cros_->RemoveObserverForAllNetworks(this); + } +} + +void InternetOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "internetPage", + IDS_OPTIONS_INTERNET_TAB_LABEL); + + localized_strings->SetString("wired_title", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SECTION_TITLE_WIRED_NETWORK)); + localized_strings->SetString("wireless_title", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SECTION_TITLE_WIRELESS_NETWORK)); + localized_strings->SetString("vpn_title", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SECTION_TITLE_VIRTUAL_NETWORK)); + localized_strings->SetString("remembered_title", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SECTION_TITLE_REMEMBERED_NETWORK)); + + localized_strings->SetString("connect_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_CONNECT)); + localized_strings->SetString("disconnect_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_DISCONNECT)); + localized_strings->SetString("options_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_OPTIONS)); + localized_strings->SetString("forget_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_FORGET)); + localized_strings->SetString("activate_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_ACTIVATE)); + localized_strings->SetString("buyplan_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_BUY_PLAN)); + + localized_strings->SetString("changeProxyButton", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CHANGE_PROXY_BUTTON)); + + localized_strings->SetString("managedNetwork", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_MANAGED_NETWORK)); + + localized_strings->SetString("wifiNetworkTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_WIFI)); + localized_strings->SetString("vpnTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_VPN)); + localized_strings->SetString("cellularPlanTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_PLAN)); + localized_strings->SetString("cellularConnTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_CONNECTION)); + localized_strings->SetString("cellularDeviceTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_DEVICE)); + localized_strings->SetString("networkTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_NETWORK)); + localized_strings->SetString("securityTabLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_TAB_SECURITY)); + + localized_strings->SetString("useDHCP", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USE_DHCP)); + localized_strings->SetString("useStaticIP", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USE_STATIC_IP)); + localized_strings->SetString("connectionState", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CONNECTION_STATE)); + localized_strings->SetString("inetAddress", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_ADDRESS)); + localized_strings->SetString("inetSubnetAddress", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SUBNETMASK)); + localized_strings->SetString("inetGateway", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_GATEWAY)); + localized_strings->SetString("inetDns", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DNSSERVER)); + localized_strings->SetString("hardwareAddress", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_HARDWARE_ADDRESS)); + + // Wifi Tab. + localized_strings->SetString("accessLockedMsg", + l10n_util::GetStringUTF16( + IDS_STATUSBAR_NETWORK_LOCKED)); + localized_strings->SetString("inetSsid", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)); + localized_strings->SetString("inetPassProtected", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NET_PROTECTED)); + localized_strings->SetString("inetNetworkShared", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_SHARED)); + localized_strings->SetString("inetPreferredNetwork", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PREFER_NETWORK)); + localized_strings->SetString("inetAutoConnectNetwork", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT)); + localized_strings->SetString("inetLogin", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_LOGIN)); + localized_strings->SetString("inetShowPass", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SHOWPASSWORD)); + localized_strings->SetString("inetPassPrompt", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSWORD)); + localized_strings->SetString("inetSsidPrompt", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SSID)); + localized_strings->SetString("inetStatus", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_STATUS_TITLE)); + localized_strings->SetString("inetConnect", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CONNECT_TITLE)); + + // VPN Tab. + localized_strings->SetString("inetServiceName", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)); + localized_strings->SetString("inetServerHostname", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME)); + localized_strings->SetString("inetProviderType", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)); + localized_strings->SetString("inetUsername", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)); + + // Cellular Tab. + localized_strings->SetString("serviceName", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_SERVICE_NAME)); + localized_strings->SetString("networkTechnology", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_NETWORK_TECHNOLOGY)); + localized_strings->SetString("operatorName", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_OPERATOR)); + localized_strings->SetString("operatorCode", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_OPERATOR_CODE)); + localized_strings->SetString("activationState", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ACTIVATION_STATE)); + localized_strings->SetString("roamingState", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ROAMING_STATE)); + localized_strings->SetString("restrictedPool", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_RESTRICTED_POOL)); + localized_strings->SetString("errorState", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ERROR_STATE)); + localized_strings->SetString("manufacturer", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_MANUFACTURER)); + localized_strings->SetString("modelId", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_MODEL_ID)); + localized_strings->SetString("firmwareRevision", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_FIRMWARE_REVISION)); + localized_strings->SetString("hardwareRevision", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_HARDWARE_REVISION)); + localized_strings->SetString("prlVersion", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PRL_VERSION)); + localized_strings->SetString("cellularApnLabel", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN)); + localized_strings->SetString("cellularApnOther", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_OTHER)); + localized_strings->SetString("cellularApnUsername", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_USERNAME)); + localized_strings->SetString("cellularApnPassword", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_PASSWORD)); + localized_strings->SetString("cellularApnUseDefault", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_CLEAR)); + localized_strings->SetString("cellularApnSet", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_SET)); + localized_strings->SetString("cellularApnCancel", + l10n_util::GetStringUTF16( + IDS_CANCEL)); + + localized_strings->SetString("accessSecurityTabLink", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ACCESS_SECURITY_TAB)); + localized_strings->SetString("lockSimCard", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_LOCK_SIM_CARD)); + localized_strings->SetString("changePinButton", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_BUTTON)); + + localized_strings->SetString("planName", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CELL_PLAN_NAME)); + localized_strings->SetString("planLoading", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_LOADING_PLAN)); + localized_strings->SetString("noPlansFound", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NO_PLANS_FOUND)); + localized_strings->SetString("purchaseMore", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_MORE)); + localized_strings->SetString("dataRemaining", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DATA_REMAINING)); + localized_strings->SetString("planExpires", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_EXPIRES)); + localized_strings->SetString("showPlanNotifications", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SHOW_MOBILE_NOTIFICATION)); + localized_strings->SetString("autoconnectCellular", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT)); + localized_strings->SetString("customerSupport", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CUSTOMER_SUPPORT)); + + localized_strings->SetString("enableWifi", + l10n_util::GetStringFUTF16( + IDS_STATUSBAR_NETWORK_DEVICE_ENABLE, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI))); + localized_strings->SetString("disableWifi", + l10n_util::GetStringFUTF16( + IDS_STATUSBAR_NETWORK_DEVICE_DISABLE, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI))); + localized_strings->SetString("enableCellular", + l10n_util::GetStringFUTF16( + IDS_STATUSBAR_NETWORK_DEVICE_ENABLE, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR))); + localized_strings->SetString("disableCellular", + l10n_util::GetStringFUTF16( + IDS_STATUSBAR_NETWORK_DEVICE_DISABLE, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR))); + localized_strings->SetString("useSharedProxies", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES)); + localized_strings->SetString("enableDataRoaming", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_ENABLE_DATA_ROAMING)); + localized_strings->SetString("generalNetworkingTitle", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_CONTROL_TITLE)); + localized_strings->SetString("detailsInternetDismiss", + l10n_util::GetStringUTF16(IDS_CLOSE)); + localized_strings->SetString("ownerOnly", l10n_util::GetStringUTF16( + IDS_OPTIONS_ACCOUNTS_OWNER_ONLY)); + std::string owner; + chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner); + localized_strings->SetString("ownerUserId", UTF8ToUTF16(owner)); + + FillNetworkInfo(localized_strings); +} + +void InternetOptionsHandler::Initialize() { + cros_->RequestNetworkScan(); +} + +void InternetOptionsHandler::RegisterMessages() { + // Setup handlers specific to this panel. + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("buttonClickCallback", + base::Bind(&InternetOptionsHandler::ButtonClickCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("refreshCellularPlan", + base::Bind(&InternetOptionsHandler::RefreshCellularPlanCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setPreferNetwork", + base::Bind(&InternetOptionsHandler::SetPreferNetworkCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setAutoConnect", + base::Bind(&InternetOptionsHandler::SetAutoConnectCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setIPConfig", + base::Bind(&InternetOptionsHandler::SetIPConfigCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("enableWifi", + base::Bind(&InternetOptionsHandler::EnableWifiCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("disableWifi", + base::Bind(&InternetOptionsHandler::DisableWifiCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("enableCellular", + base::Bind(&InternetOptionsHandler::EnableCellularCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("disableCellular", + base::Bind(&InternetOptionsHandler::DisableCellularCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("buyDataPlan", + base::Bind(&InternetOptionsHandler::BuyDataPlanCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("showMorePlanInfo", + base::Bind(&InternetOptionsHandler::BuyDataPlanCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setApn", + base::Bind(&InternetOptionsHandler::SetApnCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setSimCardLock", + base::Bind(&InternetOptionsHandler::SetSimCardLockCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("changePin", + base::Bind(&InternetOptionsHandler::ChangePinCallback, + base::Unretained(this))); +} + +void InternetOptionsHandler::EnableWifiCallback(const ListValue* args) { + cros_->EnableWifiNetworkDevice(true); +} + +void InternetOptionsHandler::DisableWifiCallback(const ListValue* args) { + cros_->EnableWifiNetworkDevice(false); +} + +void InternetOptionsHandler::EnableCellularCallback(const ListValue* args) { + const chromeos::NetworkDevice* cellular = cros_->FindCellularDevice(); + if (!cellular) { + LOG(ERROR) << "Didn't find cellular device, it should have been available."; + cros_->EnableCellularNetworkDevice(true); + } else if (cellular->sim_lock_state() == chromeos::SIM_UNLOCKED || + cellular->sim_lock_state() == chromeos::SIM_UNKNOWN) { + cros_->EnableCellularNetworkDevice(true); + } else { + chromeos::SimDialogDelegate::ShowDialog(GetNativeWindow(), + chromeos::SimDialogDelegate::SIM_DIALOG_UNLOCK); + } +} + +void InternetOptionsHandler::DisableCellularCallback(const ListValue* args) { + cros_->EnableCellularNetworkDevice(false); +} + +void InternetOptionsHandler::BuyDataPlanCallback(const ListValue* args) { + if (!web_ui_) + return; + Browser* browser = BrowserList::FindBrowserWithFeature( + Profile::FromWebUI(web_ui_), Browser::FEATURE_TABSTRIP); + if (browser) + browser->OpenMobilePlanTabAndActivate(); +} + +void InternetOptionsHandler::SetApnCallback(const ListValue* args) { + std::string service_path; + std::string apn; + std::string username; + std::string password; + if (args->GetSize() != 4 || + !args->GetString(0, &service_path) || + !args->GetString(1, &apn) || + !args->GetString(2, &username) || + !args->GetString(3, &password)) { + NOTREACHED(); + return; + } + + chromeos::CellularNetwork* network = + cros_->FindCellularNetworkByPath(service_path); + if (network) { + network->SetApn(chromeos::CellularApn( + apn, network->apn().network_id, username, password)); + } +} + +void InternetOptionsHandler::SetSimCardLockCallback(const ListValue* args) { + bool require_pin_new_value; + if (!args->GetBoolean(0, &require_pin_new_value)) { + NOTREACHED(); + return; + } + // 1. Bring up SIM unlock dialog, pass new RequirePin setting in URL. + // 2. Dialog will ask for current PIN in any case. + // 3. If card is locked it will first call PIN unlock operation + // 4. Then it will call Set RequirePin, passing the same PIN. + // 5. We'll get notified by REQUIRE_PIN_SETTING_CHANGE_ENDED notification. + chromeos::SimDialogDelegate::SimDialogMode mode; + if (require_pin_new_value) + mode = chromeos::SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON; + else + mode = chromeos::SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF; + chromeos::SimDialogDelegate::ShowDialog(GetNativeWindow(), mode); +} + +void InternetOptionsHandler::ChangePinCallback(const ListValue* args) { + chromeos::SimDialogDelegate::ShowDialog(GetNativeWindow(), + chromeos::SimDialogDelegate::SIM_DIALOG_CHANGE_PIN); +} + +void InternetOptionsHandler::RefreshNetworkData() { + DictionaryValue dictionary; + FillNetworkInfo(&dictionary); + web_ui_->CallJavascriptFunction( + "options.InternetOptions.refreshNetworkData", dictionary); +} + +void InternetOptionsHandler::OnNetworkManagerChanged( + chromeos::NetworkLibrary* cros) { + if (!web_ui_) + return; + MonitorNetworks(); + RefreshNetworkData(); +} + +void InternetOptionsHandler::OnNetworkChanged( + chromeos::NetworkLibrary* cros, + const chromeos::Network* network) { + if (web_ui_) + RefreshNetworkData(); +} + +// Monitor wireless networks for changes. It is only necessary +// to set up individual observers for the cellular networks +// (if any) and for the connected Wi-Fi network (if any). The +// only change we are interested in for Wi-Fi networks is signal +// strength. For non-connected Wi-Fi networks, all information is +// reported via scan results, which trigger network manager +// updates. Only the connected Wi-Fi network has changes reported +// via service property updates. +void InternetOptionsHandler::MonitorNetworks() { + cros_->RemoveObserverForAllNetworks(this); + const chromeos::WifiNetwork* wifi_network = cros_->wifi_network(); + if (wifi_network) + cros_->AddNetworkObserver(wifi_network->service_path(), this); + // Always monitor the cellular networks, if any, so that changes + // in network technology, roaming status, and signal strength + // will be shown. + const chromeos::CellularNetworkVector& cell_networks = + cros_->cellular_networks(); + for (size_t i = 0; i < cell_networks.size(); ++i) { + chromeos::CellularNetwork* cell_network = cell_networks[i]; + cros_->AddNetworkObserver(cell_network->service_path(), this); + } + const chromeos::VirtualNetwork* virtual_network = cros_->virtual_network(); + if (virtual_network) + cros_->AddNetworkObserver(virtual_network->service_path(), this); +} + +void InternetOptionsHandler::OnCellularDataPlanChanged( + chromeos::NetworkLibrary* cros) { + if (!web_ui_) + return; + const chromeos::CellularNetwork* cellular = cros_->cellular_network(); + if (!cellular) + return; + const chromeos::CellularDataPlanVector* plans = + cros_->GetDataPlans(cellular->service_path()); + DictionaryValue connection_plans; + ListValue* plan_list = new ListValue(); + if (plans) { + for (chromeos::CellularDataPlanVector::const_iterator iter = plans->begin(); + iter != plans->end(); ++iter) { + plan_list->Append(CellularDataPlanToDictionary(*iter)); + } + } + connection_plans.SetString("servicePath", cellular->service_path()); + connection_plans.SetBoolean("needsPlan", cellular->needs_new_plan()); + connection_plans.SetBoolean("activated", + cellular->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATED); + connection_plans.Set("plans", plan_list); + SetActivationButtonVisibility(cellular, &connection_plans); + web_ui_->CallJavascriptFunction( + "options.InternetOptions.updateCellularPlans", connection_plans); +} + + +void InternetOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + OptionsPageUIHandler::Observe(type, source, details); + if (type == chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED) { + base::FundamentalValue require_pin(*content::Details<bool>(details).ptr()); + web_ui_->CallJavascriptFunction( + "options.InternetOptions.updateSecurityTab", require_pin); + } else if (type == chrome::NOTIFICATION_ENTER_PIN_ENDED) { + // We make an assumption (which is valid for now) that the SIM + // unlock dialog is put up only when the user is trying to enable + // mobile data. + bool cancelled = *content::Details<bool>(details).ptr(); + if (cancelled) { + base::DictionaryValue dictionary; + FillNetworkInfo(&dictionary); + web_ui_->CallJavascriptFunction( + "options.InternetOptions.setupAttributes", dictionary); + } + // The case in which the correct PIN was entered and the SIM is + // now unlocked is handled in NetworkMenuButton. + } +} + +DictionaryValue* InternetOptionsHandler::CellularDataPlanToDictionary( + const chromeos::CellularDataPlan* plan) { + DictionaryValue* plan_dict = new DictionaryValue(); + plan_dict->SetInteger("planType", plan->plan_type); + plan_dict->SetString("name", plan->plan_name); + plan_dict->SetString("planSummary", plan->GetPlanDesciption()); + plan_dict->SetString("dataRemaining", plan->GetDataRemainingDesciption()); + plan_dict->SetString("planExpires", plan->GetPlanExpiration()); + plan_dict->SetString("warning", plan->GetRemainingWarning()); + return plan_dict; +} + +void InternetOptionsHandler::SetPreferNetworkCallback(const ListValue* args) { + std::string service_path; + std::string prefer_network_str; + + if (args->GetSize() < 2 || + !args->GetString(0, &service_path) || + !args->GetString(1, &prefer_network_str)) { + NOTREACHED(); + return; + } + + chromeos::Network* network = cros_->FindNetworkByPath(service_path); + if (!network) + return; + + bool prefer_network = prefer_network_str == "true"; + if (prefer_network != network->preferred()) + network->SetPreferred(prefer_network); +} + +void InternetOptionsHandler::SetAutoConnectCallback(const ListValue* args) { + std::string service_path; + std::string auto_connect_str; + + if (args->GetSize() < 2 || + !args->GetString(0, &service_path) || + !args->GetString(1, &auto_connect_str)) { + NOTREACHED(); + return; + } + + chromeos::Network* network = cros_->FindNetworkByPath(service_path); + if (!network) + return; + + bool auto_connect = auto_connect_str == "true"; + if (auto_connect != network->auto_connect()) + network->SetAutoConnect(auto_connect); +} + +void InternetOptionsHandler::SetIPConfigCallback(const ListValue* args) { + std::string service_path; + std::string dhcp_str; + std::string address; + std::string netmask; + std::string gateway; + std::string name_servers; + + if (args->GetSize() < 6 || + !args->GetString(0, &service_path) || + !args->GetString(1, &dhcp_str) || + !args->GetString(2, &address) || + !args->GetString(3, &netmask) || + !args->GetString(4, &gateway) || + !args->GetString(5, &name_servers)) { + NOTREACHED(); + return; + } + + chromeos::Network* network = cros_->FindNetworkByPath(service_path); + if (!network) + return; + + cros_->SetIPConfig(chromeos::NetworkIPConfig(network->device_path(), + dhcp_str == "true" ? chromeos::IPCONFIG_TYPE_DHCP : + chromeos::IPCONFIG_TYPE_IPV4, + address, netmask, gateway, name_servers)); +} + +void InternetOptionsHandler::PopulateDictionaryDetails( + const chromeos::Network* network) { + DCHECK(network); + + if (web_ui_) { + Profile::FromWebUI(web_ui_)->GetProxyConfigTracker()->UISetCurrentNetwork( + network->service_path()); + } + + DictionaryValue dictionary; + std::string hardware_address; + chromeos::NetworkIPConfigVector ipconfigs = cros_->GetIPConfigs( + network->device_path(), &hardware_address, + chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX); + if (!hardware_address.empty()) + dictionary.SetString("hardwareAddress", hardware_address); + + scoped_ptr<DictionaryValue> ipconfig_dhcp; + scoped_ptr<DictionaryValue> ipconfig_static; + for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin(); + it != ipconfigs.end(); ++it) { + const chromeos::NetworkIPConfig& ipconfig = *it; + scoped_ptr<DictionaryValue> ipconfig_dict(new DictionaryValue()); + ipconfig_dict->SetString("address", ipconfig.address); + ipconfig_dict->SetString("subnetAddress", ipconfig.netmask); + ipconfig_dict->SetString("gateway", ipconfig.gateway); + ipconfig_dict->SetString("dns", ipconfig.name_servers); + if (ipconfig.type == chromeos::IPCONFIG_TYPE_DHCP) + ipconfig_dhcp.reset(ipconfig_dict.release()); + else if (ipconfig.type == chromeos::IPCONFIG_TYPE_IPV4) + ipconfig_static.reset(ipconfig_dict.release()); + } + + chromeos::NetworkPropertyUIData ipconfig_dhcp_ui_data(network, NULL); + SetValueDictionary(&dictionary, "ipconfigDHCP", ipconfig_dhcp.release(), + ipconfig_dhcp_ui_data); + chromeos::NetworkPropertyUIData ipconfig_static_ui_data(network, NULL); + SetValueDictionary(&dictionary, "ipconfigStatic", ipconfig_static.release(), + ipconfig_static_ui_data); + + chromeos::ConnectionType type = network->type(); + dictionary.SetInteger("type", type); + dictionary.SetString("servicePath", network->service_path()); + dictionary.SetBoolean("connecting", network->connecting()); + dictionary.SetBoolean("connected", network->connected()); + dictionary.SetString("connectionState", network->GetStateString()); + + // Only show proxy for remembered networks. + chromeos::NetworkProfileType network_profile = network->profile_type(); + dictionary.SetBoolean("showProxy", network_profile != chromeos::PROFILE_NONE); + + // Hide the dhcp/static radio if not ethernet or wifi (or if not enabled) + bool staticIPConfig = CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableStaticIPConfig); + dictionary.SetBoolean("showStaticIPConfig", staticIPConfig && + (type == chromeos::TYPE_WIFI || type == chromeos::TYPE_ETHERNET)); + + chromeos::NetworkPropertyUIData preferred_ui_data( + network, chromeos::NetworkUIData::kPropertyPreferred); + if (network_profile == chromeos::PROFILE_USER) { + dictionary.SetBoolean("showPreferred", true); + SetValueDictionary(&dictionary, "preferred", + Value::CreateBooleanValue(network->preferred()), + preferred_ui_data); + } else { + dictionary.SetBoolean("showPreferred", false); + SetValueDictionary(&dictionary, "preferred", + Value::CreateBooleanValue(network->preferred()), + preferred_ui_data); + } + chromeos::NetworkPropertyUIData auto_connect_ui_data( + network, chromeos::NetworkUIData::kPropertyAutoConnect); + SetValueDictionary(&dictionary, "autoConnect", + Value::CreateBooleanValue(network->auto_connect()), + auto_connect_ui_data); + + if (type == chromeos::TYPE_WIFI) { + dictionary.SetBoolean("deviceConnected", cros_->wifi_connected()); + const chromeos::WifiNetwork* wifi = + cros_->FindWifiNetworkByPath(network->service_path()); + if (!wifi) { + LOG(WARNING) << "Cannot find network " << network->service_path(); + } else { + PopulateWifiDetails(wifi, &dictionary); + } + } else if (type == chromeos::TYPE_CELLULAR) { + dictionary.SetBoolean("deviceConnected", cros_->cellular_connected()); + const chromeos::CellularNetwork* cellular = + cros_->FindCellularNetworkByPath(network->service_path()); + if (!cellular) { + LOG(WARNING) << "Cannot find network " << network->service_path(); + } else { + PopulateCellularDetails(cellular, &dictionary); + } + } else if (type == chromeos::TYPE_VPN) { + dictionary.SetBoolean("deviceConnected", + cros_->virtual_network_connected()); + const chromeos::VirtualNetwork* vpn = + cros_->FindVirtualNetworkByPath(network->service_path()); + if (!vpn) { + LOG(WARNING) << "Cannot find network " << network->service_path(); + } else { + PopulateVPNDetails(vpn, &dictionary); + } + } else if (type == chromeos::TYPE_ETHERNET) { + dictionary.SetBoolean("deviceConnected", cros_->ethernet_connected()); + } + + web_ui_->CallJavascriptFunction( + "options.InternetOptions.showDetailedInfo", dictionary); +} + +void InternetOptionsHandler::PopulateWifiDetails( + const chromeos::WifiNetwork* wifi, + DictionaryValue* dictionary) { + dictionary->SetString("ssid", wifi->name()); + bool remembered = (wifi->profile_type() != chromeos::PROFILE_NONE); + dictionary->SetBoolean("remembered", remembered); + dictionary->SetBoolean("encrypted", wifi->encrypted()); + bool shared = wifi->profile_type() == chromeos::PROFILE_SHARED; + dictionary->SetBoolean("shared", shared); +} + +DictionaryValue* InternetOptionsHandler::CreateDictionaryFromCellularApn( + const chromeos::CellularApn& apn) { + DictionaryValue* dictionary = new DictionaryValue(); + dictionary->SetString("apn", apn.apn); + dictionary->SetString("networkId", apn.network_id); + dictionary->SetString("username", apn.username); + dictionary->SetString("password", apn.password); + dictionary->SetString("name", apn.name); + dictionary->SetString("localizedName", apn.localized_name); + dictionary->SetString("language", apn.language); + return dictionary; +} + +void InternetOptionsHandler::PopulateCellularDetails( + const chromeos::CellularNetwork* cellular, + DictionaryValue* dictionary) { + // Cellular network / connection settings. + dictionary->SetString("serviceName", cellular->name()); + dictionary->SetString("networkTechnology", + cellular->GetNetworkTechnologyString()); + dictionary->SetString("operatorName", cellular->operator_name()); + dictionary->SetString("operatorCode", cellular->operator_code()); + dictionary->SetString("activationState", + cellular->GetActivationStateString()); + dictionary->SetString("roamingState", + cellular->GetRoamingStateString()); + dictionary->SetString("restrictedPool", + cellular->restricted_pool() ? + l10n_util::GetStringUTF8( + IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL) : + l10n_util::GetStringUTF8( + IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)); + dictionary->SetString("errorState", cellular->GetErrorString()); + dictionary->SetString("supportUrl", cellular->payment_url()); + dictionary->SetBoolean("needsPlan", cellular->needs_new_plan()); + + dictionary->Set("apn", CreateDictionaryFromCellularApn(cellular->apn())); + dictionary->Set("lastGoodApn", + CreateDictionaryFromCellularApn(cellular->last_good_apn())); + + // Device settings. + const chromeos::NetworkDevice* device = + cros_->FindNetworkDeviceByPath(cellular->device_path()); + if (device) { + chromeos::NetworkPropertyUIData cellular_propety_ui_data(cellular, NULL); + dictionary->SetString("manufacturer", device->manufacturer()); + dictionary->SetString("modelId", device->model_id()); + dictionary->SetString("firmwareRevision", device->firmware_revision()); + dictionary->SetString("hardwareRevision", device->hardware_revision()); + dictionary->SetString("prlVersion", + base::StringPrintf("%u", device->prl_version())); + dictionary->SetString("meid", device->meid()); + dictionary->SetString("imei", device->imei()); + dictionary->SetString("mdn", device->mdn()); + dictionary->SetString("imsi", device->imsi()); + dictionary->SetString("esn", device->esn()); + dictionary->SetString("min", device->min()); + dictionary->SetBoolean("gsm", + device->technology_family() == chromeos::TECHNOLOGY_FAMILY_GSM); + SetValueDictionary( + dictionary, "simCardLockEnabled", + Value::CreateBooleanValue( + device->sim_pin_required() == chromeos::SIM_PIN_REQUIRED), + cellular_propety_ui_data); + + chromeos::MobileConfig* config = chromeos::MobileConfig::GetInstance(); + if (config->IsReady()) { + std::string carrier_id = cros_->GetCellularHomeCarrierId(); + const chromeos::MobileConfig::Carrier* carrier = + config->GetCarrier(carrier_id); + if (carrier && !carrier->top_up_url().empty()) + dictionary->SetString("carrierUrl", carrier->top_up_url()); + } + + const chromeos::CellularApnList& apn_list = device->provider_apn_list(); + ListValue* apn_list_value = new ListValue(); + for (chromeos::CellularApnList::const_iterator it = apn_list.begin(); + it != apn_list.end(); ++it) { + apn_list_value->Append(CreateDictionaryFromCellularApn(*it)); + } + SetValueDictionary(dictionary, "providerApnList", apn_list_value, + cellular_propety_ui_data); + } + + SetActivationButtonVisibility(cellular, dictionary); +} + +void InternetOptionsHandler::PopulateVPNDetails( + const chromeos::VirtualNetwork* vpn, + DictionaryValue* dictionary) { + dictionary->SetString("service_name", vpn->name()); + bool remembered = (vpn->profile_type() != chromeos::PROFILE_NONE); + dictionary->SetBoolean("remembered", remembered); + dictionary->SetString("server_hostname", vpn->server_hostname()); + dictionary->SetString("provider_type", vpn->GetProviderTypeString()); + dictionary->SetString("username", vpn->username()); +} + +void InternetOptionsHandler::SetActivationButtonVisibility( + const chromeos::CellularNetwork* cellular, + DictionaryValue* dictionary) { + if (cellular->needs_new_plan()) { + dictionary->SetBoolean("showBuyButton", true); + } else if (cellular->activation_state() != + chromeos::ACTIVATION_STATE_ACTIVATING && + cellular->activation_state() != + chromeos::ACTIVATION_STATE_ACTIVATED) { + dictionary->SetBoolean("showActivateButton", true); + } +} + +void InternetOptionsHandler::CreateModalPopup(views::WidgetDelegate* view) { + views::Widget* window = browser::CreateViewsWindow(GetNativeWindow(), + view, + STYLE_GENERIC); + window->SetAlwaysOnTop(true); + window->Show(); +} + +gfx::NativeWindow InternetOptionsHandler::GetNativeWindow() const { + // TODO(beng): This is an improper direct dependency on Browser. Route this + // through some sort of delegate. + Browser* browser = + BrowserList::FindBrowserWithProfile(Profile::FromWebUI(web_ui_)); + return browser->window()->GetNativeHandle(); +} + +void InternetOptionsHandler::ButtonClickCallback(const ListValue* args) { + std::string str_type; + std::string service_path; + std::string command; + if (args->GetSize() != 3 || + !args->GetString(0, &str_type) || + !args->GetString(1, &service_path) || + !args->GetString(2, &command)) { + NOTREACHED(); + return; + } + + int type = atoi(str_type.c_str()); + if (type == chromeos::TYPE_ETHERNET) { + const chromeos::EthernetNetwork* ether = cros_->ethernet_network(); + if (ether) + PopulateDictionaryDetails(ether); + } else if (type == chromeos::TYPE_WIFI) { + HandleWifiButtonClick(service_path, command); + } else if (type == chromeos::TYPE_CELLULAR) { + HandleCellularButtonClick(service_path, command); + } else if (type == chromeos::TYPE_VPN) { + HandleVPNButtonClick(service_path, command); + } else { + NOTREACHED(); + } +} + +void InternetOptionsHandler::HandleWifiButtonClick( + const std::string& service_path, + const std::string& command) { + chromeos::WifiNetwork* wifi = NULL; + if (command == "forget") { + cros_->ForgetNetwork(service_path); + } else if (service_path == kOtherNetworksFakePath) { + // Other wifi networks. + CreateModalPopup(new chromeos::NetworkConfigView(chromeos::TYPE_WIFI)); + } else if ((wifi = cros_->FindWifiNetworkByPath(service_path))) { + if (command == "connect") { + // Connect to wifi here. Open password page if appropriate. + if (wifi->IsPassphraseRequired()) { + CreateModalPopup(new chromeos::NetworkConfigView(wifi)); + } else { + cros_->ConnectToWifiNetwork(wifi); + } + } else if (command == "disconnect") { + cros_->DisconnectFromNetwork(wifi); + } else if (command == "options") { + PopulateDictionaryDetails(wifi); + } + } +} + +void InternetOptionsHandler::HandleCellularButtonClick( + const std::string& service_path, + const std::string& command) { + chromeos::CellularNetwork* cellular = NULL; + if (service_path == kOtherNetworksFakePath) { + chromeos::ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow()); + } else if ((cellular = cros_->FindCellularNetworkByPath(service_path))) { + if (command == "connect") { + cros_->ConnectToCellularNetwork(cellular); + } else if (command == "disconnect") { + cros_->DisconnectFromNetwork(cellular); + } else if (command == "activate") { + Browser* browser = BrowserList::GetLastActive(); + if (browser) + browser->OpenMobilePlanTabAndActivate(); + } else if (command == "options") { + PopulateDictionaryDetails(cellular); + } + } +} + +void InternetOptionsHandler::HandleVPNButtonClick( + const std::string& service_path, + const std::string& command) { + chromeos::VirtualNetwork* network = NULL; + if (command == "forget") { + cros_->ForgetNetwork(service_path); + } else if (service_path == kOtherNetworksFakePath) { + // TODO(altimofeev): verify if service_path in condition is correct. + // Other VPN networks. + CreateModalPopup(new chromeos::NetworkConfigView(chromeos::TYPE_VPN)); + } else if ((network = cros_->FindVirtualNetworkByPath(service_path))) { + if (command == "connect") { + // Connect to VPN here. Open password page if appropriate. + if (network->NeedMoreInfoToConnect()) { + CreateModalPopup(new chromeos::NetworkConfigView(network)); + } else { + cros_->ConnectToVirtualNetwork(network); + } + } else if (command == "disconnect") { + cros_->DisconnectFromNetwork(network); + } else if (command == "options") { + PopulateDictionaryDetails(network); + } + } +} + +void InternetOptionsHandler::RefreshCellularPlanCallback( + const ListValue* args) { + std::string service_path; + if (args->GetSize() != 1 || + !args->GetString(0, &service_path)) { + NOTREACHED(); + return; + } + const chromeos::CellularNetwork* cellular = + cros_->FindCellularNetworkByPath(service_path); + if (cellular) + cellular->RefreshDataPlansIfNeeded(); +} + +ListValue* InternetOptionsHandler::GetWiredList() { + ListValue* list = new ListValue(); + + // If ethernet is not enabled, then don't add anything. + if (cros_->ethernet_enabled()) { + const chromeos::EthernetNetwork* ethernet_network = + cros_->ethernet_network(); + if (ethernet_network) { + NetworkInfoDictionary network_dict(ethernet_network); + network_dict.set_name( + l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)), + list->Append(network_dict.BuildDictionary()); + } + } + return list; +} + +ListValue* InternetOptionsHandler::GetWirelessList() { + ListValue* list = new ListValue(); + + const chromeos::WifiNetworkVector& wifi_networks = cros_->wifi_networks(); + for (chromeos::WifiNetworkVector::const_iterator it = + wifi_networks.begin(); it != wifi_networks.end(); ++it) { + NetworkInfoDictionary network_dict(*it); + network_dict.set_connectable(cros_->CanConnectToNetwork(*it)); + list->Append(network_dict.BuildDictionary()); + } + + // Add "Other WiFi network..." if wifi is enabled. + if (cros_->wifi_enabled()) { + NetworkInfoDictionary network_dict; + network_dict.set_service_path(kOtherNetworksFakePath); + network_dict.set_icon( + chromeos::NetworkMenuIcon::GetConnectedBitmap( + chromeos::NetworkMenuIcon::ARCS)); + network_dict.set_name( + l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS)); + network_dict.set_connectable(true); + network_dict.set_connection_type(chromeos::TYPE_WIFI); + list->Append(network_dict.BuildDictionary()); + } + + const chromeos::CellularNetworkVector cellular_networks = + cros_->cellular_networks(); + for (chromeos::CellularNetworkVector::const_iterator it = + cellular_networks.begin(); it != cellular_networks.end(); ++it) { + NetworkInfoDictionary network_dict(*it); + network_dict.set_connectable(cros_->CanConnectToNetwork(*it)); + network_dict.set_activation_state((*it)->activation_state()); + network_dict.set_needs_new_plan( + (*it)->SupportsDataPlan() && (*it)->restricted_pool()); + list->Append(network_dict.BuildDictionary()); + } + + const chromeos::NetworkDevice* cellular_device = cros_->FindCellularDevice(); + if (cellular_device && cellular_device->support_network_scan() && + cros_->cellular_enabled()) { + NetworkInfoDictionary network_dict; + network_dict.set_service_path(kOtherNetworksFakePath); + network_dict.set_icon( + chromeos::NetworkMenuIcon::GetDisconnectedBitmap( + chromeos::NetworkMenuIcon::BARS)); + network_dict.set_name( + l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS)); + network_dict.set_connectable(true); + network_dict.set_connection_type(chromeos::TYPE_CELLULAR); + network_dict.set_activation_state(chromeos::ACTIVATION_STATE_ACTIVATED); + list->Append(network_dict.BuildDictionary()); + } + + return list; +} + +ListValue* InternetOptionsHandler::GetVPNList() { + ListValue* list = new ListValue(); + + const chromeos::VirtualNetworkVector& virtual_networks = + cros_->virtual_networks(); + for (chromeos::VirtualNetworkVector::const_iterator it = + virtual_networks.begin(); it != virtual_networks.end(); ++it) { + NetworkInfoDictionary network_dict(*it); + network_dict.set_connectable(cros_->CanConnectToNetwork(*it)); + list->Append(network_dict.BuildDictionary()); + } + + return list; +} + +ListValue* InternetOptionsHandler::GetRememberedList() { + ListValue* list = new ListValue(); + + for (chromeos::WifiNetworkVector::const_iterator rit = + cros_->remembered_wifi_networks().begin(); + rit != cros_->remembered_wifi_networks().end(); ++rit) { + chromeos::WifiNetwork* remembered = *rit; + chromeos::WifiNetwork* wifi = static_cast<chromeos::WifiNetwork*>( + cros_->FindNetworkByUniqueId(remembered->unique_id())); + + NetworkInfoDictionary network_dict(wifi, remembered); + list->Append(network_dict.BuildDictionary()); + } + + for (chromeos::VirtualNetworkVector::const_iterator rit = + cros_->remembered_virtual_networks().begin(); + rit != cros_->remembered_virtual_networks().end(); ++rit) { + chromeos::VirtualNetwork* remembered = *rit; + chromeos::VirtualNetwork* vpn = static_cast<chromeos::VirtualNetwork*>( + cros_->FindNetworkByUniqueId(remembered->unique_id())); + + NetworkInfoDictionary network_dict(vpn, remembered); + list->Append(network_dict.BuildDictionary()); + } + + return list; +} + +void InternetOptionsHandler::FillNetworkInfo(DictionaryValue* dictionary) { + dictionary->SetBoolean("accessLocked", cros_->IsLocked()); + dictionary->Set("wiredList", GetWiredList()); + dictionary->Set("wirelessList", GetWirelessList()); + dictionary->Set("vpnList", GetVPNList()); + dictionary->Set("rememberedList", GetRememberedList()); + dictionary->SetBoolean("wifiAvailable", cros_->wifi_available()); + dictionary->SetBoolean("wifiBusy", cros_->wifi_busy()); + dictionary->SetBoolean("wifiEnabled", cros_->wifi_enabled()); + dictionary->SetBoolean("cellularAvailable", cros_->cellular_available()); + dictionary->SetBoolean("cellularBusy", cros_->cellular_busy()); + dictionary->SetBoolean("cellularEnabled", cros_->cellular_enabled()); +} + +void InternetOptionsHandler::SetValueDictionary( + DictionaryValue* settings, + const char* key, + base::Value* value, + const chromeos::NetworkPropertyUIData& ui_data) { + DictionaryValue* value_dict = new DictionaryValue(); + // DictionaryValue::Set() takes ownership of |value|. + if (value) + value_dict->Set("value", value); + const base::Value* default_value = ui_data.default_value(); + if (default_value) + value_dict->Set("default", default_value->DeepCopy()); + if (ui_data.managed()) + value_dict->SetString("controlledBy", "policy"); + else if (ui_data.recommended()) + value_dict->SetString("controlledBy", "recommended"); + settings->Set(key, value_dict); +} diff --git a/chrome/browser/ui/webui/options2/chromeos/internet_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler.h new file mode 100644 index 0000000..c35c309 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler.h @@ -0,0 +1,148 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_INTERNET_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_INTERNET_OPTIONS_HANDLER_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/cros/network_ui_data.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "content/public/browser/notification_registrar.h" +#include "ui/gfx/native_widget_types.h" + +class SkBitmap; +namespace views { +class WidgetDelegate; +} + +// ChromeOS internet options page UI handler. +class InternetOptionsHandler + : public OptionsPage2UIHandler, + public chromeos::NetworkLibrary::NetworkManagerObserver, + public chromeos::NetworkLibrary::NetworkObserver, + public chromeos::NetworkLibrary::CellularDataPlanObserver { + public: + InternetOptionsHandler(); + virtual ~InternetOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // NetworkLibrary::NetworkManagerObserver implementation. + virtual void OnNetworkManagerChanged( + chromeos::NetworkLibrary* network_lib) OVERRIDE; + // NetworkLibrary::NetworkObserver implementation. + virtual void OnNetworkChanged(chromeos::NetworkLibrary* network_lib, + const chromeos::Network* network) OVERRIDE; + // NetworkLibrary::CellularDataPlanObserver implementation. + virtual void OnCellularDataPlanChanged( + chromeos::NetworkLibrary* network_lib) OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + // Opens a modal popup dialog. + void CreateModalPopup(views::WidgetDelegate* view); + gfx::NativeWindow GetNativeWindow() const; + + // Passes data needed to show details overlay for network. + // |args| will be [ network_type, service_path, command ] + // And command is one of 'options', 'connect', disconnect', 'activate' or + // 'forget' + // Handle{Wifi,Cellular}ButtonClick handles button click on a wireless + // network item and a cellular network item respectively. + void ButtonClickCallback(const base::ListValue* args); + void HandleWifiButtonClick(const std::string& service_path, + const std::string& command); + void HandleCellularButtonClick(const std::string& service_path, + const std::string& command); + void HandleVPNButtonClick(const std::string& service_path, + const std::string& command); + + // Initiates cellular plan data refresh. The results from libcros will be + // passed through CellularDataPlanChanged() callback method. + // |args| will be [ service_path ] + void RefreshCellularPlanCallback(const base::ListValue* args); + void SetActivationButtonVisibility( + const chromeos::CellularNetwork* cellular, + base::DictionaryValue* dictionary); + + void SetPreferNetworkCallback(const base::ListValue* args); + void SetAutoConnectCallback(const base::ListValue* args); + void SetSharedCallback(const base::ListValue* args); + void SetIPConfigCallback(const base::ListValue* args); + void EnableWifiCallback(const base::ListValue* args); + void DisableWifiCallback(const base::ListValue* args); + void EnableCellularCallback(const base::ListValue* args); + void DisableCellularCallback(const base::ListValue* args); + void BuyDataPlanCallback(const base::ListValue* args); + void SetApnCallback(const base::ListValue* args); + void SetSimCardLockCallback(const base::ListValue* args); + void ChangePinCallback(const base::ListValue* args); + void ShareNetworkCallback(const base::ListValue* args); + + // Populates the ui with the details of the given device path. This forces + // an overlay to be displayed in the UI. + void PopulateDictionaryDetails(const chromeos::Network* network); + void PopulateWifiDetails(const chromeos::WifiNetwork* wifi, + base::DictionaryValue* dictionary); + void PopulateCellularDetails(const chromeos::CellularNetwork* cellular, + base::DictionaryValue* dictionary); + void PopulateVPNDetails(const chromeos::VirtualNetwork* vpn, + base::DictionaryValue* dictionary); + + // Converts CellularDataPlan structure into dictionary for JS. Formats plan + // settings into human readable texts. + base::DictionaryValue* CellularDataPlanToDictionary( + const chromeos::CellularDataPlan* plan); + + // Converts CellularApn stuct into dictionary for JS. + base::DictionaryValue* CreateDictionaryFromCellularApn( + const chromeos::CellularApn& apn); + + // Creates the map of wired networks. + base::ListValue* GetWiredList(); + // Creates the map of wireless networks. + base::ListValue* GetWirelessList(); + // Creates the map of virtual networks. + base::ListValue* GetVPNList(); + // Creates the map of remembered networks. + base::ListValue* GetRememberedList(); + // Fills network information into JS dictionary for displaying network lists. + void FillNetworkInfo(base::DictionaryValue* dictionary); + // Refreshes the display of network information. + void RefreshNetworkData(); + // Adds observers for wireless networks, if any, so that we can dynamically + // display the correct icon for that network's signal strength and, in the + // case of cellular networks, network technology and roaming status. + void MonitorNetworks(); + + // Stores a dictionary under |key| in |settings| that is suitable to be sent + // to the webui that contains the actual value of a setting and whether it's + // controlled by policy. Takes ownership of |value|. + void SetValueDictionary(DictionaryValue* settings, + const char* key, + base::Value* value, + const chromeos::NetworkPropertyUIData& ui_data); + + // Convenience pointer to netwrok library (will not change). + chromeos::NetworkLibrary* cros_; + + content::NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(InternetOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_INTERNET_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.cc b/chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.cc new file mode 100644 index 0000000..c3c3096 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.h" + +#include <limits> + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/language_preferences.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_options_util.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { +const char kI18nPrefix[] = "Chewing_"; +} // namespace + +namespace chromeos { + +LanguageChewingHandler::LanguageChewingHandler() { +} + +LanguageChewingHandler::~LanguageChewingHandler() { +} + +void LanguageChewingHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "languageChewingPage", + IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTINGS_TITLE); + + for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) { + localized_strings->SetString( + GetI18nContentValue(language_prefs::kChewingBooleanPrefs[i], + kI18nPrefix), + l10n_util::GetStringUTF16( + language_prefs::kChewingBooleanPrefs[i].message_id)); + } + + // For maximum Chinese characters in pre-edit buffer, we use slider UI. + { + const language_prefs::LanguageIntegerRangePreference& preference = + language_prefs::kChewingIntegerPrefs[ + language_prefs::kChewingMaxChiSymbolLenIndex]; + localized_strings->SetString( + GetI18nContentValue(preference, kI18nPrefix), + l10n_util::GetStringUTF16(preference.message_id)); + localized_strings->SetString( + GetTemplateDataMinName(preference, kI18nPrefix), + base::IntToString(preference.min_pref_value)); + localized_strings->SetString( + GetTemplateDataMaxName(preference, kI18nPrefix), + base::IntToString(preference.max_pref_value)); + } + + // For number of candidates per page, we use select-option UI. + { + const language_prefs::LanguageIntegerRangePreference& preference = + language_prefs::kChewingIntegerPrefs[ + language_prefs::kChewingCandPerPageIndex]; + localized_strings->SetString( + GetI18nContentValue(preference, kI18nPrefix), + l10n_util::GetStringUTF16(preference.message_id)); + ListValue* list_value = new ListValue(); + for (int i = preference.min_pref_value; i <= preference.max_pref_value; + ++i) { + ListValue* option = new ListValue(); + option->Append(CreateValue(i)); + option->Append(CreateValue(i)); + list_value->Append(option); + } + localized_strings->Set(GetTemplateDataPropertyName(preference, kI18nPrefix), + list_value); + } + + for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; + ++i) { + const language_prefs::LanguageMultipleChoicePreference<const char*>& + preference = language_prefs::kChewingMultipleChoicePrefs[i]; + localized_strings->SetString( + GetI18nContentValue(preference, kI18nPrefix), + l10n_util::GetStringUTF16(preference.label_message_id)); + localized_strings->Set( + GetTemplateDataPropertyName(preference, kI18nPrefix), + CreateMultipleChoiceList(preference)); + } + + localized_strings->SetString( + GetI18nContentValue(language_prefs::kChewingHsuSelKeyType, kI18nPrefix), + l10n_util::GetStringUTF16( + language_prefs::kChewingHsuSelKeyType.label_message_id)); + localized_strings->Set( + GetTemplateDataPropertyName(language_prefs::kChewingHsuSelKeyType, + kI18nPrefix), + CreateMultipleChoiceList(language_prefs::kChewingHsuSelKeyType)); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.h b/chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.h new file mode 100644 index 0000000..b251fe7 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_CHEWING_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_CHEWING_HANDLER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +} + +namespace chromeos { + +// Chewing options page UI handler. +class LanguageChewingHandler : public OptionsPage2UIHandler { + public: + LanguageChewingHandler(); + virtual ~LanguageChewingHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(LanguageChewingHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_CHEWING_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.cc b/chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.cc new file mode 100644 index 0000000..d95b2ace --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.h" + +#include "base/values.h" +#include "chrome/browser/chromeos/input_method/xkeyboard.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { +const struct ModifierKeysSelectItem { + int message_id; + chromeos::input_method::ModifierKey value; +} kModifierKeysSelectItems[] = { + { IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_SEARCH, + chromeos::input_method::kSearchKey }, + { IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_LEFT_CTRL, + chromeos::input_method::kLeftControlKey }, + { IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_LEFT_ALT, + chromeos::input_method::kLeftAltKey }, + { IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_VOID, + chromeos::input_method::kVoidKey }, + { IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_CAPS_LOCK, + chromeos::input_method::kCapsLockKey }, +}; + +const char* kDataValuesNames[] = { + "xkbRemapSearchKeyToValue", + "xkbRemapControlKeyToValue", + "xkbRemapAltKeyToValue", +}; +} // namespace + +namespace chromeos { + +LanguageCustomizeModifierKeysHandler::LanguageCustomizeModifierKeysHandler() { +} + +LanguageCustomizeModifierKeysHandler::~LanguageCustomizeModifierKeysHandler() { +} + +void LanguageCustomizeModifierKeysHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + localized_strings->SetString("xkbRemapSearchKeyToContent", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_SEARCH_LABEL)); + localized_strings->SetString("xkbRemapControlKeyToContent", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_LEFT_CTRL_LABEL)); + localized_strings->SetString("xkbRemapAltKeyToContent", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_XKB_KEY_LEFT_ALT_LABEL)); + + for (size_t i = 0; i < arraysize(kDataValuesNames); ++i) { + ListValue* list_value = new ListValue(); + for (size_t j = 0; j < arraysize(kModifierKeysSelectItems); ++j) { + const input_method::ModifierKey value = + kModifierKeysSelectItems[j].value; + const int message_id = kModifierKeysSelectItems[j].message_id; + // Only the seach key can be remapped to the caps lock key. + if (kDataValuesNames[i] != std::string("xkbRemapSearchKeyToValue") && + value == input_method::kCapsLockKey) { + continue; + } + ListValue* option = new ListValue(); + option->Append(Value::CreateIntegerValue(value)); + option->Append(Value::CreateStringValue(l10n_util::GetStringUTF16( + message_id))); + list_value->Append(option); + } + localized_strings->Set(kDataValuesNames[i], list_value); + } +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.h b/chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.h new file mode 100644 index 0000000..2a1f1a5 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_CUSTOMIZE_MODIFIER_KEYS_HANDLER_H_ // NOLINT +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_CUSTOMIZE_MODIFIER_KEYS_HANDLER_H_ // NOLINT +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace chromeos { + +// Customize modifier keys overlay page UI handler. +class LanguageCustomizeModifierKeysHandler : public OptionsPage2UIHandler { + public: + LanguageCustomizeModifierKeysHandler(); + virtual ~LanguageCustomizeModifierKeysHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(LanguageCustomizeModifierKeysHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_CUSTOMIZE_MODIFIER_KEYS_HANDLER_H_ // NOLINT diff --git a/chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.cc b/chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.cc new file mode 100644 index 0000000..5362ccf --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.h" + +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/language_preferences.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chromeos { + +LanguageHangulHandler::LanguageHangulHandler() { +} + +LanguageHangulHandler::~LanguageHangulHandler() { +} + +void LanguageHangulHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "languageHangulPage", + IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_TITLE); + + localized_strings->SetString("hangul_keyboard_layout", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_KEYBOARD_LAYOUT_TEXT)); + + localized_strings->Set("HangulkeyboardLayoutList", GetKeyboardLayoutList()); +} + +ListValue* LanguageHangulHandler::GetKeyboardLayoutList() { + ListValue* keyboard_layout_list = new ListValue(); + for (size_t i = 0; i < language_prefs::kNumHangulKeyboardNameIDPairs; ++i) { + ListValue* option = new ListValue(); + option->Append(Value::CreateStringValue( + language_prefs::kHangulKeyboardNameIDPairs[i].keyboard_id)); + option->Append(Value::CreateStringValue(l10n_util::GetStringUTF16( + language_prefs::kHangulKeyboardNameIDPairs[i].message_id))); + keyboard_layout_list->Append(option); + } + return keyboard_layout_list; +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.h b/chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.h new file mode 100644 index 0000000..47e6d82 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_HANGUL_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_HANGUL_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace chromeos { + +// Hangul options page UI handler. +class LanguageHangulHandler : public OptionsPage2UIHandler { + public: + LanguageHangulHandler(); + virtual ~LanguageHangulHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + private: + // Returns the list of hangul keyboards. + static base::ListValue* GetKeyboardLayoutList(); + + DISALLOW_COPY_AND_ASSIGN(LanguageHangulHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_HANGUL_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.cc b/chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.cc new file mode 100644 index 0000000..ce8afe9 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.h" + +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/language_preferences.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_options_util.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { +const char kI18nPrefix[] = "mozc_"; +} // namespace + +namespace chromeos { + +LanguageMozcHandler::LanguageMozcHandler() { +} + +LanguageMozcHandler::~LanguageMozcHandler() { +} + +void LanguageMozcHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "languageMozcPage", + IDS_OPTIONS_SETTINGS_LANGUAGES_MOZC_SETTINGS_TITLE); + + for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) { + localized_strings->SetString( + GetI18nContentValue(language_prefs::kMozcBooleanPrefs[i], kI18nPrefix), + l10n_util::GetStringUTF16( + language_prefs::kMozcBooleanPrefs[i].message_id)); + } + + for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) { + const language_prefs::LanguageMultipleChoicePreference<const char*>& + preference = language_prefs::kMozcMultipleChoicePrefs[i]; + localized_strings->SetString( + GetI18nContentValue(preference, kI18nPrefix), + l10n_util::GetStringUTF16(preference.label_message_id)); + localized_strings->Set(GetTemplateDataPropertyName(preference, kI18nPrefix), + CreateMultipleChoiceList(preference)); + } + + for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) { + const language_prefs::LanguageIntegerRangePreference& preference = + language_prefs::kMozcIntegerPrefs[i]; + localized_strings->SetString( + GetI18nContentValue(preference, kI18nPrefix), + l10n_util::GetStringUTF16(preference.message_id)); + ListValue* list_value = new ListValue(); + for (int j = preference.min_pref_value; j <= preference.max_pref_value; + ++j) { + ListValue* option = new ListValue(); + option->Append(CreateValue(j)); + option->Append(CreateValue(j)); + list_value->Append(option); + } + localized_strings->Set(GetTemplateDataPropertyName(preference, kI18nPrefix), + list_value); + } +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.h b/chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.h new file mode 100644 index 0000000..9069571 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_MOZC_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_MOZC_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +} + +namespace chromeos { + +// Mozc options page UI handler. +class LanguageMozcHandler : public OptionsPage2UIHandler { + public: + LanguageMozcHandler(); + virtual ~LanguageMozcHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(LanguageMozcHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_MOZC_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/language_options_util.cc b/chrome/browser/ui/webui/options2/chromeos/language_options_util.cc new file mode 100644 index 0000000..6108070 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_options_util.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/language_options_util.h" + +namespace chromeos { + +// See comments in .h. +Value* CreateValue(const char* in_value) { + return Value::CreateStringValue(in_value); +} + +Value* CreateValue(int in_value) { + return Value::CreateIntegerValue(in_value); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/language_options_util.h b/chrome/browser/ui/webui/options2/chromeos/language_options_util.h new file mode 100644 index 0000000..70f7307 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_options_util.h @@ -0,0 +1,83 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_OPTIONS_UTIL_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_OPTIONS_UTIL_H_ +#pragma once + +#include <string> + +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/language_preferences.h" +#include "ui/base/l10n/l10n_util.h" + +namespace base { +class ListValue; +} + +namespace chromeos { + +// Returns an i18n-content value corresponding to |preference|. +template <typename T> +std::string GetI18nContentValue(const T& preference, const char* prefix) { + return std::string(prefix) + preference.ibus_config_name; +} + +// Returns a property name of templateData corresponding to |preference|. +template <typename T> +std::string GetTemplateDataPropertyName(const T& preference, + const char* prefix) { + return std::string(prefix) + preference.ibus_config_name + "Value"; +} + +// Returns an property name of templateData corresponding the value of the min +// attribute. +template <typename T> +std::string GetTemplateDataMinName(const T& preference, const char* prefix) { + return std::string(prefix) + preference.ibus_config_name + "Min"; +} + +// Returns an property name of templateData corresponding the value of the max +// attribute. +template <typename T> +std::string GetTemplateDataMaxName(const T& preference, const char* prefix) { + return std::string(prefix) + preference.ibus_config_name + "Max"; +} + +// Creates a Value object from the given value. Here we use function +// overloading to handle string and integer preferences in +// CreateMultipleChoiceList. +Value* CreateValue(const char* in_value); +Value* CreateValue(int in_value); + +// Creates a multiple choice list from the given preference. +template <typename T> +base::ListValue* CreateMultipleChoiceList( + const language_prefs::LanguageMultipleChoicePreference<T>& preference) { + int list_length = 0; + for (size_t i = 0; + i < language_prefs::LanguageMultipleChoicePreference<T>::kMaxItems; + ++i) { + if (preference.values_and_ids[i].item_message_id == 0) + break; + ++list_length; + } + DCHECK_GT(list_length, 0); + + base::ListValue* list_value = new base::ListValue(); + for (int i = 0; i < list_length; ++i) { + base::ListValue* option = new base::ListValue(); + option->Append(CreateValue( + preference.values_and_ids[i].ibus_config_value)); + option->Append(base::Value::CreateStringValue(l10n_util::GetStringUTF16( + preference.values_and_ids[i].item_message_id))); + list_value->Append(option); + } + return list_value; +} + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_OPTIONS_UTIL_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.cc b/chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.cc new file mode 100644 index 0000000..8e2c19c --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.h" + +#include "base/values.h" +#include "chrome/browser/chromeos/language_preferences.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_options_util.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { +const char kI18nPrefix[] = "Pinyin"; +} // namespace + +namespace chromeos { + +LanguagePinyinHandler::LanguagePinyinHandler() { +} + +LanguagePinyinHandler::~LanguagePinyinHandler() { +} + +void LanguagePinyinHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "languagePinyinPage", + IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTINGS_TITLE); + + for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) { + localized_strings->SetString( + GetI18nContentValue(language_prefs::kPinyinBooleanPrefs[i], + kI18nPrefix), + l10n_util::GetStringUTF16( + language_prefs::kPinyinBooleanPrefs[i].message_id)); + } + + localized_strings->SetString( + GetI18nContentValue(language_prefs::kPinyinDoublePinyinSchema, + kI18nPrefix), + l10n_util::GetStringUTF16( + language_prefs::kPinyinDoublePinyinSchema.label_message_id)); + ListValue* list_value = new ListValue(); + for (size_t i = 0; + i < language_prefs::LanguageMultipleChoicePreference<int>::kMaxItems; + ++i) { + if (language_prefs::kPinyinDoublePinyinSchema.values_and_ids[i]. + item_message_id == 0) + break; + ListValue* option = new ListValue(); + option->Append(Value::CreateIntegerValue( + language_prefs::kPinyinDoublePinyinSchema.values_and_ids[i]. + ibus_config_value)); + option->Append(Value::CreateStringValue(l10n_util::GetStringUTF16( + language_prefs::kPinyinDoublePinyinSchema.values_and_ids[i]. + item_message_id))); + list_value->Append(option); + } + localized_strings->Set( + GetTemplateDataPropertyName(language_prefs::kPinyinDoublePinyinSchema, + kI18nPrefix), + list_value); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.h b/chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.h new file mode 100644 index 0000000..7a81cb5 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_PINYIN_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_PINYIN_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +} + +namespace chromeos { + +// Pinyin options page UI handler. +class LanguagePinyinHandler : public OptionsPage2UIHandler { + public: + LanguagePinyinHandler(); + virtual ~LanguagePinyinHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(LanguagePinyinHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_LANGUAGE_PINYIN_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/proxy_handler.cc b/chrome/browser/ui/webui/options2/chromeos/proxy_handler.cc new file mode 100644 index 0000000..773fe51 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/proxy_handler.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/proxy_handler.h" + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/stl_util.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +namespace chromeos { + +ProxyHandler::ProxyHandler() { +} + +ProxyHandler::~ProxyHandler() { +} + +void ProxyHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + // Proxy page - ChromeOS + localized_strings->SetString("proxyPage", + l10n_util::GetStringUTF16(IDS_OPTIONS_PROXY_TAB_LABEL)); + localized_strings->SetString("proxyPageTitleFormat", + l10n_util::GetStringUTF16(IDS_PROXY_PAGE_TITLE_FORMAT)); + localized_strings->SetString("proxy_config_title", + l10n_util::GetStringUTF16(IDS_PROXY_CONFIG_TITLE)); + localized_strings->SetString("proxyDirectInternetConnection", + l10n_util::GetStringUTF16(IDS_PROXY_DIRECT_CONNECTION)); + + localized_strings->SetString("proxyManual", + l10n_util::GetStringUTF16(IDS_PROXY_MANUAL_CONFIG)); + localized_strings->SetString("sameProxyProtocols", + l10n_util::GetStringUTF16(IDS_PROXY_SAME_FORALL)); + + localized_strings->SetString("httpProxy", + l10n_util::GetStringUTF16(IDS_PROXY_HTTP_PROXY)); + localized_strings->SetString("secureHttpProxy", + l10n_util::GetStringUTF16(IDS_PROXY_HTTP_SECURE_HTTP_PROXY)); + localized_strings->SetString("ftpProxy", + l10n_util::GetStringUTF16(IDS_PROXY_FTP_PROXY)); + localized_strings->SetString("socksHost", + l10n_util::GetStringUTF16(IDS_PROXY_SOCKS_HOST)); + localized_strings->SetString("proxyAutomatic", + l10n_util::GetStringUTF16(IDS_PROXY_AUTOMATIC)); + localized_strings->SetString("proxyConfigUrl", + l10n_util::GetStringUTF16(IDS_PROXY_CONFIG_URL)); + localized_strings->SetString("advanced_proxy_config", + l10n_util::GetStringUTF16(IDS_PROXY_ADVANCED_CONFIG)); + localized_strings->SetString("addHost", + l10n_util::GetStringUTF16(IDS_PROXY_ADD_HOST)); + localized_strings->SetString("removeHost", + l10n_util::GetStringUTF16(IDS_PROXY_REMOVE_HOST)); + localized_strings->SetString("proxyPort", + l10n_util::GetStringUTF16(IDS_PROXY_PORT)); + localized_strings->SetString("proxyBypass", + l10n_util::GetStringUTF16(IDS_PROXY_BYPASS)); + localized_strings->SetString("policyManagedPrefsBannerText", + l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_MANAGED_PREFS)); + localized_strings->SetString("extensionManagedPrefsBannerText", + l10n_util::GetStringUTF16(IDS_OPTIONS_EXTENSION_MANAGED_PREFS)); + localized_strings->SetString("unmodifiablePrefsBannerText", + l10n_util::GetStringUTF16(IDS_OPTIONS_UNMODIFIABLE_PREFS)); + localized_strings->SetString("enableSharedProxiesBannerText", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_ENABLE_SHARED_PROXIES_HINT, + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES))); +} + +void ProxyHandler::SetNetworkName(const std::string& name) { + StringValue network(name); + web_ui_->CallJavascriptFunction("options.ProxyOptions.setNetworkName", + network); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/proxy_handler.h b/chrome/browser/ui/webui/options2/chromeos/proxy_handler.h new file mode 100644 index 0000000..e164642 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/proxy_handler.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_PROXY_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_PROXY_HANDLER_H_ + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace chromeos { + +// ChromeOS proxy options page UI handler. +class ProxyHandler : public OptionsPage2UIHandler { + public: + explicit ProxyHandler(); + virtual ~ProxyHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // Set network name for proxy page title. + void SetNetworkName(const std::string& name); + + private: + + DISALLOW_COPY_AND_ASSIGN(ProxyHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_PROXY_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/stats_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/stats_options_handler.cc new file mode 100644 index 0000000..998e1b5 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/stats_options_handler.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/stats_options_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "content/browser/user_metrics.h" + +namespace chromeos { + +StatsOptionsHandler::StatsOptionsHandler() { +} + +// OptionsPageUIHandler implementation. +void StatsOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { +} + +void StatsOptionsHandler::Initialize() { +} + +// WebUIMessageHandler implementation. +void StatsOptionsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("metricsReportingCheckboxAction", + base::Bind(&StatsOptionsHandler::HandleMetricsReportingCheckbox, + base::Unretained(this))); +} + +void StatsOptionsHandler::HandleMetricsReportingCheckbox( + const ListValue* args) { +#if defined(GOOGLE_CHROME_BUILD) + const std::string checked_str = UTF16ToUTF8(ExtractStringValue(args)); + const bool enabled = (checked_str == "true"); + UserMetrics::RecordAction( + enabled ? + UserMetricsAction("Options_MetricsReportingCheckbox_Enable") : + UserMetricsAction("Options_MetricsReportingCheckbox_Disable")); +#endif +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/stats_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/stats_options_handler.h new file mode 100644 index 0000000..2212064 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/stats_options_handler.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_STATS_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_STATS_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace chromeos { + +// ChromeOS handler for "Stats/crash reporting to Google" option of the Advanced +// settings page. This handler does only ChromeOS-specific actions while default +// code is in Chrome's AdvancedOptionsHandler +// (chrome/browser/webui/advanced_options_handler.cc). +class StatsOptionsHandler : public OptionsPage2UIHandler { + public: + StatsOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + private: + void HandleMetricsReportingCheckbox(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(StatsOptionsHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_STATS_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/system_options_handler.cc b/chrome/browser/ui/webui/options2/chromeos/system_options_handler.cc new file mode 100644 index 0000000..62261ee --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/system_options_handler.cc @@ -0,0 +1,170 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/system_options_handler.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/json/json_value_serializer.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/accessibility/accessibility_util.h" +#include "chrome/browser/chromeos/cros_settings.h" +#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h" +#include "chrome/browser/chromeos/dbus/power_manager_client.h" +#include "chrome/browser/chromeos/language_preferences.h" +#include "chrome/browser/chromeos/system/touchpad_settings.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/extensions/extension.h" +#include "grit/browser_resources.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +using content::BrowserThread; + +namespace { + +void TouchpadExistsFileThread(bool* exists) { + *exists = chromeos::system::touchpad_settings::TouchpadExists(); +} + +} + +SystemOptionsHandler::SystemOptionsHandler() { +} + +SystemOptionsHandler::~SystemOptionsHandler() { +} + +void SystemOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "systemPage", IDS_OPTIONS_SYSTEM_TAB_LABEL); + localized_strings->SetString("datetimeTitle", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME)); + localized_strings->SetString("timezone", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION)); + localized_strings->SetString("use24HourClock", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_USE_24HOUR_CLOCK_DESCRIPTION)); + + localized_strings->SetString("screen", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_SCREEN)); + localized_strings->SetString("brightness", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BRIGHTNESS_DESCRIPTION)); + localized_strings->SetString("brightnessDecrease", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BRIGHTNESS_DECREASE)); + localized_strings->SetString("brightnessIncrease", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BRIGHTNESS_INCREASE)); + + localized_strings->SetString("touchpad", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_TOUCHPAD)); + localized_strings->SetString("enableTapToClick", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_TAP_TO_CLICK_ENABLED_DESCRIPTION)); + localized_strings->SetString("sensitivity", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SENSITIVITY_DESCRIPTION)); + localized_strings->SetString("sensitivityLess", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SENSITIVITY_LESS_DESCRIPTION)); + localized_strings->SetString("sensitivityMore", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SENSITIVITY_MORE_DESCRIPTION)); + + localized_strings->SetString("language", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE)); + localized_strings->SetString("languageCustomize", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE)); + localized_strings->SetString("modifierKeysCustomize", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_MODIFIER_KEYS_CUSTOMIZE)); + + localized_strings->SetString("accessibilityTitle", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY)); + localized_strings->SetString("accessibility", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DESCRIPTION)); + + // TODO(pastarmovj): replace this with a call to the CrosSettings list + // handling functionality to come. + localized_strings->Set("timezoneList", + static_cast<chromeos::SystemSettingsProvider*>( + chromeos::CrosSettings::Get()->GetProvider( + chromeos::kSystemTimezone))->GetTimezoneList()); +} + +void SystemOptionsHandler::Initialize() { + DCHECK(web_ui_); + PrefService* pref_service = g_browser_process->local_state(); + bool acc_enabled = pref_service->GetBoolean(prefs::kSpokenFeedbackEnabled); + base::FundamentalValue checked(acc_enabled); + web_ui_->CallJavascriptFunction( + "options.SystemOptions.SetAccessibilityCheckboxState", checked); + + bool* exists = new bool; + BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, + base::Bind(&TouchpadExistsFileThread, exists), + base::Bind(&SystemOptionsHandler::TouchpadExists, AsWeakPtr(), exists)); +} + +void SystemOptionsHandler::TouchpadExists(bool* exists) { + if (*exists) + web_ui_->CallJavascriptFunction( + "options.SystemOptions.showTouchpadControls"); + delete exists; +} + +void SystemOptionsHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("accessibilityChange", + base::Bind(&SystemOptionsHandler::AccessibilityChangeCallback, + base::Unretained(this))); + + web_ui_->RegisterMessageCallback("decreaseScreenBrightness", + base::Bind(&SystemOptionsHandler::DecreaseScreenBrightnessCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("increaseScreenBrightness", + base::Bind(&SystemOptionsHandler::IncreaseScreenBrightnessCallback, + base::Unretained(this))); +} + +void SystemOptionsHandler::AccessibilityChangeCallback(const ListValue* args) { + std::string checked_str; + args->GetString(0, &checked_str); + bool accessibility_enabled = (checked_str == "true"); + + chromeos::accessibility::EnableAccessibility(accessibility_enabled, NULL); +} + +void SystemOptionsHandler::DecreaseScreenBrightnessCallback( + const ListValue* args) { + // Do not allow the options button to turn off the backlight, as that + // can make it very difficult to see the increase brightness button. + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> + DecreaseScreenBrightness(false); +} + +void SystemOptionsHandler::IncreaseScreenBrightnessCallback( + const ListValue* args) { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> + IncreaseScreenBrightness(); +} diff --git a/chrome/browser/ui/webui/options2/chromeos/system_options_handler.h b/chrome/browser/ui/webui/options2/chromeos/system_options_handler.h new file mode 100644 index 0000000..021712a --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/system_options_handler.h @@ -0,0 +1,50 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SYSTEM_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SYSTEM_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/memory/weak_ptr.h" +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +} + +// ChromeOS system options page UI handler. +class SystemOptionsHandler + : public OptionsPage2UIHandler, + public base::SupportsWeakPtr<SystemOptionsHandler> { + public: + SystemOptionsHandler(); + virtual ~SystemOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + virtual void RegisterMessages() OVERRIDE; + + // Called when the accessibility checkbox value is changed. + // |args| will contain the checkbox checked state as a string + // ("true" or "false"). + void AccessibilityChangeCallback(const base::ListValue* args); + + // Called when the System configuration screen is used to adjust + // the screen brightness. + // |args| will be an empty list. + void DecreaseScreenBrightnessCallback(const base::ListValue* args); + void IncreaseScreenBrightnessCallback(const base::ListValue* args); + + private: + // Callback for TouchpadHelper. + void TouchpadExists(bool* exists); + + DISALLOW_COPY_AND_ASSIGN(SystemOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SYSTEM_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/system_settings_provider.cc b/chrome/browser/ui/webui/options2/chromeos/system_settings_provider.cc new file mode 100644 index 0000000..9ad4cc1 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/system_settings_provider.cc @@ -0,0 +1,331 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h" + +#include <string> + +#include "base/i18n/rtl.h" +#include "base/lazy_instance.h" +#include "base/memory/scoped_ptr.h" +#include "base/stl_util.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "base/synchronization/lock.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros_settings.h" +#include "chrome/browser/chromeos/cros_settings_names.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "unicode/calendar.h" +#include "unicode/timezone.h" +#include "unicode/ures.h" + +namespace { + +// TODO(jungshik): Using Enumerate method in ICU gives 600+ timezones. +// Even after filtering out duplicate entries with a strict identity check, +// we still have 400+ zones. Relaxing the criteria for the timezone +// identity is likely to cut down the number to < 100. Until we +// come up with a better list, we hard-code the following list as used by +// Android. +static const char* kTimeZones[] = { + "Pacific/Majuro", + "Pacific/Midway", + "Pacific/Honolulu", + "America/Anchorage", + "America/Los_Angeles", + "America/Tijuana", + "America/Denver", + "America/Phoenix", + "America/Chihuahua", + "America/Chicago", + "America/Mexico_City", + "America/Costa_Rica", + "America/Regina", + "America/New_York", + "America/Bogota", + "America/Caracas", + "America/Barbados", + "America/Manaus", + "America/Santiago", + "America/St_Johns", + "America/Sao_Paulo", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Godthab", + "America/Montevideo", + "Atlantic/South_Georgia", + "Atlantic/Azores", + "Atlantic/Cape_Verde", + "Africa/Casablanca", + "Europe/London", + "Europe/Amsterdam", + "Europe/Belgrade", + "Europe/Brussels", + "Europe/Sarajevo", + "Africa/Windhoek", + "Africa/Brazzaville", + "Asia/Amman", + "Europe/Athens", + "Asia/Beirut", + "Africa/Cairo", + "Europe/Helsinki", + "Asia/Jerusalem", + "Europe/Minsk", + "Africa/Harare", + "Asia/Baghdad", + "Europe/Moscow", + "Asia/Kuwait", + "Africa/Nairobi", + "Asia/Tehran", + "Asia/Baku", + "Asia/Tbilisi", + "Asia/Yerevan", + "Asia/Dubai", + "Asia/Kabul", + "Asia/Karachi", + "Asia/Oral", + "Asia/Yekaterinburg", + "Asia/Calcutta", + "Asia/Colombo", + "Asia/Katmandu", + "Asia/Almaty", + "Asia/Rangoon", + "Asia/Krasnoyarsk", + "Asia/Bangkok", + "Asia/Shanghai", + "Asia/Hong_Kong", + "Asia/Irkutsk", + "Asia/Kuala_Lumpur", + "Australia/Perth", + "Asia/Taipei", + "Asia/Seoul", + "Asia/Tokyo", + "Asia/Yakutsk", + "Australia/Adelaide", + "Australia/Darwin", + "Australia/Brisbane", + "Australia/Hobart", + "Australia/Sydney", + "Asia/Vladivostok", + "Pacific/Guam", + "Asia/Magadan", + "Pacific/Auckland", + "Pacific/Fiji", + "Pacific/Tongatapu", +}; + +static base::LazyInstance<base::Lock, + base::LeakyLazyInstanceTraits<base::Lock> > + g_timezone_bundle_lock = LAZY_INSTANCE_INITIALIZER; + +struct UResClose { + inline void operator() (UResourceBundle* b) const { + ures_close(b); + } +}; + +string16 GetExemplarCity(const icu::TimeZone& zone) { + // TODO(jungshik): After upgrading to ICU 4.6, use U_ICUDATA_ZONE + static const char* zone_bundle_name = NULL; + + // These will be leaked at the end. + static UResourceBundle *zone_bundle = NULL; + static UResourceBundle *zone_strings = NULL; + + UErrorCode status = U_ZERO_ERROR; + { + base::AutoLock lock(g_timezone_bundle_lock.Get()); + if (zone_bundle == NULL) + zone_bundle = ures_open(zone_bundle_name, uloc_getDefault(), &status); + + if (zone_strings == NULL) + zone_strings = ures_getByKey(zone_bundle, "zone_strings", NULL, &status); + } + + icu::UnicodeString zone_id; + zone.getID(zone_id); + std::string zone_id_str; + zone_id.toUTF8String(zone_id_str); + + // resource keys for timezones use ':' in place of '/'. + ReplaceSubstringsAfterOffset(&zone_id_str, 0, "/", ":"); + scoped_ptr_malloc<UResourceBundle, UResClose> zone_item( + ures_getByKey(zone_strings, zone_id_str.c_str(), NULL, &status)); + icu::UnicodeString city; + if (!U_FAILURE(status)) { + city = icu::ures_getUnicodeStringByKey(zone_item.get(), "ec", &status); + if (U_SUCCESS(status)) + return string16(city.getBuffer(), city.length()); + } + + // Fallback case in case of failure. + ReplaceSubstringsAfterOffset(&zone_id_str, 0, ":", "/"); + // Take the last component of a timezone id (e.g. 'Baz' in 'Foo/Bar/Baz'). + // Depending on timezones, keeping all but the 1st component + // (e.g. Bar/Baz) may be better, but our current list does not have + // any timezone for which that's the case. + std::string::size_type slash_pos = zone_id_str.rfind('/'); + if (slash_pos != std::string::npos && slash_pos < zone_id_str.size()) + zone_id_str.erase(0, slash_pos + 1); + // zone id has '_' in place of ' '. + ReplaceSubstringsAfterOffset(&zone_id_str, 0, "_", " "); + return ASCIIToUTF16(zone_id_str); +} + +} // namespace anonymous + +namespace chromeos { + +SystemSettingsProvider::SystemSettingsProvider() { + for (size_t i = 0; i < arraysize(kTimeZones); i++) { + timezones_.push_back(icu::TimeZone::createTimeZone( + icu::UnicodeString(kTimeZones[i], -1, US_INV))); + } + system::TimezoneSettings::GetInstance()->AddObserver(this); + timezone_value_.reset(base::Value::CreateStringValue(GetKnownTimezoneID( + system::TimezoneSettings::GetInstance()->GetTimezone()))); +} + +SystemSettingsProvider::~SystemSettingsProvider() { + system::TimezoneSettings::GetInstance()->RemoveObserver(this); + STLDeleteElements(&timezones_); +} + +void SystemSettingsProvider::DoSet(const std::string& path, + const base::Value& in_value) { + // Non-guest users can change the time zone. + if (UserManager::Get()->IsLoggedInAsGuest()) + return; + + if (path == kSystemTimezone) { + string16 value; + if (!in_value.IsType(Value::TYPE_STRING) || !in_value.GetAsString(&value)) + return; + const icu::TimeZone* timezone = GetTimezone(value); + if (!timezone) + return; + system::TimezoneSettings::GetInstance()->SetTimezone(*timezone); + timezone_value_.reset( + base::Value::CreateStringValue(GetKnownTimezoneID(*timezone))); + } +} + +const base::Value* SystemSettingsProvider::Get(const std::string& path) const { + if (path == kSystemTimezone) + return timezone_value_.get(); + return NULL; +} + +// The timezone is always trusted. +bool SystemSettingsProvider::GetTrusted(const std::string& path, + const base::Closure& callback) { + return true; +} + +bool SystemSettingsProvider::HandlesSetting(const std::string& path) const { + return path == kSystemTimezone; +} + +void SystemSettingsProvider::Reload() { + // TODO(pastarmovj): We can actually cache the timezone here to make returning + // it faster. +} + +void SystemSettingsProvider::TimezoneChanged(const icu::TimeZone& timezone) { + // Fires system setting change notification. + timezone_value_.reset( + base::Value::CreateStringValue(GetKnownTimezoneID(timezone))); + CrosSettings::Get()->FireObservers(kSystemTimezone); +} + +ListValue* SystemSettingsProvider::GetTimezoneList() { + ListValue* timezoneList = new ListValue(); + for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin(); + iter != timezones_.end(); ++iter) { + const icu::TimeZone* timezone = *iter; + ListValue* option = new ListValue(); + option->Append(Value::CreateStringValue(GetTimezoneID(*timezone))); + option->Append(Value::CreateStringValue(GetTimezoneName(*timezone))); + timezoneList->Append(option); + } + return timezoneList; +} + +string16 SystemSettingsProvider::GetTimezoneName( + const icu::TimeZone& timezone) { + // Instead of using the raw_offset, use the offset in effect now. + // For instance, US Pacific Time, the offset shown will be -7 in summer + // while it'll be -8 in winter. + int raw_offset, dst_offset; + UDate now = icu::Calendar::getNow(); + UErrorCode status = U_ZERO_ERROR; + timezone.getOffset(now, false, raw_offset, dst_offset, status); + DCHECK(U_SUCCESS(status)); + int offset = raw_offset + dst_offset; + // offset is in msec. + int minute_offset = std::abs(offset) / 60000; + int hour_offset = minute_offset / 60; + int min_remainder = minute_offset % 60; + // Some timezones have a non-integral hour offset. So, we need to + // use hh:mm form. + std::string offset_str = base::StringPrintf(offset >= 0 ? + "UTC+%d:%02d" : "UTC-%d:%02d", hour_offset, min_remainder); + + // TODO(jungshik): When coming up with a better list of timezones, we also + // have to come up with better 'display' names. One possibility is to list + // multiple cities (e.g. "Los Angeles, Vancouver .." in the order of + // the population of a country the city belongs to.). + // We can also think of using LONG_GENERIC or LOCATION once we upgrade + // to ICU 4.6. + // In the meantime, we use "LONG" name with "Exemplar City" to distinguish + // multiple timezones with the same "LONG" name but with different + // rules (e.g. US Mountain Time in Denver vs Phoenix). + icu::UnicodeString name; + timezone.getDisplayName(dst_offset != 0, icu::TimeZone::LONG, name); + string16 result(l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_TIMEZONE_DISPLAY_TEMPLATE, ASCIIToUTF16(offset_str), + string16(name.getBuffer(), name.length()), GetExemplarCity(timezone))); + base::i18n::AdjustStringForLocaleDirection(&result); + return result; +} + +string16 SystemSettingsProvider::GetTimezoneID( + const icu::TimeZone& timezone) { + icu::UnicodeString id; + timezone.getID(id); + return string16(id.getBuffer(), id.length()); +} + +const icu::TimeZone* SystemSettingsProvider::GetTimezone( + const string16& timezone_id) { + for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin(); + iter != timezones_.end(); ++iter) { + const icu::TimeZone* timezone = *iter; + if (GetTimezoneID(*timezone) == timezone_id) { + return timezone; + } + } + return NULL; +} + +string16 SystemSettingsProvider::GetKnownTimezoneID( + const icu::TimeZone& timezone) const { + for (std::vector<icu::TimeZone*>::const_iterator iter = timezones_.begin(); + iter != timezones_.end(); ++iter) { + const icu::TimeZone* known_timezone = *iter; + if (known_timezone->hasSameRules(timezone)) + return GetTimezoneID(*known_timezone); + } + + // Not able to find a matching timezone in our list. + return string16(); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h b/chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h new file mode 100644 index 0000000..e39fa2b --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h @@ -0,0 +1,76 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SYSTEM_SETTINGS_PROVIDER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SYSTEM_SETTINGS_PROVIDER_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/string16.h" +#include "chrome/browser/chromeos/cros_settings_provider.h" +#include "chrome/browser/chromeos/system/timezone_settings.h" +#include "third_party/icu/public/i18n/unicode/timezone.h" + +namespace base { +class Value; +class ListValue; +class StringValue; +} + +namespace chromeos { + +class SystemSettingsProvider : public CrosSettingsProvider, + public system::TimezoneSettings::Observer { + public: + SystemSettingsProvider(); + virtual ~SystemSettingsProvider(); + + // CrosSettingsProvider overrides. + virtual const base::Value* Get(const std::string& path) const OVERRIDE; + virtual bool GetTrusted(const std::string& path, + const base::Closure& callback) OVERRIDE; + virtual bool HandlesSetting(const std::string& path) const OVERRIDE; + virtual void Reload() OVERRIDE; + + // Overridden from TimezoneSettings::Observer: + virtual void TimezoneChanged(const icu::TimeZone& timezone) OVERRIDE; + + // Creates the map of timezones used by the options page. + base::ListValue* GetTimezoneList(); + + private: + // CrosSettingsProvider overrides. + virtual void DoSet(const std::string& path, + const base::Value& in_value) OVERRIDE; + + // Gets timezone name. + static string16 GetTimezoneName(const icu::TimeZone& timezone); + + // Gets timezone ID which is also used as timezone pref value. + static string16 GetTimezoneID(const icu::TimeZone& timezone); + + // Gets timezone object from its id. + const icu::TimeZone* GetTimezone(const string16& timezone_id); + + // Gets a timezone id from a timezone in |timezones_| that has the same + // rule of given |timezone|. + // One timezone could have multiple timezones, + // e.g. + // US/Pacific == America/Los_Angeles + // We should always use the known timezone id when passing back as + // pref values. + string16 GetKnownTimezoneID(const icu::TimeZone& timezone) const; + + // Timezones. + std::vector<icu::TimeZone*> timezones_; + + scoped_ptr<base::Value> timezone_value_; + + DISALLOW_COPY_AND_ASSIGN(SystemSettingsProvider); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SYSTEM_SETTINGS_PROVIDER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/user_image_source.cc b/chrome/browser/ui/webui/options2/chromeos/user_image_source.cc new file mode 100644 index 0000000..f259c03 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/user_image_source.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/user_image_source.h" + +#include "base/memory/ref_counted_memory.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/common/url_constants.h" +#include "grit/theme_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/codec/png_codec.h" + +namespace chromeos { + +std::vector<unsigned char> UserImageSource::GetUserImage( + const std::string& email) const { + std::vector<unsigned char> user_image; + const chromeos::User* user = chromeos::UserManager::Get()->FindUser(email); + if (user) { + gfx::PNGCodec::EncodeBGRASkBitmap(user->image(), false, &user_image); + return user_image; + } + gfx::PNGCodec::EncodeBGRASkBitmap( + *ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_LOGIN_DEFAULT_USER), + false, + &user_image); + return user_image; +} + +UserImageSource::UserImageSource() + : DataSource(chrome::kChromeUIUserImageHost, MessageLoop::current()) { +} + +UserImageSource::~UserImageSource() {} + +void UserImageSource::StartDataRequest(const std::string& path, + bool is_incognito, + int request_id) { + // Strip the query param value - we only use it as a hack to ensure our + // image gets reloaded instead of being pulled from the browser cache + std::string email = path.substr(0, path.find_first_of("?")); + SendResponse(request_id, new RefCountedBytes(GetUserImage(email))); +} + +std::string UserImageSource::GetMimeType(const std::string&) const { + // We need to explicitly return a mime type, otherwise if the user tries to + // drag the image they get no extension. + return "image/png"; +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/user_image_source.h b/chrome/browser/ui/webui/options2/chromeos/user_image_source.h new file mode 100644 index 0000000..ea38b49 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/user_image_source.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_USER_IMAGE_SOURCE_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_USER_IMAGE_SOURCE_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/ui/webui/chrome_url_data_manager.h" + +namespace chromeos { + +// UserImageSource is the data source that serves user images for users that +// have it. +class UserImageSource : public ChromeURLDataManager::DataSource { + public: + UserImageSource(); + + // Called when the network layer has requested a resource underneath + // the path we registered. + virtual void StartDataRequest(const std::string& path, + bool is_incognito, + int request_id) OVERRIDE; + + virtual std::string GetMimeType(const std::string&) const OVERRIDE; + + // Returns PNG encoded image for user with specified email. + // If there's no user with such email, returns the default image. + std::vector<unsigned char> GetUserImage(const std::string& email) const; + + private: + virtual ~UserImageSource(); + + DISALLOW_COPY_AND_ASSIGN(UserImageSource); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_USER_IMAGE_SOURCE_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.cc b/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.cc new file mode 100644 index 0000000..22c0fe6 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.h" + +#include <map> +#include <set> +#include <string> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/input_method/input_method_manager.h" +#include "chrome/browser/chromeos/input_method/input_method_util.h" +#include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h" +#include "chrome/browser/chromeos/preferences.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/scoped_user_pref_update.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ime = ::chromeos::input_method; + +namespace chromeos { + +VirtualKeyboardManagerHandler::VirtualKeyboardManagerHandler() { +} + +VirtualKeyboardManagerHandler::~VirtualKeyboardManagerHandler() { +} + +void VirtualKeyboardManagerHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static const OptionsStringResource resources[] = { + { "virtualKeyboardLayoutColumnTitle", + IDS_OPTIONS_SETTINGS_LANGUAGES_VIRTUAL_KEYBOARD_LAYOUT_COLUMN_TITLE }, + { "virtualKeyboardKeyboardColumnTitle", + IDS_OPTIONS_SETTINGS_LANGUAGES_VIRTUAL_KEYBOARD_KEYBOARD_COLUMN_TITLE }, + { "defaultVirtualKeyboard", + IDS_OPTIONS_SETTINGS_LANGUAGES_DEFAULT_VIRTUAL_KEYBOARD }, + }; + RegisterStrings(localized_strings, resources, arraysize(resources)); + + RegisterTitle(localized_strings, "virtualKeyboardPage", + IDS_OPTIONS_SETTINGS_LANGUAGES_VIRTUAL_KEYBOARD_SETTINGS_TITLE); + + // Do not call GetVirtualKeyboardList() here since |web_ui_| is not ready yet. +} + +void VirtualKeyboardManagerHandler::Initialize() { +} + +void VirtualKeyboardManagerHandler::RegisterMessages() { + DCHECK(web_ui_); + // Register handler functions for chrome.send(). + web_ui_->RegisterMessageCallback("updateVirtualKeyboardList", + base::Bind(&VirtualKeyboardManagerHandler::UpdateVirtualKeyboardList, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setVirtualKeyboardPreference", + base::Bind(&VirtualKeyboardManagerHandler::SetVirtualKeyboardPreference, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("clearVirtualKeyboardPreference", + base::Bind(&VirtualKeyboardManagerHandler::ClearVirtualKeyboardPreference, + base::Unretained(this))); +} + +ListValue* VirtualKeyboardManagerHandler::GetVirtualKeyboardList() { + DCHECK(web_ui_); + ime::InputMethodManager* input_method = + ime::InputMethodManager::GetInstance(); + + // Get a multi map from layout name (e.g. "us(dvorak)"), to virtual keyboard + // extension. + const LayoutToKeyboard& layout_to_keyboard = + input_method->GetLayoutNameToKeyboardMapping(); + const UrlToKeyboard& url_to_keyboard = + input_method->GetUrlToKeyboardMapping(); + + // Get the current pref values. + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); + DCHECK(prefs); + const DictionaryValue* virtual_keyboard_pref = + prefs->GetDictionary(prefs::kLanguagePreferredVirtualKeyboard); + + return CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, virtual_keyboard_pref); +} + +void VirtualKeyboardManagerHandler::UpdateVirtualKeyboardList( + const ListValue* args) { + scoped_ptr<Value> virtual_keyboards(GetVirtualKeyboardList()); + DCHECK(virtual_keyboards.get()); + web_ui_->CallJavascriptFunction( + "VirtualKeyboardManager.updateVirtualKeyboardList", *virtual_keyboards); +} + +void VirtualKeyboardManagerHandler::SetVirtualKeyboardPreference( + const ListValue* args) { + DCHECK(web_ui_); + std::string layout, url; + if (!args || !args->GetString(0, &layout) || !args->GetString(1, &url)) { + LOG(ERROR) << "SetVirtualKeyboardPreference: Invalid argument"; + return; + } + + // Validate args. + ime::InputMethodManager* input_method = + ime::InputMethodManager::GetInstance(); + if (!ValidateUrl(input_method->GetUrlToKeyboardMapping(), layout, url)) { + LOG(ERROR) << "SetVirtualKeyboardPreference: Invalid args: " + << "layout=" << layout << ", url=" << url; + return; + } + + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); + DCHECK(prefs); + { + DictionaryPrefUpdate updater( + prefs, prefs::kLanguagePreferredVirtualKeyboard); + DictionaryValue* pref_value = updater.Get(); + pref_value->SetWithoutPathExpansion(layout, new StringValue(url)); + } + Preferences::UpdateVirturalKeyboardPreference(prefs); +} + +void VirtualKeyboardManagerHandler::ClearVirtualKeyboardPreference( + const ListValue* args) { + DCHECK(web_ui_); + std::string layout; + if (!args || !args->GetString(0, &layout)) { + LOG(ERROR) << "ClearVirtualKeyboardPreference: Invalid argument"; + return; + } + + // Validate |layout|. + ime::InputMethodManager* input_method = + ime::InputMethodManager::GetInstance(); + if (!input_method->GetLayoutNameToKeyboardMapping().count(layout)) { + LOG(ERROR) << "ClearVirtualKeyboardPreference: Invalid layout: " << layout; + return; + } + + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); + DCHECK(prefs); + { + DictionaryPrefUpdate updater( + prefs, prefs::kLanguagePreferredVirtualKeyboard); + DictionaryValue* pref_value = updater.Get(); + pref_value->RemoveWithoutPathExpansion(layout, NULL); + } + Preferences::UpdateVirturalKeyboardPreference(prefs); +} + +// static +bool VirtualKeyboardManagerHandler::ValidateUrl( + const UrlToKeyboard& url_to_keyboard, + const std::string& layout, + const std::string& url) { + UrlToKeyboard::const_iterator iter = url_to_keyboard.find(GURL(url)); + if (iter == url_to_keyboard.end() || + !iter->second->supported_layouts().count(layout)) { + return false; + } + return true; +} + +// static +ListValue* VirtualKeyboardManagerHandler::CreateVirtualKeyboardList( + const LayoutToKeyboard& layout_to_keyboard, + const UrlToKeyboard& url_to_keyboard, + const DictionaryValue* virtual_keyboard_pref) { + ListValue* layout_list = new ListValue; + + // |dictionary| points to an element in the |layout_list|. One dictionary + // element is created for one layout. + DictionaryValue* dictionary = NULL; + + LayoutToKeyboard::const_iterator i; + for (i = layout_to_keyboard.begin(); i != layout_to_keyboard.end(); ++i) { + const std::string& layout_id = i->first; + + std::string string_value; + // Check the "layout" value in the current dictionary. + if (dictionary) { + dictionary->GetString("layout", &string_value); + } + + if (string_value != layout_id) { + // New layout is found. Add the layout to |layout_list|. + dictionary = new DictionaryValue; + layout_list->Append(dictionary); + + // Set layout id as well as its human readable form. + ime::InputMethodManager* manager = ime::InputMethodManager::GetInstance(); + const ime::InputMethodDescriptor* desc = + manager->GetInputMethodUtil()->GetInputMethodDescriptorFromXkbId( + layout_id); + const std::string layout_name = desc ? + manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId( + desc->id()) : layout_id; + dictionary->SetString("layout", layout_id); + dictionary->SetString("layoutName", layout_name); + + // Check if the layout is in user pref. + if (virtual_keyboard_pref && + virtual_keyboard_pref->GetString(layout_id, &string_value) && + ValidateUrl(url_to_keyboard, layout_id, string_value)) { + dictionary->SetString("preferredKeyboard", string_value); + } + dictionary->Set("supportedKeyboards", new ListValue); + } + + ListValue* supported_keyboards = NULL; + dictionary->GetList("supportedKeyboards", &supported_keyboards); + DCHECK(supported_keyboards); + + DictionaryValue* virtual_keyboard = new DictionaryValue; + virtual_keyboard->SetString("name", i->second->name()); + virtual_keyboard->SetBoolean("isSystem", i->second->is_system()); + virtual_keyboard->SetString("url", i->second->url().spec()); + supported_keyboards->Append(virtual_keyboard); + } + + return layout_list; +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.h b/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.h new file mode 100644 index 0000000..5da4142 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.h @@ -0,0 +1,78 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_VIRTUAL_KEYBOARD_MANAGER_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_VIRTUAL_KEYBOARD_MANAGER_HANDLER_H_ +#pragma once + +#include <map> +#include <set> +#include <string> + +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "googleurl/src/gurl.h" + +namespace base { +class DictionaryValue; +class ListValue; +} // namespace base + +namespace chromeos { + +namespace input_method { +class VirtualKeyboard; +} // namespace input_method; + +// A class which provides information to virtual_keyboard.js. +class VirtualKeyboardManagerHandler : public OptionsPage2UIHandler { + public: + VirtualKeyboardManagerHandler(); + virtual ~VirtualKeyboardManagerHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + protected: + typedef std::multimap< + std::string, const input_method::VirtualKeyboard*> LayoutToKeyboard; + typedef std::map<GURL, const input_method::VirtualKeyboard*> UrlToKeyboard; + + // Returns true if |layout_to_keyboard| contains |layout| as a key, and the + // value for |layout| contains |url|. This function is protected for + // testability. + static bool ValidateUrl(const UrlToKeyboard& url_to_keyboard, + const std::string& layout, + const std::string& url); + + // Builds a list from |layout_to_keyboard| and |virtual_keyboard_user_pref|. + // See virtual_keyboard_list.js for an example of the format the list should + // take. This function is protected for testability. + static base::ListValue* CreateVirtualKeyboardList( + const LayoutToKeyboard& layout_to_keyboard, + const UrlToKeyboard& url_to_keyboard, + const base::DictionaryValue* virtual_keyboard_user_pref); + + private: + // Reads user pref and create a list using CreateVirtualKeyboardList(). + base::ListValue* GetVirtualKeyboardList(); + + // Handles chrome.send("updateVirtualKeyboardList") JS call. + // TODO(yusukes): This function should also be called when user pref is + // updated by chrome://settings page in other tab. + void UpdateVirtualKeyboardList(const base::ListValue* args); + + // Handles chrome.send("setVirtualKeyboardPreference") JS call. + void SetVirtualKeyboardPreference(const base::ListValue* args); + // Handles chrome.send("clearVirtualKeyboardPreference") JS call. + void ClearVirtualKeyboardPreference(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardManagerHandler); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_VIRTUAL_KEYBOARD_MANAGER_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler_unittest.cc b/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler_unittest.cc new file mode 100644 index 0000000..5783401 --- /dev/null +++ b/chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler_unittest.cc @@ -0,0 +1,550 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.h" + +#include <map> +#include <set> +#include <string> + +#include "base/logging.h" +#include "base/values.h" +#include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +typedef std::multimap< + std::string, const chromeos::input_method::VirtualKeyboard*> LayoutToKeyboard; +typedef std::map< + GURL, const chromeos::input_method::VirtualKeyboard*> UrlToKeyboard; + +template <size_t L> +std::set<std::string> CreateLayoutSet(const char* (&layouts)[L]) { + return std::set<std::string>(layouts, layouts + L); +} + +} // namespace + +namespace chromeos { + +class Testee : public VirtualKeyboardManagerHandler { + public: + // Change access rights. + using VirtualKeyboardManagerHandler::ValidateUrl; + using VirtualKeyboardManagerHandler::CreateVirtualKeyboardList; +}; + +TEST(VirtualKeyboardManagerHandler, TestValidateUrl) { + static const char* layouts1[] = { "a", "b" }; + static const char* layouts2[] = { "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts1), true); + input_method::VirtualKeyboard virtual_keyboard_2( + GURL("http://url2/"), "name 2", CreateLayoutSet(layouts2), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_2.url(), + virtual_keyboard_2.name(), + virtual_keyboard_2.supported_layouts(), + virtual_keyboard_2.is_system())); + + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(2U, url_to_keyboard.size()); + + EXPECT_TRUE(Testee::ValidateUrl(url_to_keyboard, "a", "http://url1/")); + EXPECT_TRUE(Testee::ValidateUrl(url_to_keyboard, "b", "http://url1/")); + EXPECT_TRUE(Testee::ValidateUrl(url_to_keyboard, "b", "http://url2/")); + + EXPECT_FALSE(Testee::ValidateUrl(url_to_keyboard, "a", "http://url3/")); + EXPECT_FALSE(Testee::ValidateUrl(url_to_keyboard, "b", "http://url3/")); + EXPECT_FALSE(Testee::ValidateUrl(url_to_keyboard, "c", "http://url1/")); + EXPECT_FALSE(Testee::ValidateUrl(url_to_keyboard, "c", "http://url2/")); +} + +TEST(VirtualKeyboardManagerHandler, TestSingleKeyboard) { + static const char* layouts[] = { "a", "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(arraysize(layouts), layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(1U, url_to_keyboard.size()); + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, NULL)); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(arraysize(layouts), keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); +} + +TEST(VirtualKeyboardManagerHandler, TestSingleKeyboardWithPref) { + static const char* layouts[] = { "a", "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(arraysize(layouts), layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(1U, url_to_keyboard.size()); + + // create pref object. + scoped_ptr<DictionaryValue> pref(new DictionaryValue); + pref->SetString("b", "http://url1/"); + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, pref.get())); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(arraysize(layouts), keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_TRUE(dictionary_value->GetString("preferredKeyboard", &string_value)); + EXPECT_EQ("http://url1/", string_value); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); +} + +TEST(VirtualKeyboardManagerHandler, TestSingleKeyboardWithTwoPrefs) { + static const char* layouts[] = { "a", "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(arraysize(layouts), layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(1U, url_to_keyboard.size()); + + // create pref object. + scoped_ptr<DictionaryValue> pref(new DictionaryValue); + pref->SetString("a", "http://url1/"); + pref->SetString("b", "http://url1/"); + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, pref.get())); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(arraysize(layouts), keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_TRUE(dictionary_value->GetString("preferredKeyboard", &string_value)); + EXPECT_EQ("http://url1/", string_value); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_TRUE(dictionary_value->GetString("preferredKeyboard", &string_value)); + EXPECT_EQ("http://url1/", string_value); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); +} + +TEST(VirtualKeyboardManagerHandler, TestSingleKeyboardWithBadPref1) { + static const char* layouts[] = { "a", "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(arraysize(layouts), layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(1U, url_to_keyboard.size()); + + // create pref object. + scoped_ptr<DictionaryValue> pref(new DictionaryValue); + pref->SetString("unknownlayout", "http://url1/"); + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, pref.get())); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(arraysize(layouts), keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); +} + +TEST(VirtualKeyboardManagerHandler, TestSingleKeyboardWithBadPref2) { + static const char* layouts[] = { "a", "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(arraysize(layouts), layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(1U, url_to_keyboard.size()); + + // create pref object. + scoped_ptr<DictionaryValue> pref(new DictionaryValue); + pref->SetString("a", "http://unknownurl/"); + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, pref.get())); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(arraysize(layouts), keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); +} + +TEST(VirtualKeyboardManagerHandler, TestSingleKeyboardWithBadPref3) { + static const char* layout1[] = { "a" }; + static const char* layout2[] = { "b" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layout1), true); + input_method::VirtualKeyboard virtual_keyboard_2( + GURL("http://url2/"), "name 2", CreateLayoutSet(layout2), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_2.url(), + virtual_keyboard_2.name(), + virtual_keyboard_2.supported_layouts(), + virtual_keyboard_2.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(2U, layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(2U, url_to_keyboard.size()); + + // create pref object. + scoped_ptr<DictionaryValue> pref(new DictionaryValue); + pref->SetString("a", "http://url2/"); // url2 does not support "a". + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, pref.get())); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(2U, keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url2/", string_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 2", string_value); +} + +TEST(VirtualKeyboardManagerHandler, TestMultipleKeyboards) { + static const char* layouts1[] = { "a", "b" }; + static const char* layouts2[] = { "c" }; + static const char* layouts3[] = { "b", "d" }; + input_method::VirtualKeyboard virtual_keyboard_1( + GURL("http://url1/"), "name 1", CreateLayoutSet(layouts1), true); + input_method::VirtualKeyboard virtual_keyboard_2( + GURL("http://url2/"), "name 2", CreateLayoutSet(layouts2), false); + input_method::VirtualKeyboard virtual_keyboard_3( + GURL("http://url3/"), "name 3", CreateLayoutSet(layouts3), true); + + input_method::VirtualKeyboardSelector selector; + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_1.url(), + virtual_keyboard_1.name(), + virtual_keyboard_1.supported_layouts(), + virtual_keyboard_1.is_system())); + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_2.url(), + virtual_keyboard_2.name(), + virtual_keyboard_2.supported_layouts(), + virtual_keyboard_2.is_system())); + ASSERT_TRUE(selector.AddVirtualKeyboard( + virtual_keyboard_3.url(), + virtual_keyboard_3.name(), + virtual_keyboard_3.supported_layouts(), + virtual_keyboard_3.is_system())); + + const LayoutToKeyboard& layout_to_keyboard = selector.layout_to_keyboard(); + ASSERT_EQ(arraysize(layouts1) + arraysize(layouts2) + arraysize(layouts3), + layout_to_keyboard.size()); + const UrlToKeyboard& url_to_keyboard = selector.url_to_keyboard(); + ASSERT_EQ(3U, url_to_keyboard.size()); + + scoped_ptr<ListValue> keyboards(Testee::CreateVirtualKeyboardList( + layout_to_keyboard, url_to_keyboard, NULL)); + ASSERT_TRUE(keyboards.get()); + ASSERT_EQ(4U /* a, b, c, and d */, keyboards->GetSize()); + + DictionaryValue* dictionary_value; + std::string string_value; + ListValue* list_value; + bool boolean_value = false; + + // Check the first element (for the layout "a"). + ASSERT_TRUE(keyboards->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("a", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetBoolean("isSystem", &boolean_value)); + EXPECT_TRUE(boolean_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + + // Check the second element (for the layout "b"). + ASSERT_TRUE(keyboards->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("b", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(2U, list_value->GetSize()); // keyboard1 and 3. + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url1/", string_value); + EXPECT_TRUE(dictionary_value->GetBoolean("isSystem", &boolean_value)); + EXPECT_TRUE(boolean_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 1", string_value); + ASSERT_TRUE(list_value->GetDictionary(1, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url3/", string_value); + EXPECT_TRUE(dictionary_value->GetBoolean("isSystem", &boolean_value)); + EXPECT_TRUE(boolean_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 3", string_value); + + // 3rd. + ASSERT_TRUE(keyboards->GetDictionary(2, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("c", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url2/", string_value); + EXPECT_TRUE(dictionary_value->GetBoolean("isSystem", &boolean_value)); + EXPECT_FALSE(boolean_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 2", string_value); + + // 4th. + ASSERT_TRUE(keyboards->GetDictionary(3, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("layout", &string_value)); + EXPECT_EQ("d", string_value); + EXPECT_TRUE(dictionary_value->GetString("layoutName", &string_value)); + EXPECT_FALSE(dictionary_value->GetString("preferredKeyboard", &string_value)); + ASSERT_TRUE(dictionary_value->GetList("supportedKeyboards", &list_value)); + ASSERT_EQ(1U, list_value->GetSize()); + ASSERT_TRUE(list_value->GetDictionary(0, &dictionary_value)); + EXPECT_TRUE(dictionary_value->GetString("url", &string_value)); + EXPECT_EQ("http://url3/", string_value); + EXPECT_TRUE(dictionary_value->GetBoolean("isSystem", &boolean_value)); + EXPECT_TRUE(boolean_value); + EXPECT_TRUE(dictionary_value->GetString("name", &string_value)); + EXPECT_EQ("name 3", string_value); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options2/clear_browser_data_handler.cc b/chrome/browser/ui/webui/options2/clear_browser_data_handler.cc new file mode 100644 index 0000000..306050e --- /dev/null +++ b/chrome/browser/ui/webui/options2/clear_browser_data_handler.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/clear_browser_data_handler.h" + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/string16.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/notification_details.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "ui/base/l10n/l10n_util.h" + +ClearBrowserDataHandler::ClearBrowserDataHandler() : remover_(NULL) { +} + +ClearBrowserDataHandler::~ClearBrowserDataHandler() { + if (remover_) + remover_->RemoveObserver(this); +} + +void ClearBrowserDataHandler::Initialize() { + clear_plugin_lso_data_enabled_.Init(prefs::kClearPluginLSODataEnabled, + Profile::FromWebUI(web_ui_)->GetPrefs(), + NULL); +} + +void ClearBrowserDataHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "clearBrowserDataLabel", IDS_CLEAR_BROWSING_DATA_LABEL }, + { "deleteBrowsingHistoryCheckbox", IDS_DEL_BROWSING_HISTORY_CHKBOX }, + { "deleteDownloadHistoryCheckbox", IDS_DEL_DOWNLOAD_HISTORY_CHKBOX }, + { "deleteCacheCheckbox", IDS_DEL_CACHE_CHKBOX }, + { "deleteCookiesCheckbox", IDS_DEL_COOKIES_CHKBOX }, + { "deleteCookiesFlashCheckbox", IDS_DEL_COOKIES_FLASH_CHKBOX }, + { "deletePasswordsCheckbox", IDS_DEL_PASSWORDS_CHKBOX }, + { "deleteFormDataCheckbox", IDS_DEL_FORM_DATA_CHKBOX }, + { "clearBrowserDataCommit", IDS_CLEAR_BROWSING_DATA_COMMIT }, + { "flashStorageSettings", IDS_FLASH_STORAGE_SETTINGS }, + { "flash_storage_url", IDS_FLASH_STORAGE_URL }, + { "clearDataDeleting", IDS_CLEAR_DATA_DELETING }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "clearBrowserDataOverlay", + IDS_CLEAR_BROWSING_DATA_TITLE); + + ListValue* time_list = new ListValue; + for (int i = 0; i < 5; i++) { + string16 label_string; + switch (i) { + case 0: + label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_HOUR); + break; + case 1: + label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_DAY); + break; + case 2: + label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_WEEK); + break; + case 3: + label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_4WEEKS); + break; + case 4: + label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_EVERYTHING); + break; + } + ListValue* option = new ListValue(); + option->Append(Value::CreateIntegerValue(i)); + option->Append(Value::CreateStringValue(label_string)); + time_list->Append(option); + } + localized_strings->Set("clearBrowserDataTimeList", time_list); +} + +void ClearBrowserDataHandler::RegisterMessages() { + // Setup handlers specific to this panel. + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("performClearBrowserData", + base::Bind(&ClearBrowserDataHandler::HandleClearBrowserData, + base::Unretained(this))); +} + +void ClearBrowserDataHandler::HandleClearBrowserData(const ListValue* value) { + Profile* profile = Profile::FromWebUI(web_ui_); + PrefService* prefs = profile->GetPrefs(); + + int remove_mask = 0; + if (prefs->GetBoolean(prefs::kDeleteBrowsingHistory)) + remove_mask |= BrowsingDataRemover::REMOVE_HISTORY; + if (prefs->GetBoolean(prefs::kDeleteDownloadHistory)) + remove_mask |= BrowsingDataRemover::REMOVE_DOWNLOADS; + if (prefs->GetBoolean(prefs::kDeleteCache)) + remove_mask |= BrowsingDataRemover::REMOVE_CACHE; + if (prefs->GetBoolean(prefs::kDeleteCookies)) { + int site_data_mask = BrowsingDataRemover::REMOVE_SITE_DATA; + // Don't try to clear LSO data if it's not supported. + if (!*clear_plugin_lso_data_enabled_) + site_data_mask &= ~BrowsingDataRemover::REMOVE_LSO_DATA; + remove_mask |= site_data_mask; + } + if (prefs->GetBoolean(prefs::kDeletePasswords)) + remove_mask |= BrowsingDataRemover::REMOVE_PASSWORDS; + if (prefs->GetBoolean(prefs::kDeleteFormData)) + remove_mask |= BrowsingDataRemover::REMOVE_FORM_DATA; + + int period_selected = prefs->GetInteger(prefs::kDeleteTimePeriod); + + base::FundamentalValue state(true); + web_ui_->CallJavascriptFunction("ClearBrowserDataOverlay.setClearingState", + state); + + // If we are still observing a previous data remover, we need to stop + // observing. + if (remover_) + remover_->RemoveObserver(this); + + // BrowsingDataRemover deletes itself when done. + remover_ = new BrowsingDataRemover(profile, + static_cast<BrowsingDataRemover::TimePeriod>(period_selected), + base::Time()); + remover_->AddObserver(this); + remover_->Remove(remove_mask); +} + +void ClearBrowserDataHandler::OnBrowsingDataRemoverDone() { + // No need to remove ourselves as an observer as BrowsingDataRemover deletes + // itself after we return. + remover_ = NULL; + DCHECK(web_ui_); + web_ui_->CallJavascriptFunction("ClearBrowserDataOverlay.doneClearing"); +} diff --git a/chrome/browser/ui/webui/options2/clear_browser_data_handler.h b/chrome/browser/ui/webui/options2/clear_browser_data_handler.h new file mode 100644 index 0000000..9793626 --- /dev/null +++ b/chrome/browser/ui/webui/options2/clear_browser_data_handler.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CLEAR_BROWSER_DATA_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CLEAR_BROWSER_DATA_HANDLER_H_ +#pragma once + +#include "chrome/browser/browsing_data_remover.h" +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +// Clear browser data handler page UI handler. +class ClearBrowserDataHandler : public OptionsPage2UIHandler, + public BrowsingDataRemover::Observer { + public: + ClearBrowserDataHandler(); + virtual ~ClearBrowserDataHandler(); + + // OptionsPage2UIHandler implementation. + virtual void Initialize() OVERRIDE; + + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + private: + // Javascript callback to start clearing data. + void HandleClearBrowserData(const ListValue* value); + + // Callback from BrowsingDataRemover. Closes the dialog. + virtual void OnBrowsingDataRemoverDone() OVERRIDE; + + // If non-null it means removal is in progress. BrowsingDataRemover takes care + // of deleting itself when done. + BrowsingDataRemover* remover_; + + // Keeps track of whether clearing LSO data is supported. + BooleanPrefMember clear_plugin_lso_data_enabled_; + + DISALLOW_COPY_AND_ASSIGN(ClearBrowserDataHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CLEAR_BROWSER_DATA_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/content_options_browsertest.js b/chrome/browser/ui/webui/options2/content_options_browsertest.js new file mode 100644 index 0000000..605660a --- /dev/null +++ b/chrome/browser/ui/webui/options2/content_options_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for content options WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function ContentOptionsWebUITest() {} + +ContentOptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to content options. + **/ + browsePreload: 'chrome://settings/content', +}; + +// Test opening the content options has correct location. +TEST_F('ContentOptionsWebUITest', 'testOpenContentOptions', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/content_settings_exception_area_browsertest.js b/chrome/browser/ui/webui/options2/content_settings_exception_area_browsertest.js new file mode 100644 index 0000000..33b3fd2 --- /dev/null +++ b/chrome/browser/ui/webui/options2/content_settings_exception_area_browsertest.js @@ -0,0 +1,26 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for content settings exception area WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function ContentSettingsExceptionAreaWebUITest() {} + +ContentSettingsExceptionAreaWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the content settings exception area. + **/ + browsePreload: 'chrome://settings/contentExceptions', +}; + +// Test opening the content settings exception area has correct location. +TEST_F('ContentSettingsExceptionAreaWebUITest', + 'testOpenContentSettingsExceptionArea', + function() { + assertEquals(this.browsePreload, document.location.href); + }); diff --git a/chrome/browser/ui/webui/options2/content_settings_handler.cc b/chrome/browser/ui/webui/options2/content_settings_handler.cc new file mode 100644 index 0000000..8b45b28 --- /dev/null +++ b/chrome/browser/ui/webui/options2/content_settings_handler.cc @@ -0,0 +1,877 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/content_settings_handler.h" + +#include <map> +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/content_settings/content_settings_details.h" +#include "chrome/browser/content_settings/content_settings_utils.h" +#include "chrome/browser/content_settings/host_content_settings_map.h" +#include "chrome/browser/custom_handlers/protocol_handler_registry.h" +#include "chrome/browser/notifications/desktop_notification_service.h" +#include "chrome/browser/notifications/desktop_notification_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/content_settings.h" +#include "chrome/common/content_settings_pattern.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" +#include "content/public/common/content_switches.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +struct ContentSettingsTypeNameEntry { + ContentSettingsType type; + const char* name; +}; + +typedef std::map<ContentSettingsPattern, ContentSetting> OnePatternSettings; +typedef std::map<ContentSettingsPattern, OnePatternSettings> + AllPatternsSettings; + +const char* kDisplayPattern = "displayPattern"; +const char* kSetting = "setting"; +const char* kOrigin = "origin"; +const char* kSource = "source"; +const char* kEmbeddingOrigin = "embeddingOrigin"; + +const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { + {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"}, + {CONTENT_SETTINGS_TYPE_IMAGES, "images"}, + {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"}, + {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"}, + {CONTENT_SETTINGS_TYPE_POPUPS, "popups"}, + {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"}, + {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"}, + {CONTENT_SETTINGS_TYPE_INTENTS, "intents"}, + {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"}, + {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"}, + {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"}, +}; +COMPILE_ASSERT(arraysize(kContentSettingsTypeGroupNames) == + CONTENT_SETTINGS_NUM_TYPES, + MISSING_CONTENT_SETTINGS_TYPE); + +ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) { + for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { + if (name == kContentSettingsTypeGroupNames[i].name) + return kContentSettingsTypeGroupNames[i].type; + } + + NOTREACHED() << name << " is not a recognized content settings type."; + return CONTENT_SETTINGS_TYPE_DEFAULT; +} + +std::string ContentSettingToString(ContentSetting setting) { + switch (setting) { + case CONTENT_SETTING_ALLOW: + return "allow"; + case CONTENT_SETTING_ASK: + return "ask"; + case CONTENT_SETTING_BLOCK: + return "block"; + case CONTENT_SETTING_SESSION_ONLY: + return "session"; + case CONTENT_SETTING_DEFAULT: + return "default"; + case CONTENT_SETTING_NUM_SETTINGS: + NOTREACHED(); + } + + return ""; +} + +ContentSetting ContentSettingFromString(const std::string& name) { + if (name == "allow") + return CONTENT_SETTING_ALLOW; + if (name == "ask") + return CONTENT_SETTING_ASK; + if (name == "block") + return CONTENT_SETTING_BLOCK; + if (name == "session") + return CONTENT_SETTING_SESSION_ONLY; + + NOTREACHED() << name << " is not a recognized content setting."; + return CONTENT_SETTING_DEFAULT; +} + +std::string GeolocationExceptionToString( + const ContentSettingsPattern& origin, + const ContentSettingsPattern& embedding_origin) { + if (origin == embedding_origin) + return origin.ToString(); + + // TODO(estade): the page needs to use CSS to indent the string. + std::string indent(" "); + + if (embedding_origin == ContentSettingsPattern::Wildcard()) { + // NOTE: As long as the user cannot add/edit entries from the exceptions + // dialog, it's impossible to actually have a non-default setting for some + // origin "embedded on any other site", so this row will never appear. If + // we add the ability to add/edit exceptions, we'll need to decide when to + // display this and how "removing" it will function. + return indent + + l10n_util::GetStringUTF8(IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ANY_OTHER); + } + + return indent + l10n_util::GetStringFUTF8( + IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST, + UTF8ToUTF16(embedding_origin.ToString())); +} + +// Create a DictionaryValue* that will act as a data source for a single row +// in a HostContentSettingsMap-controlled exceptions table (e.g., cookies). +// Ownership of the pointer is passed to the caller. +DictionaryValue* GetExceptionForPage( + const ContentSettingsPattern& pattern, + ContentSetting setting, + std::string provider_name) { + DictionaryValue* exception = new DictionaryValue(); + exception->SetString(kDisplayPattern, pattern.ToString()); + exception->SetString(kSetting, ContentSettingToString(setting)); + exception->SetString(kSource, provider_name); + return exception; +} + +// Create a DictionaryValue* that will act as a data source for a single row +// in the Geolocation exceptions table. Ownership of the pointer is passed to +// the caller. +DictionaryValue* GetGeolocationExceptionForPage( + const ContentSettingsPattern& origin, + const ContentSettingsPattern& embedding_origin, + ContentSetting setting) { + DictionaryValue* exception = new DictionaryValue(); + exception->SetString(kDisplayPattern, + GeolocationExceptionToString(origin, embedding_origin)); + exception->SetString(kSetting, ContentSettingToString(setting)); + exception->SetString(kOrigin, origin.ToString()); + exception->SetString(kEmbeddingOrigin, embedding_origin.ToString()); + return exception; +} + +// Create a DictionaryValue* that will act as a data source for a single row +// in the desktop notifications exceptions table. Ownership of the pointer is +// passed to the caller. +DictionaryValue* GetNotificationExceptionForPage( + const ContentSettingsPattern& pattern, + ContentSetting setting, + const std::string& provider_name) { + DictionaryValue* exception = new DictionaryValue(); + exception->SetString(kDisplayPattern, pattern.ToString()); + exception->SetString(kSetting, ContentSettingToString(setting)); + exception->SetString(kOrigin, pattern.ToString()); + exception->SetString(kSource, provider_name); + return exception; +} + +} // namespace + +ContentSettingsHandler::ContentSettingsHandler() { +} + +ContentSettingsHandler::~ContentSettingsHandler() { +} + +void ContentSettingsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "content_exceptions", IDS_COOKIES_EXCEPTIONS_BUTTON }, + { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON }, + { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON }, + { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON }, + { "askException", IDS_EXCEPTIONS_ASK_BUTTON }, + { "addExceptionRow", IDS_EXCEPTIONS_ADD_BUTTON }, + { "removeExceptionRow", IDS_EXCEPTIONS_REMOVE_BUTTON }, + { "editExceptionRow", IDS_EXCEPTIONS_EDIT_BUTTON }, + { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL }, + { "examplePattern", IDS_EXCEPTIONS_PATTERN_EXAMPLE }, + { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS }, + { "manage_exceptions", IDS_EXCEPTIONS_MANAGE }, + { "manage_handlers", IDS_HANDLERS_MANAGE }, + { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER }, + { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER }, + // Cookies filter. + { "cookies_tab_label", IDS_COOKIES_TAB_LABEL }, + { "cookies_header", IDS_COOKIES_HEADER }, + { "cookies_allow", IDS_COOKIES_ALLOW_RADIO }, + { "cookies_block", IDS_COOKIES_BLOCK_RADIO }, + { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO }, + { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX }, + { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX }, + { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX }, + { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON }, + { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS }, + { "flash_storage_url", IDS_FLASH_STORAGE_URL }, + // Image filter. + { "images_tab_label", IDS_IMAGES_TAB_LABEL }, + { "images_header", IDS_IMAGES_HEADER }, + { "images_allow", IDS_IMAGES_LOAD_RADIO }, + { "images_block", IDS_IMAGES_NOLOAD_RADIO }, + // JavaScript filter. + { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL }, + { "javascript_header", IDS_JAVASCRIPT_HEADER }, + { "javascript_allow", IDS_JS_ALLOW_RADIO }, + { "javascript_block", IDS_JS_DONOTALLOW_RADIO }, + // Plug-ins filter. + { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL }, + { "plugins_header", IDS_PLUGIN_HEADER }, + { "plugins_ask", IDS_PLUGIN_ASK_RADIO }, + { "plugins_allow", IDS_PLUGIN_LOAD_RADIO }, + { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO }, + { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE }, + // Pop-ups filter. + { "popups_tab_label", IDS_POPUP_TAB_LABEL }, + { "popups_header", IDS_POPUP_HEADER }, + { "popups_allow", IDS_POPUP_ALLOW_RADIO }, + { "popups_block", IDS_POPUP_BLOCK_RADIO }, + // Location filter. + { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL }, + { "location_header", IDS_GEOLOCATION_HEADER }, + { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO }, + { "location_ask", IDS_GEOLOCATION_ASK_RADIO }, + { "location_block", IDS_GEOLOCATION_BLOCK_RADIO }, + // Notifications filter. + { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL }, + { "notifications_header", IDS_NOTIFICATIONS_HEADER }, + { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO }, + { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO }, + { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO }, + // Intents filter. + { "intentsTabLabel", IDS_INTENTS_TAB_LABEL }, + { "intentsAllow", IDS_INTENTS_ALLOW_RADIO }, + { "intentsAsk", IDS_INTENTS_ASK_RADIO }, + { "intentsBlock", IDS_INTENTS_BLOCK_RADIO }, + { "intents_header", IDS_INTENTS_HEADER }, + // Fullscreen filter. + { "fullscreen_tab_label", IDS_FULLSCREEN_TAB_LABEL }, + { "fullscreen_header", IDS_FULLSCREEN_HEADER }, + // Mouse Lock filter. + { "mouselock_tab_label", IDS_MOUSE_LOCK_TAB_LABEL }, + { "mouselock_header", IDS_MOUSE_LOCK_HEADER }, + { "mouselock_allow", IDS_MOUSE_LOCK_ALLOW_RADIO }, + { "mouselock_ask", IDS_MOUSE_LOCK_ASK_RADIO }, + { "mouselock_block", IDS_MOUSE_LOCK_BLOCK_RADIO }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "contentSettingsPage", + IDS_CONTENT_SETTINGS_TITLE); + localized_strings->SetBoolean("enable_click_to_play", + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableClickToPlay)); + localized_strings->SetBoolean("enable_web_intents", + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableWebIntents)); +} + +void ContentSettingsHandler::Initialize() { + notification_registrar_.Add( + this, chrome::NOTIFICATION_PROFILE_CREATED, + content::NotificationService::AllSources()); + notification_registrar_.Add( + this, chrome::NOTIFICATION_PROFILE_DESTROYED, + content::NotificationService::AllSources()); + + UpdateHandlersEnabledRadios(); + UpdateAllExceptionsViewsFromModel(); + notification_registrar_.Add( + this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED, + content::NotificationService::AllSources()); + notification_registrar_.Add( + this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED, + content::NotificationService::AllSources()); + Profile* profile = Profile::FromWebUI(web_ui_); + notification_registrar_.Add( + this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, + content::Source<Profile>(profile)); + + PrefService* prefs = profile->GetPrefs(); + pref_change_registrar_.Init(prefs); + pref_change_registrar_.Add(prefs::kGeolocationContentSettings, this); +} + +void ContentSettingsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_PROFILE_DESTROYED: { + if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) { + web_ui_->CallJavascriptFunction( + "ContentSettingsExceptionsArea.OTRProfileDestroyed"); + } + break; + } + + case chrome::NOTIFICATION_PROFILE_CREATED: { + if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) + UpdateAllOTRExceptionsViewsFromModel(); + break; + } + + case chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED: { + // Filter out notifications from other profiles. + HostContentSettingsMap* map = + content::Source<HostContentSettingsMap>(source).ptr(); + if (map != GetContentSettingsMap() && + map != GetOTRContentSettingsMap()) + break; + + const ContentSettingsDetails* settings_details = + content::Details<const ContentSettingsDetails>(details).ptr(); + + // TODO(estade): we pretend update_all() is always true. + if (settings_details->update_all_types()) + UpdateAllExceptionsViewsFromModel(); + else + UpdateExceptionsViewFromModel(settings_details->type()); + break; + } + + case chrome::NOTIFICATION_PREF_CHANGED: { + const std::string& pref_name = + *content::Details<std::string>(details).ptr(); + if (pref_name == prefs::kGeolocationContentSettings) + UpdateGeolocationExceptionsView(); + break; + } + + case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: { + UpdateNotificationExceptionsView(); + break; + } + + case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: { + UpdateHandlersEnabledRadios(); + break; + } + + default: + OptionsPage2UIHandler::Observe(type, source, details); + } +} + +void ContentSettingsHandler::UpdateSettingDefaultFromModel( + ContentSettingsType type) { + DictionaryValue filter_settings; + std::string provider_id; + filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value", + GetSettingDefaultFromModel(type, &provider_id)); + filter_settings.SetString( + ContentSettingsTypeToGroupName(type) + ".managedBy", + provider_id); + + web_ui_->CallJavascriptFunction( + "ContentSettings.setContentFilterSettingsValue", filter_settings); +} + +std::string ContentSettingsHandler::GetSettingDefaultFromModel( + ContentSettingsType type, std::string* provider_id) { + Profile* profile = Profile::FromWebUI(web_ui_); + ContentSetting default_setting; + if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + default_setting = + DesktopNotificationServiceFactory::GetForProfile(profile)-> + GetDefaultContentSetting(provider_id); + } else { + default_setting = + profile->GetHostContentSettingsMap()-> + GetDefaultContentSetting(type, provider_id); + } + + return ContentSettingToString(default_setting); +} + +void ContentSettingsHandler::UpdateHandlersEnabledRadios() { +#if defined(ENABLE_REGISTER_PROTOCOL_HANDLER) + DCHECK(web_ui_); + base::FundamentalValue handlers_enabled( + GetProtocolHandlerRegistry()->enabled()); + + web_ui_->CallJavascriptFunction("ContentSettings.updateHandlersEnabledRadios", + handlers_enabled); +#endif // defined(ENABLE_REGISTER_PROTOCOL_HANDLER) +} + +void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() { + for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; + type < CONTENT_SETTINGS_NUM_TYPES; ++type) { + // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE + // is supposed to be set by policy only. Hence there is no user facing UI + // for this content type and we skip it here. + if (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE) + continue; + UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type)); + } +} + +void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() { + for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; + type < CONTENT_SETTINGS_NUM_TYPES; ++type) { + UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type)); + } +} + +void ContentSettingsHandler::UpdateExceptionsViewFromModel( + ContentSettingsType type) { + // Skip updating intents unless it's enabled from the command line. + if (type == CONTENT_SETTINGS_TYPE_INTENTS && + !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableWebIntents)) + return; + + switch (type) { + case CONTENT_SETTINGS_TYPE_GEOLOCATION: + UpdateGeolocationExceptionsView(); + break; + case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: + UpdateNotificationExceptionsView(); + break; + default: + UpdateExceptionsViewFromHostContentSettingsMap(type); + break; + } +} + +void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel( + ContentSettingsType type) { + switch (type) { + case CONTENT_SETTINGS_TYPE_GEOLOCATION: + case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: + case CONTENT_SETTINGS_TYPE_INTENTS: + case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: + break; + default: + UpdateExceptionsViewFromOTRHostContentSettingsMap(type); + break; + } +} + +void ContentSettingsHandler::UpdateGeolocationExceptionsView() { + Profile* profile = Profile::FromWebUI(web_ui_); + HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); + + ContentSettingsForOneType all_settings; + map->GetSettingsForOneType( + CONTENT_SETTINGS_TYPE_GEOLOCATION, + std::string(), + &all_settings); + + // Group geolocation settings by primary_pattern. + AllPatternsSettings all_patterns_settings; + for (ContentSettingsForOneType::iterator i = + all_settings.begin(); + i != all_settings.end(); + ++i) { + // Don't add default settings. + if (i->primary_pattern == ContentSettingsPattern::Wildcard() && + i->secondary_pattern == ContentSettingsPattern::Wildcard() && + i->source != "preferences") { + continue; + } + all_patterns_settings[i->primary_pattern][i->secondary_pattern] = + i->setting; + } + + ListValue exceptions; + for (AllPatternsSettings::iterator i = all_patterns_settings.begin(); + i != all_patterns_settings.end(); + ++i) { + const ContentSettingsPattern& primary_pattern = i->first; + const OnePatternSettings& one_settings = i->second; + + OnePatternSettings::const_iterator parent = + one_settings.find(primary_pattern); + + // Add the "parent" entry for the non-embedded setting. + ContentSetting parent_setting = + parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second; + exceptions.Append(GetGeolocationExceptionForPage(primary_pattern, + primary_pattern, + parent_setting)); + + // Add the "children" for any embedded settings. + for (OnePatternSettings::const_iterator j = one_settings.begin(); + j != one_settings.end(); + ++j) { + // Skip the non-embedded setting which we already added above. + if (j == parent) + continue; + + exceptions.Append( + GetGeolocationExceptionForPage(primary_pattern, j->first, j->second)); + } + } + + StringValue type_string( + ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION)); + web_ui_->CallJavascriptFunction("ContentSettings.setExceptions", + type_string, exceptions); + + // This is mainly here to keep this function ideologically parallel to + // UpdateExceptionsViewFromHostContentSettingsMap(). + UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION); +} + +void ContentSettingsHandler::UpdateNotificationExceptionsView() { + Profile* profile = Profile::FromWebUI(web_ui_); + DesktopNotificationService* service = + DesktopNotificationServiceFactory::GetForProfile(profile); + + ContentSettingsForOneType settings; + service->GetNotificationsSettings(&settings); + + ListValue exceptions; + for (ContentSettingsForOneType::const_iterator i = + settings.begin(); + i != settings.end(); + ++i) { + // Don't add default settings. + if (i->primary_pattern == ContentSettingsPattern::Wildcard() && + i->secondary_pattern == ContentSettingsPattern::Wildcard() && + i->source != "preferences") { + continue; + } + + exceptions.Append( + GetNotificationExceptionForPage(i->primary_pattern, i->setting, + i->source)); + } + + StringValue type_string( + ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); + web_ui_->CallJavascriptFunction("ContentSettings.setExceptions", + type_string, exceptions); + + // This is mainly here to keep this function ideologically parallel to + // UpdateExceptionsViewFromHostContentSettingsMap(). + UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); +} + +void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap( + ContentSettingsType type) { + ContentSettingsForOneType entries; + GetContentSettingsMap()->GetSettingsForOneType(type, "", &entries); + + ListValue exceptions; + for (size_t i = 0; i < entries.size(); ++i) { + // Skip default settings from extensions and policy, and the default content + // settings; all of them will affect the default setting UI. + if (entries[i].primary_pattern == ContentSettingsPattern::Wildcard() && + entries[i].secondary_pattern == ContentSettingsPattern::Wildcard() && + entries[i].source != "preference") { + continue; + } + // The content settings UI does not support secondary content settings + // pattern yet. For content settings set through the content settings UI the + // secondary pattern is by default a wildcard pattern. Hence users are not + // able to modify content settings with a secondary pattern other than the + // wildcard pattern. So only show settings that the user is able to modify. + // TODO(bauerb): Support a read-only view for those patterns. + if (entries[i].secondary_pattern == ContentSettingsPattern::Wildcard()) { + exceptions.Append( + GetExceptionForPage(entries[i].primary_pattern, entries[i].setting, + entries[i].source)); + } else { + LOG(ERROR) << "Secondary content settings patterns are not " + << "supported by the content settings UI"; + } + } + + StringValue type_string(ContentSettingsTypeToGroupName(type)); + web_ui_->CallJavascriptFunction("ContentSettings.setExceptions", type_string, + exceptions); + + UpdateExceptionsViewFromOTRHostContentSettingsMap(type); + + // TODO(koz): The default for fullscreen is always 'ask'. + // http://crbug.com/104683 + if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN) + return; + + // The default may also have changed (we won't get a separate notification). + // If it hasn't changed, this call will be harmless. + UpdateSettingDefaultFromModel(type); +} + +void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap( + ContentSettingsType type) { + const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap(); + if (!otr_settings_map) + return; + + ContentSettingsForOneType otr_entries; + otr_settings_map->GetSettingsForOneType(type, "", &otr_entries); + + ListValue otr_exceptions; + for (size_t i = 0; i < otr_entries.size(); ++i) { + // Off-the-record HostContentSettingsMap contains incognito content settings + // as well as normal content settings. Here, we use the incongnito settings + // only. + if (!otr_entries[i].incognito) + continue; + // The content settings UI does not support secondary content settings + // pattern yet. For content settings set through the content settings UI the + // secondary pattern is by default a wildcard pattern. Hence users are not + // able to modify content settings with a secondary pattern other than the + // wildcard pattern. So only show settings that the user is able to modify. + // TODO(bauerb): Support a read-only view for those patterns. + if (otr_entries[i].secondary_pattern == + ContentSettingsPattern::Wildcard()) { + otr_exceptions.Append( + GetExceptionForPage(otr_entries[i].primary_pattern, + otr_entries[i].setting, + otr_entries[i].source)); + } else { + LOG(ERROR) << "Secondary content settings patterns are not " + << "supported by the content settings UI"; + } + } + + StringValue type_string(ContentSettingsTypeToGroupName(type)); + web_ui_->CallJavascriptFunction("ContentSettings.setOTRExceptions", + type_string, otr_exceptions); +} + +void ContentSettingsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("setContentFilter", + base::Bind(&ContentSettingsHandler::SetContentFilter, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeException", + base::Bind(&ContentSettingsHandler::RemoveException, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setException", + base::Bind(&ContentSettingsHandler::SetException, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("checkExceptionPatternValidity", + base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity, + base::Unretained(this))); +} + +void ContentSettingsHandler::SetContentFilter(const ListValue* args) { + DCHECK_EQ(2U, args->GetSize()); + std::string group, setting; + if (!(args->GetString(0, &group) && + args->GetString(1, &setting))) { + NOTREACHED(); + return; + } + + ContentSetting default_setting = ContentSettingFromString(setting); + ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group); + if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + Profile* profile = Profile::FromWebUI(web_ui_); + DesktopNotificationServiceFactory::GetForProfile(profile)-> + SetDefaultContentSetting(default_setting); + } else { + GetContentSettingsMap()-> + SetDefaultContentSetting(content_type, default_setting); + } + switch (content_type) { + case CONTENT_SETTINGS_TYPE_COOKIES: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultCookieSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_IMAGES: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultImagesSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_JAVASCRIPT: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultJavaScriptSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_PLUGINS: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultPluginsSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_POPUPS: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultPopupsSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultNotificationsSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_GEOLOCATION: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultGeolocationSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_INTENTS: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultHandlersSettingChanged")); + break; + case CONTENT_SETTINGS_TYPE_MOUSELOCK: + UserMetrics::RecordAction( + UserMetricsAction("Options_DefaultMouseLockSettingChanged")); + break; + default: + break; + } +} + +void ContentSettingsHandler::RemoveException(const ListValue* args) { + size_t arg_i = 0; + std::string type_string; + CHECK(args->GetString(arg_i++, &type_string)); + + Profile* profile = Profile::FromWebUI(web_ui_); + ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); + if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) { + std::string origin; + std::string embedding_origin; + bool rv = args->GetString(arg_i++, &origin); + DCHECK(rv); + rv = args->GetString(arg_i++, &embedding_origin); + DCHECK(rv); + + profile->GetHostContentSettingsMap()-> + SetContentSetting(ContentSettingsPattern::FromString(origin), + ContentSettingsPattern::FromString(embedding_origin), + CONTENT_SETTINGS_TYPE_GEOLOCATION, + std::string(), + CONTENT_SETTING_DEFAULT); + } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + std::string origin; + std::string setting; + bool rv = args->GetString(arg_i++, &origin); + DCHECK(rv); + rv = args->GetString(arg_i++, &setting); + DCHECK(rv); + ContentSetting content_setting = ContentSettingFromString(setting); + + DCHECK(content_setting == CONTENT_SETTING_ALLOW || + content_setting == CONTENT_SETTING_BLOCK); + DesktopNotificationServiceFactory::GetForProfile(profile)-> + ClearSetting(ContentSettingsPattern::FromString(origin)); + } else { + std::string mode; + bool rv = args->GetString(arg_i++, &mode); + DCHECK(rv); + + std::string pattern; + rv = args->GetString(arg_i++, &pattern); + DCHECK(rv); + + HostContentSettingsMap* settings_map = + mode == "normal" ? GetContentSettingsMap() : + GetOTRContentSettingsMap(); + // The settings map could be null if the mode was OTR but the OTR profile + // got destroyed before we received this message. + if (settings_map) { + settings_map->SetContentSetting( + ContentSettingsPattern::FromString(pattern), + ContentSettingsPattern::Wildcard(), + ContentSettingsTypeFromGroupName(type_string), + "", + CONTENT_SETTING_DEFAULT); + } + } +} + +void ContentSettingsHandler::SetException(const ListValue* args) { + size_t arg_i = 0; + std::string type_string; + CHECK(args->GetString(arg_i++, &type_string)); + std::string mode; + CHECK(args->GetString(arg_i++, &mode)); + std::string pattern; + CHECK(args->GetString(arg_i++, &pattern)); + std::string setting; + CHECK(args->GetString(arg_i++, &setting)); + + ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); + if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION || + type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + NOTREACHED(); + return; + } + + HostContentSettingsMap* settings_map = + mode == "normal" ? GetContentSettingsMap() : + GetOTRContentSettingsMap(); + + // The settings map could be null if the mode was OTR but the OTR profile + // got destroyed before we received this message. + if (!settings_map) + return; + settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern), + ContentSettingsPattern::Wildcard(), + type, + "", + ContentSettingFromString(setting)); +} + +void ContentSettingsHandler::CheckExceptionPatternValidity( + const ListValue* args) { + size_t arg_i = 0; + Value* type; + CHECK(args->Get(arg_i++, &type)); + std::string mode_string; + CHECK(args->GetString(arg_i++, &mode_string)); + std::string pattern_string; + CHECK(args->GetString(arg_i++, &pattern_string)); + + ContentSettingsPattern pattern = + ContentSettingsPattern::FromString(pattern_string); + + scoped_ptr<Value> mode_value(Value::CreateStringValue(mode_string)); + scoped_ptr<Value> pattern_value(Value::CreateStringValue(pattern_string)); + scoped_ptr<Value> valid_value(Value::CreateBooleanValue(pattern.IsValid())); + + web_ui_->CallJavascriptFunction( + "ContentSettings.patternValidityCheckComplete", + *type, + *mode_value.get(), + *pattern_value.get(), + *valid_value.get()); +} + +// static +std::string ContentSettingsHandler::ContentSettingsTypeToGroupName( + ContentSettingsType type) { + for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { + if (type == kContentSettingsTypeGroupNames[i].type) + return kContentSettingsTypeGroupNames[i].name; + } + + NOTREACHED(); + return std::string(); +} + +HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() { + return Profile::FromWebUI(web_ui_)->GetHostContentSettingsMap(); +} + +ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() { + return Profile::FromWebUI(web_ui_)->GetProtocolHandlerRegistry(); +} + +HostContentSettingsMap* + ContentSettingsHandler::GetOTRContentSettingsMap() { + Profile* profile = Profile::FromWebUI(web_ui_); + if (profile->HasOffTheRecordProfile()) + return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap(); + return NULL; +} diff --git a/chrome/browser/ui/webui/options2/content_settings_handler.h b/chrome/browser/ui/webui/options2/content_settings_handler.h new file mode 100644 index 0000000..3678344 --- /dev/null +++ b/chrome/browser/ui/webui/options2/content_settings_handler.h @@ -0,0 +1,113 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CONTENT_SETTINGS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CONTENT_SETTINGS_HANDLER_H_ +#pragma once + +#include "chrome/browser/plugin_data_remover_helper.h" +#include "chrome/browser/prefs/pref_change_registrar.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "chrome/common/content_settings_types.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +class HostContentSettingsMap; +class ProtocolHandlerRegistry; + +class ContentSettingsHandler : public OptionsPage2UIHandler { + public: + ContentSettingsHandler(); + virtual ~ContentSettingsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + + virtual void Initialize() OVERRIDE; + + virtual void RegisterMessages() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Gets a string identifier for the group name, for use in HTML. + static std::string ContentSettingsTypeToGroupName(ContentSettingsType type); + + private: + // Functions that call into the page ----------------------------------------- + + // Updates the page with the default settings (allow, ask, block, etc.) + void UpdateSettingDefaultFromModel(ContentSettingsType type); + + // Clobbers and rebuilds the specific content setting type exceptions table. + void UpdateExceptionsViewFromModel(ContentSettingsType type); + // Clobbers and rebuilds the specific content setting type exceptions + // OTR table. + void UpdateOTRExceptionsViewFromModel(ContentSettingsType type); + // Clobbers and rebuilds all the exceptions tables in the page (both normal + // and OTR tables). + void UpdateAllExceptionsViewsFromModel(); + // As above, but only OTR tables. + void UpdateAllOTRExceptionsViewsFromModel(); + // Clobbers and rebuilds just the geolocation exception table. + void UpdateGeolocationExceptionsView(); + // Clobbers and rebuilds just the desktop notification exception table. + void UpdateNotificationExceptionsView(); + // Clobbers and rebuilds an exception table that's managed by the host content + // settings map. + void UpdateExceptionsViewFromHostContentSettingsMap(ContentSettingsType type); + // As above, but acts on the OTR table for the content setting type. + void UpdateExceptionsViewFromOTRHostContentSettingsMap( + ContentSettingsType type); + // Updates the radio buttons for enabling / disabling handlers. + void UpdateHandlersEnabledRadios(); + + // Callbacks used by the page ------------------------------------------------ + + // Sets the default value for a specific content type. |args| includes the + // content type and a string describing the new default the user has + // chosen. + void SetContentFilter(const ListValue* args); + + // Removes the given row from the table. The first entry in |args| is the + // content type, and the rest of the arguments depend on the content type + // to be removed. + void RemoveException(const ListValue* args); + + // Changes the value of an exception. Called after the user is done editing an + // exception. + void SetException(const ListValue* args); + + // Called to decide whether a given pattern is valid, or if it should be + // rejected. Called while the user is editing an exception pattern. + void CheckExceptionPatternValidity(const ListValue* args); + + // Utility functions --------------------------------------------------------- + + // Gets the HostContentSettingsMap for the normal profile. + HostContentSettingsMap* GetContentSettingsMap(); + + // Gets the HostContentSettingsMap for the incognito profile, or NULL if there + // is no active incognito session. + HostContentSettingsMap* GetOTRContentSettingsMap(); + + // Gets the default setting in string form. If |provider_id| is not NULL, the + // id of the provider which provided the default setting is assigned to it. + std::string GetSettingDefaultFromModel(ContentSettingsType type, + std::string* provider_id); + + // Gets the ProtocolHandlerRegistry for the normal profile. + ProtocolHandlerRegistry* GetProtocolHandlerRegistry(); + + // Member variables --------------------------------------------------------- + + content::NotificationRegistrar notification_registrar_; + PrefChangeRegistrar pref_change_registrar_; + + DISALLOW_COPY_AND_ASSIGN(ContentSettingsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CONTENT_SETTINGS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/cookies_view_browsertest.js b/chrome/browser/ui/webui/options2/cookies_view_browsertest.js new file mode 100644 index 0000000..43213cb --- /dev/null +++ b/chrome/browser/ui/webui/options2/cookies_view_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for cookies view WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function CookiesViewWebUITest() {} + +CookiesViewWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the cookies view. + **/ + browsePreload: 'chrome://settings/cookies', +}; + +// Test opening the cookies view has correct location. +TEST_F('CookiesViewWebUITest', 'testOpenCookiesView', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/cookies_view_handler.cc b/chrome/browser/ui/webui/options2/cookies_view_handler.cc new file mode 100644 index 0000000..6d86eb2 --- /dev/null +++ b/chrome/browser/ui/webui/options2/cookies_view_handler.cc @@ -0,0 +1,222 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/cookies_view_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browsing_data_appcache_helper.h" +#include "chrome/browser/browsing_data_cookie_helper.h" +#include "chrome/browser/browsing_data_database_helper.h" +#include "chrome/browser/browsing_data_file_system_helper.h" +#include "chrome/browser/browsing_data_indexed_db_helper.h" +#include "chrome/browser/browsing_data_quota_helper.h" +#include "chrome/browser/browsing_data_local_storage_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/cookies_tree_model_util.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +CookiesViewHandler::CookiesViewHandler() : batch_update_(false) { +} + +CookiesViewHandler::~CookiesViewHandler() { +} + +void CookiesViewHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "label_cookie_name", IDS_COOKIES_COOKIE_NAME_LABEL }, + { "label_cookie_content", IDS_COOKIES_COOKIE_CONTENT_LABEL }, + { "label_cookie_domain", IDS_COOKIES_COOKIE_DOMAIN_LABEL }, + { "label_cookie_path", IDS_COOKIES_COOKIE_PATH_LABEL }, + { "label_cookie_send_for", IDS_COOKIES_COOKIE_SENDFOR_LABEL }, + { "label_cookie_accessible_to_script", + IDS_COOKIES_COOKIE_ACCESSIBLE_TO_SCRIPT_LABEL }, + { "label_cookie_created", IDS_COOKIES_COOKIE_CREATED_LABEL }, + { "label_cookie_expires", IDS_COOKIES_COOKIE_EXPIRES_LABEL }, + { "label_webdb_desc", IDS_COOKIES_WEB_DATABASE_DESCRIPTION_LABEL }, + { "label_local_storage_size", + IDS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL }, + { "label_local_storage_last_modified", + IDS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL }, + { "label_local_storage_origin", IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL }, + { "label_indexed_db_size", IDS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL }, + { "label_indexed_db_last_modified", + IDS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL }, + { "label_indexed_db_origin", IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL }, + { "label_app_cache_manifest", + IDS_COOKIES_APPLICATION_CACHE_MANIFEST_LABEL }, + { "label_cookie_last_accessed", IDS_COOKIES_LAST_ACCESSED_LABEL }, + { "cookie_domain", IDS_COOKIES_DOMAIN_COLUMN_HEADER }, + { "cookie_local_data", IDS_COOKIES_DATA_COLUMN_HEADER }, + { "cookie_singular", IDS_COOKIES_SINGLE_COOKIE }, + { "cookie_plural", IDS_COOKIES_PLURAL_COOKIES }, + { "cookie_database_storage", IDS_COOKIES_DATABASE_STORAGE }, + { "cookie_indexed_db", IDS_COOKIES_INDEXED_DB }, + { "cookie_local_storage", IDS_COOKIES_LOCAL_STORAGE }, + { "cookie_app_cache", IDS_COOKIES_APPLICATION_CACHE }, + { "search_cookies", IDS_COOKIES_SEARCH_COOKIES }, + { "remove_cookie", IDS_COOKIES_REMOVE_LABEL }, + { "remove_all_cookie", IDS_COOKIES_REMOVE_ALL_LABEL }, + { "cookie_file_system", IDS_COOKIES_FILE_SYSTEM }, + { "label_file_system_origin", IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL }, + { "label_file_system_temporary_usage", + IDS_COOKIES_FILE_SYSTEM_TEMPORARY_USAGE_LABEL }, + { "label_file_system_persistent_usage", + IDS_COOKIES_FILE_SYSTEM_PERSISTENT_USAGE_LABEL }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "cookiesViewPage", + IDS_COOKIES_WEBSITE_PERMISSIONS_WINDOW_TITLE); +} + +void CookiesViewHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("updateCookieSearchResults", + base::Bind(&CookiesViewHandler::UpdateSearchResults, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeAllCookies", + base::Bind(&CookiesViewHandler::RemoveAll, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeCookie", + base::Bind(&CookiesViewHandler::Remove, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("loadCookie", + base::Bind(&CookiesViewHandler::LoadChildren, + base::Unretained(this))); +} + +void CookiesViewHandler::TreeNodesAdded(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) { + // Skip if there is a batch update in progress. + if (batch_update_) + return; + + CookieTreeNode* parent_node = cookies_tree_model_->AsNode(parent); + + ListValue* children = new ListValue; + cookies_tree_model_util::GetChildNodeList(parent_node, start, count, + children); + + ListValue args; + args.Append(parent == cookies_tree_model_->GetRoot() ? + Value::CreateNullValue() : + Value::CreateStringValue( + cookies_tree_model_util::GetTreeNodeId(parent_node))); + args.Append(Value::CreateIntegerValue(start)); + args.Append(children); + web_ui_->CallJavascriptFunction("CookiesView.onTreeItemAdded", args); +} + +void CookiesViewHandler::TreeNodesRemoved(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) { + // Skip if there is a batch update in progress. + if (batch_update_) + return; + + ListValue args; + args.Append(parent == cookies_tree_model_->GetRoot() ? + Value::CreateNullValue() : + Value::CreateStringValue(cookies_tree_model_util::GetTreeNodeId( + cookies_tree_model_->AsNode(parent)))); + args.Append(Value::CreateIntegerValue(start)); + args.Append(Value::CreateIntegerValue(count)); + web_ui_->CallJavascriptFunction("CookiesView.onTreeItemRemoved", args); +} + +void CookiesViewHandler::TreeModelBeginBatch(CookiesTreeModel* model) { + DCHECK(!batch_update_); // There should be no nested batch begin. + batch_update_ = true; +} + +void CookiesViewHandler::TreeModelEndBatch(CookiesTreeModel* model) { + DCHECK(batch_update_); + batch_update_ = false; + + SendChildren(cookies_tree_model_->GetRoot()); +} + +void CookiesViewHandler::EnsureCookiesTreeModelCreated() { + if (!cookies_tree_model_.get()) { + Profile* profile = Profile::FromWebUI(web_ui_); + cookies_tree_model_.reset(new CookiesTreeModel( + new BrowsingDataCookieHelper(profile), + new BrowsingDataDatabaseHelper(profile), + new BrowsingDataLocalStorageHelper(profile), + NULL, + new BrowsingDataAppCacheHelper(profile), + BrowsingDataIndexedDBHelper::Create(profile), + BrowsingDataFileSystemHelper::Create(profile), + BrowsingDataQuotaHelper::Create(profile), + false)); + cookies_tree_model_->AddCookiesTreeObserver(this); + } +} + +void CookiesViewHandler::UpdateSearchResults(const ListValue* args) { + std::string query; + if (!args->GetString(0, &query)) { + return; + } + + EnsureCookiesTreeModelCreated(); + + cookies_tree_model_->UpdateSearchResults(UTF8ToWide(query)); +} + +void CookiesViewHandler::RemoveAll(const ListValue* args) { + EnsureCookiesTreeModelCreated(); + cookies_tree_model_->DeleteAllStoredObjects(); +} + +void CookiesViewHandler::Remove(const ListValue* args) { + std::string node_path; + if (!args->GetString(0, &node_path)) { + return; + } + + EnsureCookiesTreeModelCreated(); + + CookieTreeNode* node = cookies_tree_model_util::GetTreeNodeFromPath( + cookies_tree_model_->GetRoot(), node_path); + if (node) + cookies_tree_model_->DeleteCookieNode(node); +} + +void CookiesViewHandler::LoadChildren(const ListValue* args) { + std::string node_path; + if (!args->GetString(0, &node_path)) { + return; + } + + EnsureCookiesTreeModelCreated(); + + CookieTreeNode* node = cookies_tree_model_util::GetTreeNodeFromPath( + cookies_tree_model_->GetRoot(), node_path); + if (node) + SendChildren(node); +} + +void CookiesViewHandler::SendChildren(CookieTreeNode* parent) { + ListValue* children = new ListValue; + cookies_tree_model_util::GetChildNodeList(parent, 0, parent->child_count(), + children); + + ListValue args; + args.Append(parent == cookies_tree_model_->GetRoot() ? + Value::CreateNullValue() : + Value::CreateStringValue(cookies_tree_model_util::GetTreeNodeId(parent))); + args.Append(children); + + web_ui_->CallJavascriptFunction("CookiesView.loadChildren", args); +} diff --git a/chrome/browser/ui/webui/options2/cookies_view_handler.h b/chrome/browser/ui/webui/options2/cookies_view_handler.h new file mode 100644 index 0000000..4055733 --- /dev/null +++ b/chrome/browser/ui/webui/options2/cookies_view_handler.h @@ -0,0 +1,69 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_COOKIES_VIEW_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_COOKIES_VIEW_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/cookies_tree_model.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +class CookiesViewHandler : public OptionsPage2UIHandler, + public CookiesTreeModel::Observer { + public: + CookiesViewHandler(); + virtual ~CookiesViewHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // CookiesTreeModel::Observer implementation. + virtual void TreeNodesAdded(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) OVERRIDE; + virtual void TreeNodesRemoved(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) OVERRIDE; + virtual void TreeNodeChanged(ui::TreeModel* model, + ui::TreeModelNode* node) OVERRIDE {} + virtual void TreeModelBeginBatch(CookiesTreeModel* model) OVERRIDE; + virtual void TreeModelEndBatch(CookiesTreeModel* model) OVERRIDE; + + private: + // Creates the CookiesTreeModel if neccessary. + void EnsureCookiesTreeModelCreated(); + + // Updates search filter for cookies tree model. + void UpdateSearchResults(const base::ListValue* args); + + // Remove all sites data. + void RemoveAll(const base::ListValue* args); + + // Remove selected sites data. + void Remove(const base::ListValue* args); + + // Get the tree node using the tree path info in |args| and call + // SendChildren to pass back children nodes data to WebUI. + void LoadChildren(const base::ListValue* args); + + // Get children nodes data and pass it to 'CookiesView.loadChildren' to + // update the WebUI. + void SendChildren(CookieTreeNode* parent); + + // The Cookies Tree model + scoped_ptr<CookiesTreeModel> cookies_tree_model_; + + // Flag to indicate whether there is a batch update in progress. + bool batch_update_; + + DISALLOW_COPY_AND_ASSIGN(CookiesViewHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_COOKIES_VIEW_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/core_options_handler.cc b/chrome/browser/ui/webui/options2/core_options_handler.cc new file mode 100644 index 0000000..b6e8d3c --- /dev/null +++ b/chrome/browser/ui/webui/options2/core_options_handler.cc @@ -0,0 +1,464 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/core_options_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/json/json_reader.h" +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/net/url_fixer_upper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_types.h" +#include "googleurl/src/gurl.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" + +CoreOptionsHandler::CoreOptionsHandler() + : handlers_host_(NULL) { +} + +CoreOptionsHandler::~CoreOptionsHandler() {} + +void CoreOptionsHandler::Initialize() { + clear_plugin_lso_data_enabled_.Init(prefs::kClearPluginLSODataEnabled, + Profile::FromWebUI(web_ui_), + this); + UpdateClearPluginLSOData(); +} + +void CoreOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + GetStaticLocalizedValues(localized_strings); +} + +void CoreOptionsHandler::GetStaticLocalizedValues( + base::DictionaryValue* localized_strings) { + DCHECK(localized_strings); + // Main + localized_strings->SetString("title", + l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE)); + + // Managed prefs + localized_strings->SetString("policyManagedPrefsBannerText", + l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_MANAGED_PREFS)); + localized_strings->SetString("extensionManagedPrefsBannerText", + l10n_util::GetStringUTF16(IDS_OPTIONS_EXTENSION_MANAGED_PREFS)); + localized_strings->SetString("policyAndExtensionManagedPrefsBannerText", + l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_EXTENSION_MANAGED_PREFS)); + + // Controlled settings bubble. + localized_strings->SetString("controlledSettingPolicy", + l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY)); + localized_strings->SetString("controlledSettingExtension", + l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_EXTENSION)); + localized_strings->SetString("controlledSettingRecommended", + l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_RECOMMENDED)); + localized_strings->SetString("controlledSettingApplyRecommendation", + l10n_util::GetStringUTF16( + IDS_OPTIONS_CONTROLLED_SETTING_APPLY_RECOMMENDATION)); + + // Search + RegisterTitle(localized_strings, "searchPage", IDS_OPTIONS_SEARCH_PAGE_TITLE); + localized_strings->SetString("searchPlaceholder", + l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PLACEHOLDER)); + localized_strings->SetString("searchPageNoMatches", + l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_NO_MATCHES)); + localized_strings->SetString("searchPageHelpLabel", + l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_LABEL)); + localized_strings->SetString("searchPageHelpTitle", + l10n_util::GetStringFUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_TITLE, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + localized_strings->SetString("searchPageHelpURL", + google_util::AppendGoogleLocaleParam( + GURL(chrome::kChromeHelpURL)).spec()); + + // Common + localized_strings->SetString("ok", + l10n_util::GetStringUTF16(IDS_OK)); + localized_strings->SetString("cancel", + l10n_util::GetStringUTF16(IDS_CANCEL)); + localized_strings->SetString("learnMore", + l10n_util::GetStringUTF16(IDS_LEARN_MORE)); + localized_strings->SetString("close", + l10n_util::GetStringUTF16(IDS_CLOSE)); +} + +void CoreOptionsHandler::Uninitialize() { + std::string last_pref; + for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin(); + iter != pref_callback_map_.end(); + ++iter) { + if (last_pref != iter->first) { + StopObservingPref(iter->first); + last_pref = iter->first; + } + } +} + +WebUIMessageHandler* CoreOptionsHandler::Attach(WebUI* web_ui) { + WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui); + DCHECK(web_ui_); + registrar_.Init(Profile::FromWebUI(web_ui_)->GetPrefs()); + return result; +} + +void CoreOptionsHandler::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PREF_CHANGED) { + std::string* pref_name = content::Details<std::string>(details).ptr(); + if (*pref_name == prefs::kClearPluginLSODataEnabled) { + // This preference is stored in Local State, not in the user preferences. + UpdateClearPluginLSOData(); + return; + } + NotifyPrefChanged(*pref_name, std::string()); + } +} + +void CoreOptionsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("coreOptionsInitialize", + base::Bind(&CoreOptionsHandler::HandleInitialize, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("fetchPrefs", + base::Bind(&CoreOptionsHandler::HandleFetchPrefs, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("observePrefs", + base::Bind(&CoreOptionsHandler::HandleObservePrefs, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setBooleanPref", + base::Bind(&CoreOptionsHandler::HandleSetBooleanPref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setIntegerPref", + base::Bind(&CoreOptionsHandler::HandleSetIntegerPref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setDoublePref", + base::Bind(&CoreOptionsHandler::HandleSetDoublePref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setStringPref", + base::Bind(&CoreOptionsHandler::HandleSetStringPref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setURLPref", + base::Bind(&CoreOptionsHandler::HandleSetURLPref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setListPref", + base::Bind(&CoreOptionsHandler::HandleSetListPref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("clearPref", + base::Bind(&CoreOptionsHandler::HandleClearPref, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("coreOptionsUserMetricsAction", + base::Bind(&CoreOptionsHandler::HandleUserMetricsAction, + base::Unretained(this))); +} + +void CoreOptionsHandler::HandleInitialize(const ListValue* args) { + DCHECK(handlers_host_); + handlers_host_->InitializeHandlers(); +} + +base::Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) { + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + + const PrefService::Preference* pref = + pref_service->FindPreference(pref_name.c_str()); + if (!pref) + return base::Value::CreateNullValue(); + + return CreateValueForPref(pref, NULL); +} + +void CoreOptionsHandler::ObservePref(const std::string& pref_name) { + registrar_.Add(pref_name.c_str(), this); +} + +void CoreOptionsHandler::SetPref(const std::string& pref_name, + const base::Value* value, + const std::string& metric) { + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + + switch (value->GetType()) { + case base::Value::TYPE_BOOLEAN: + case base::Value::TYPE_INTEGER: + case base::Value::TYPE_DOUBLE: + case base::Value::TYPE_STRING: + pref_service->Set(pref_name.c_str(), *value); + break; + + default: + NOTREACHED(); + return; + } + + pref_service->ScheduleSavePersistentPrefs(); + + ProcessUserMetric(value, metric); +} + +void CoreOptionsHandler::ClearPref(const std::string& pref_name, + const std::string& metric) { + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + pref_service->ClearPref(pref_name.c_str()); + pref_service->ScheduleSavePersistentPrefs(); + + if (!metric.empty()) + UserMetrics::RecordComputedAction(metric); +} + +void CoreOptionsHandler::ProcessUserMetric(const base::Value* value, + const std::string& metric) { + if (metric.empty()) + return; + + std::string metric_string = metric; + if (value->IsType(base::Value::TYPE_BOOLEAN)) { + bool bool_value; + CHECK(value->GetAsBoolean(&bool_value)); + metric_string += bool_value ? "_Enable" : "_Disable"; + } + + UserMetrics::RecordComputedAction(metric_string); +} + +void CoreOptionsHandler::NotifyPrefChanged( + const std::string& pref_name, + const std::string& controlling_pref_name) { + const PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + const PrefService::Preference* pref = + pref_service->FindPreference(pref_name.c_str()); + if (!pref) + return; + const PrefService::Preference* controlling_pref = + !controlling_pref_name.empty() ? + pref_service->FindPreference(controlling_pref_name.c_str()) : NULL; + std::pair<PreferenceCallbackMap::const_iterator, + PreferenceCallbackMap::const_iterator> range; + range = pref_callback_map_.equal_range(pref_name); + for (PreferenceCallbackMap::const_iterator iter = range.first; + iter != range.second; ++iter) { + const std::wstring& callback_function = iter->second; + ListValue result_value; + result_value.Append(base::Value::CreateStringValue(pref_name.c_str())); + result_value.Append(CreateValueForPref(pref, controlling_pref)); + web_ui_->CallJavascriptFunction(WideToASCII(callback_function), + result_value); + } +} + +DictionaryValue* CoreOptionsHandler::CreateValueForPref( + const PrefService::Preference* pref, + const PrefService::Preference* controlling_pref) { + DictionaryValue* dict = new DictionaryValue; + dict->Set("value", pref->GetValue()->DeepCopy()); + if (!controlling_pref) // No controlling pref is managing actual pref. + controlling_pref = pref; // This means pref is controlling itself. + if (controlling_pref->IsManaged()) { + dict->SetString("controlledBy", "policy"); + } else if (controlling_pref->IsExtensionControlled()) { + dict->SetString("controlledBy", "extension"); + } else if (controlling_pref->IsRecommended()) { + dict->SetString("controlledBy", "recommended"); + } + dict->SetBoolean("disabled", !controlling_pref->IsUserModifiable()); + return dict; +} + +void CoreOptionsHandler::StopObservingPref(const std::string& path) { + registrar_.Remove(path.c_str(), this); +} + +void CoreOptionsHandler::HandleFetchPrefs(const ListValue* args) { + // First param is name of callback function, so, there needs to be at least + // one more element for the actual preference identifier. + DCHECK_GE(static_cast<int>(args->GetSize()), 2); + + // Get callback JS function name. + base::Value* callback; + if (!args->Get(0, &callback) || !callback->IsType(base::Value::TYPE_STRING)) + return; + + string16 callback_function; + if (!callback->GetAsString(&callback_function)) + return; + + // Get the list of name for prefs to build the response dictionary. + DictionaryValue result_value; + base::Value* list_member; + + for (size_t i = 1; i < args->GetSize(); i++) { + if (!args->Get(i, &list_member)) + break; + + if (!list_member->IsType(base::Value::TYPE_STRING)) + continue; + + std::string pref_name; + if (!list_member->GetAsString(&pref_name)) + continue; + + result_value.Set(pref_name.c_str(), FetchPref(pref_name)); + } + web_ui_->CallJavascriptFunction(UTF16ToASCII(callback_function), + result_value); +} + +void CoreOptionsHandler::HandleObservePrefs(const ListValue* args) { + // First param is name is JS callback function name, the rest are pref + // identifiers that we are observing. + DCHECK_GE(static_cast<int>(args->GetSize()), 2); + + // Get preference change callback function name. + string16 callback_func_name; + if (!args->GetString(0, &callback_func_name)) + return; + + // Get all other parameters - pref identifiers. + for (size_t i = 1; i < args->GetSize(); i++) { + base::Value* list_member; + if (!args->Get(i, &list_member)) + break; + + // Just ignore bad pref identifiers for now. + std::string pref_name; + if (!list_member->IsType(base::Value::TYPE_STRING) || + !list_member->GetAsString(&pref_name)) + continue; + + if (pref_callback_map_.find(pref_name) == pref_callback_map_.end()) + ObservePref(pref_name); + + pref_callback_map_.insert( + PreferenceCallbackMap::value_type(pref_name, + UTF16ToWideHack(callback_func_name))); + } +} + +void CoreOptionsHandler::HandleSetBooleanPref(const ListValue* args) { + HandleSetPref(args, TYPE_BOOLEAN); +} + +void CoreOptionsHandler::HandleSetIntegerPref(const ListValue* args) { + HandleSetPref(args, TYPE_INTEGER); +} + +void CoreOptionsHandler::HandleSetDoublePref(const ListValue* args) { + HandleSetPref(args, TYPE_DOUBLE); +} + +void CoreOptionsHandler::HandleSetStringPref(const ListValue* args) { + HandleSetPref(args, TYPE_STRING); +} + +void CoreOptionsHandler::HandleSetURLPref(const ListValue* args) { + HandleSetPref(args, TYPE_URL); +} + +void CoreOptionsHandler::HandleSetListPref(const ListValue* args) { + HandleSetPref(args, TYPE_LIST); +} + +void CoreOptionsHandler::HandleSetPref(const ListValue* args, PrefType type) { + DCHECK_GT(static_cast<int>(args->GetSize()), 1); + + std::string pref_name; + if (!args->GetString(0, &pref_name)) + return; + + base::Value* value; + if (!args->Get(1, &value)) + return; + + scoped_ptr<base::Value> temp_value; + + switch (type) { + case TYPE_BOOLEAN: + CHECK_EQ(base::Value::TYPE_BOOLEAN, value->GetType()); + break; + case TYPE_INTEGER: { + // In JS all numbers are doubles. + double double_value; + CHECK(value->GetAsDouble(&double_value)); + int int_value = static_cast<int>(double_value); + temp_value.reset(base::Value::CreateIntegerValue(int_value)); + value = temp_value.get(); + break; + } + case TYPE_DOUBLE: + CHECK_EQ(base::Value::TYPE_DOUBLE, value->GetType()); + break; + case TYPE_STRING: + CHECK_EQ(base::Value::TYPE_STRING, value->GetType()); + break; + case TYPE_URL: { + std::string original; + CHECK(value->GetAsString(&original)); + GURL fixed = URLFixerUpper::FixupURL(original, std::string()); + temp_value.reset(base::Value::CreateStringValue(fixed.spec())); + value = temp_value.get(); + break; + } + case TYPE_LIST: { + // In case we have a List pref we got a JSON string. + std::string json_string; + CHECK(value->GetAsString(&json_string)); + temp_value.reset( + base::JSONReader().JsonToValue(json_string, + false, // no check_root + false)); // no trailing comma + value = temp_value.get(); + CHECK_EQ(base::Value::TYPE_LIST, value->GetType()); + break; + } + default: + NOTREACHED(); + } + + std::string metric; + if (args->GetSize() > 2 && !args->GetString(2, &metric)) + LOG(WARNING) << "Invalid metric parameter: " << pref_name; + SetPref(pref_name, value, metric); +} + +void CoreOptionsHandler::HandleClearPref(const ListValue* args) { + DCHECK_GT(static_cast<int>(args->GetSize()), 0); + + std::string pref_name; + if (!args->GetString(0, &pref_name)) + return; + + std::string metric; + if (args->GetSize() > 1) + args->GetString(1, &metric); + + ClearPref(pref_name, metric); +} + +void CoreOptionsHandler::HandleUserMetricsAction(const ListValue* args) { + std::string metric = UTF16ToUTF8(ExtractStringValue(args)); + if (!metric.empty()) + UserMetrics::RecordComputedAction(metric); +} + +void CoreOptionsHandler::UpdateClearPluginLSOData() { + scoped_ptr<base::Value> enabled( + base::Value::CreateBooleanValue( + clear_plugin_lso_data_enabled_.GetValue())); + web_ui_->CallJavascriptFunction( + "OptionsPage.setClearPluginLSODataEnabled", *enabled); +} diff --git a/chrome/browser/ui/webui/options2/core_options_handler.h b/chrome/browser/ui/webui/options2/core_options_handler.h new file mode 100644 index 0000000..355195a --- /dev/null +++ b/chrome/browser/ui/webui/options2/core_options_handler.h @@ -0,0 +1,151 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CORE_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CORE_OPTIONS_HANDLER_H_ +#pragma once + +#include <map> +#include <string> + +#include "base/values.h" +#include "chrome/browser/plugin_data_remover_helper.h" +#include "chrome/browser/prefs/pref_change_registrar.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +// Core options UI handler. +// Handles resource and JS calls common to all options sub-pages. +class CoreOptionsHandler : public OptionsPage2UIHandler { + public: + CoreOptionsHandler(); + virtual ~CoreOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void Initialize() OVERRIDE; + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + virtual void Uninitialize() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE; + + void set_handlers_host(OptionsPage2UIHandlerHost* handlers_host) { + handlers_host_ = handlers_host; + } + + // Adds localized strings to |localized_strings|. + static void GetStaticLocalizedValues( + base::DictionaryValue* localized_strings); + + protected: + // Fetches a pref value of given |pref_name|. + // Note that caller owns the returned Value. + virtual base::Value* FetchPref(const std::string& pref_name); + + // Observes a pref of given |pref_name|. + virtual void ObservePref(const std::string& pref_name); + + // Sets a pref |value| to given |pref_name|. + virtual void SetPref(const std::string& pref_name, + const base::Value* value, + const std::string& metric); + + // Clears pref value for given |pref_name|. + void ClearPref(const std::string& pref_name, const std::string& metric); + + // Stops observing given preference identified by |path|. + virtual void StopObservingPref(const std::string& path); + + // Records a user metric action for the given value. + void ProcessUserMetric(const base::Value* value, + const std::string& metric); + + // Notifies registered JS callbacks on change in |pref_name| preference. + // |controlling_pref_name| controls if |pref_name| is managed by + // policy/extension; empty |controlling_pref_name| indicates no other pref is + // controlling |pref_name|. + void NotifyPrefChanged(const std::string& pref_name, + const std::string& controlling_pref_name); + + // Creates dictionary value for |pref|, |controlling_pref| controls if |pref| + // is managed by policy/extension; NULL indicates no other pref is controlling + // |pref|. + DictionaryValue* CreateValueForPref( + const PrefService::Preference* pref, + const PrefService::Preference* controlling_pref); + + typedef std::multimap<std::string, std::wstring> PreferenceCallbackMap; + PreferenceCallbackMap pref_callback_map_; + + private: + // Type of preference value received from the page. This doesn't map 1:1 to + // Value::Type, since a TYPE_STRING can require custom processing. + enum PrefType { + TYPE_BOOLEAN = 0, + TYPE_INTEGER, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_URL, + TYPE_LIST, + }; + + // Callback for the "coreOptionsInitialize" message. This message will + // trigger the Initialize() method of all other handlers so that final + // setup can be performed before the page is shown. + void HandleInitialize(const ListValue* args); + + // Callback for the "fetchPrefs" message. This message accepts the list of + // preference names passed as the |args| parameter (ListValue). It passes + // results dictionary of preference values by calling prefsFetched() JS method + // on the page. + void HandleFetchPrefs(const ListValue* args); + + // Callback for the "observePrefs" message. This message initiates + // notification observing for given array of preference names. + void HandleObservePrefs(const ListValue* args); + + // Callbacks for the "set<type>Pref" message. This message saves the new + // preference value. |args| is an array of parameters as follows: + // item 0 - name of the preference. + // item 1 - the value of the preference in string form. + // item 2 - name of the metric identifier (optional). + void HandleSetBooleanPref(const ListValue* args); + void HandleSetIntegerPref(const ListValue* args); + void HandleSetDoublePref(const ListValue* args); + void HandleSetStringPref(const ListValue* args); + void HandleSetURLPref(const ListValue* args); + void HandleSetListPref(const ListValue* args); + + void HandleSetPref(const ListValue* args, PrefType type); + + // Callback for the "clearPref" message. This message clears a preference + // value. |args| is an array of parameters as follows: + // item 0 - name of the preference. + // item 1 - name of the metric identifier (optional). + void HandleClearPref(const ListValue* args); + + // Callback for the "coreOptionsUserMetricsAction" message. This records + // an action that should be tracked if metrics recording is enabled. |args| + // is an array that contains a single item, the name of the metric identifier. + void HandleUserMetricsAction(const ListValue* args); + + void UpdateClearPluginLSOData(); + + OptionsPage2UIHandlerHost* handlers_host_; + PrefChangeRegistrar registrar_; + + // Used for asynchronously updating the preference stating whether clearing + // LSO data is supported. + PluginDataRemoverHelper clear_plugin_lso_data_enabled_; + + DISALLOW_COPY_AND_ASSIGN(CoreOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_CORE_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/extension_settings_handler.cc b/chrome/browser/ui/webui/options2/extension_settings_handler.cc new file mode 100644 index 0000000..cc6f548 --- /dev/null +++ b/chrome/browser/ui/webui/options2/extension_settings_handler.cc @@ -0,0 +1,785 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/extension_settings_handler.h" + +#include "base/auto_reset.h" +#include "base/base64.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "base/version.h" +#include "chrome/browser/debugger/devtools_window.h" +#include "chrome/browser/extensions/crx_installer.h" +#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_updater.h" +#include "chrome/browser/extensions/extension_warning_set.h" +#include "chrome/browser/extensions/unpacked_installer.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/tab_contents/background_contents.h" +#include "chrome/browser/ui/webui/extension_icon_source.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_view_type.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/browser/browsing_instance.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_view.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "grit/browser_resources.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +namespace { + +bool ShouldShowExtension(const Extension* extension) { + // Don't show themes since this page's UI isn't really useful for themes. + if (extension->is_theme()) + return false; + + // Don't show component extensions because they are only extensions as an + // implementation detail of Chrome. + if (extension->location() == Extension::COMPONENT && + !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kShowComponentExtensionOptions)) + return false; + + // Always show unpacked extensions and apps. + if (extension->location() == Extension::LOAD) + return true; + + // Unless they are unpacked, never show hosted apps. + if (extension->is_hosted_app()) + return false; + + return true; +} + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// +// ExtensionSettingsHandler +// +/////////////////////////////////////////////////////////////////////////////// + +ExtensionSettingsHandler::ExtensionSettingsHandler() + : extension_service_(NULL), + ignore_notifications_(false), + deleting_rvh_(NULL), + registered_for_notifications_(false) { +} + +ExtensionSettingsHandler::~ExtensionSettingsHandler() { + // There may be pending file dialogs, we need to tell them that we've gone + // away so they don't try and call back to us. + if (load_extension_dialog_.get()) + load_extension_dialog_->ListenerDestroyed(); + + registrar_.RemoveAll(); +} + +// static +void ExtensionSettingsHandler::RegisterUserPrefs(PrefService* prefs) { + prefs->RegisterBooleanPref(prefs::kExtensionsUIDeveloperMode, + false, + PrefService::SYNCABLE_PREF); +} + +void ExtensionSettingsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("extensionSettingsRequestExtensionsData", + base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsToggleDeveloperMode", + base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsInspect", + base::Bind(&ExtensionSettingsHandler::HandleInspectMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsReload", + base::Bind(&ExtensionSettingsHandler::HandleReloadMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsEnable", + base::Bind(&ExtensionSettingsHandler::HandleEnableMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsEnableIncognito", + base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsAllowFileAccess", + base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsUninstall", + base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsOptions", + base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsShowButton", + base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsLoad", + base::Bind(&ExtensionSettingsHandler::HandleLoadMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsAutoupdate", + base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("extensionSettingsSelectFilePath", + base::Bind(&ExtensionSettingsHandler::HandleSelectFilePathMessage, + base::Unretained(this))); +} + +void ExtensionSettingsHandler::HandleRequestExtensionsData( + const ListValue* args) { + DictionaryValue results; + + // Add the extensions to the results structure. + ListValue *extensions_list = new ListValue(); + + ExtensionWarningSet* warnings = extension_service_->extension_warnings(); + + const ExtensionSet* extensions = extension_service_->extensions(); + for (ExtensionSet::const_iterator extension = extensions->begin(); + extension != extensions->end(); ++extension) { + if (ShouldShowExtension(*extension)) { + extensions_list->Append(CreateExtensionDetailValue( + extension_service_, + *extension, + GetActivePagesForExtension(*extension), + warnings, + true, false)); // enabled, terminated + } + } + extensions = extension_service_->disabled_extensions(); + for (ExtensionSet::const_iterator extension = extensions->begin(); + extension != extensions->end(); ++extension) { + if (ShouldShowExtension(*extension)) { + extensions_list->Append(CreateExtensionDetailValue( + extension_service_, + *extension, + GetActivePagesForExtension(*extension), + warnings, + false, false)); // enabled, terminated + } + } + extensions = extension_service_->terminated_extensions(); + std::vector<ExtensionPage> empty_pages; + for (ExtensionSet::const_iterator extension = extensions->begin(); + extension != extensions->end(); ++extension) { + if (ShouldShowExtension(*extension)) { + extensions_list->Append(CreateExtensionDetailValue( + extension_service_, + *extension, + empty_pages, // Terminated process has no active pages. + warnings, + false, true)); // enabled, terminated + } + } + results.Set("extensions", extensions_list); + + Profile* profile = Profile::FromWebUI(web_ui_); + bool developer_mode = + profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); + results.SetBoolean("developerMode", developer_mode); + + web_ui_->CallJavascriptFunction("ExtensionSettings.returnExtensionsData", + results); + + MaybeRegisterForNotifications(); +} + +void ExtensionSettingsHandler::MaybeRegisterForNotifications() { + if (registered_for_notifications_) + return; + + registered_for_notifications_ = true; + Profile* profile = Profile::FromWebUI(web_ui_); + + // Register for notifications that we need to reload the page. + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, + content::Source<Profile>(profile)); + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, + content::Source<Profile>(profile)); + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, + content::Source<Profile>(profile)); + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_WARNING_CHANGED, + content::Source<Profile>(profile)); + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + content::NOTIFICATION_RENDER_VIEW_HOST_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add( + this, + chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, + content::Source<ExtensionPrefs>(profile->GetExtensionService()-> + extension_prefs())); +} + +ExtensionUninstallDialog* +ExtensionSettingsHandler::GetExtensionUninstallDialog() { + if (!extension_uninstall_dialog_.get()) { + extension_uninstall_dialog_.reset( + ExtensionUninstallDialog::Create(Profile::FromWebUI(web_ui_), this)); + } + return extension_uninstall_dialog_.get(); +} + +void ExtensionSettingsHandler::HandleToggleDeveloperMode( + const ListValue* args) { + Profile* profile = Profile::FromWebUI(web_ui_); + bool developer_mode = + profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); + profile->GetPrefs()->SetBoolean( + prefs::kExtensionsUIDeveloperMode, !developer_mode); + HandleRequestExtensionsData(NULL); +} + +void ExtensionSettingsHandler::HandleInspectMessage(const ListValue* args) { + std::string render_process_id_str; + std::string render_view_id_str; + int render_process_id; + int render_view_id; + CHECK_EQ(2U, args->GetSize()); + CHECK(args->GetString(0, &render_process_id_str)); + CHECK(args->GetString(1, &render_view_id_str)); + CHECK(base::StringToInt(render_process_id_str, &render_process_id)); + CHECK(base::StringToInt(render_view_id_str, &render_view_id)); + RenderViewHost* host = RenderViewHost::FromID(render_process_id, + render_view_id); + if (!host) { + // This can happen if the host has gone away since the page was displayed. + return; + } + + DevToolsWindow::OpenDevToolsWindow(host); +} + +void ExtensionSettingsHandler::HandleReloadMessage(const ListValue* args) { + std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); + CHECK(!extension_id.empty()); + extension_service_->ReloadExtension(extension_id); +} + +void ExtensionSettingsHandler::HandleEnableMessage(const ListValue* args) { + CHECK_EQ(2U, args->GetSize()); + std::string extension_id, enable_str; + CHECK(args->GetString(0, &extension_id)); + CHECK(args->GetString(1, &enable_str)); + + const Extension* extension = + extension_service_->GetExtensionById(extension_id, true); + if (!Extension::UserMayDisable(extension->location())) { + LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was" + << "made. Extension id: " << extension->id(); + return; + } + + if (enable_str == "true") { + ExtensionPrefs* prefs = extension_service_->extension_prefs(); + if (prefs->DidExtensionEscalatePermissions(extension_id)) { + ShowExtensionDisabledDialog(extension_service_, + Profile::FromWebUI(web_ui_), extension); + } else { + extension_service_->EnableExtension(extension_id); + } + } else { + extension_service_->DisableExtension(extension_id); + } +} + +void ExtensionSettingsHandler::HandleEnableIncognitoMessage( + const ListValue* args) { + CHECK_EQ(2U, args->GetSize()); + std::string extension_id, enable_str; + CHECK(args->GetString(0, &extension_id)); + CHECK(args->GetString(1, &enable_str)); + const Extension* extension = + extension_service_->GetExtensionById(extension_id, true); + DCHECK(extension); + + // Flipping the incognito bit will generate unload/load notifications for the + // extension, but we don't want to reload the page, because a) we've already + // updated the UI to reflect the change, and b) we want the yellow warning + // text to stay until the user has left the page. + // + // TODO(aa): This creates crapiness in some cases. For example, in a main + // window, when toggling this, the browser action will flicker because it gets + // unloaded, then reloaded. It would be better to have a dedicated + // notification for this case. + // + // Bug: http://crbug.com/41384 + AutoReset<bool> auto_reset_ignore_notifications(&ignore_notifications_, true); + extension_service_->SetIsIncognitoEnabled(extension->id(), + enable_str == "true"); +} + +void ExtensionSettingsHandler::HandleAllowFileAccessMessage( + const ListValue* args) { + CHECK_EQ(2U, args->GetSize()); + std::string extension_id, allow_str; + CHECK(args->GetString(0, &extension_id)); + CHECK(args->GetString(1, &allow_str)); + const Extension* extension = + extension_service_->GetExtensionById(extension_id, true); + DCHECK(extension); + + if (!Extension::UserMayDisable(extension->location())) { + LOG(ERROR) << "Attempt to change allow file access of an extension that is " + << "non-usermanagable was made. Extension id : " + << extension->id(); + return; + } + + extension_service_->SetAllowFileAccess(extension, allow_str == "true"); +} + +void ExtensionSettingsHandler::HandleUninstallMessage(const ListValue* args) { + std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); + CHECK(!extension_id.empty()); + const Extension* extension = + extension_service_->GetExtensionById(extension_id, true); + if (!extension) + extension = extension_service_->GetTerminatedExtension(extension_id); + if (!extension) + return; + + if (!Extension::UserMayDisable(extension->location())) { + LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable " + << "was made. Extension id : " << extension->id(); + return; + } + + if (!extension_id_prompting_.empty()) + return; // Only one prompt at a time. + + extension_id_prompting_ = extension_id; + + GetExtensionUninstallDialog()->ConfirmUninstall(extension); +} + +void ExtensionSettingsHandler::ExtensionUninstallAccepted() { + DCHECK(!extension_id_prompting_.empty()); + + bool was_terminated = false; + + // The extension can be uninstalled in another window while the UI was + // showing. Do nothing in that case. + const Extension* extension = + extension_service_->GetExtensionById(extension_id_prompting_, true); + if (!extension) { + extension = extension_service_->GetTerminatedExtension( + extension_id_prompting_); + was_terminated = true; + } + if (!extension) + return; + + extension_service_->UninstallExtension(extension_id_prompting_, + false, // External uninstall. + NULL); // Error. + extension_id_prompting_ = ""; + + // There will be no EXTENSION_UNLOADED notification for terminated + // extensions as they were already unloaded. + if (was_terminated) + HandleRequestExtensionsData(NULL); +} + +void ExtensionSettingsHandler::ExtensionUninstallCanceled() { + extension_id_prompting_ = ""; +} + +void ExtensionSettingsHandler::HandleOptionsMessage(const ListValue* args) { + const Extension* extension = GetExtension(args); + if (!extension || extension->options_url().is_empty()) + return; + Profile::FromWebUI(web_ui_)->GetExtensionProcessManager()->OpenOptionsPage( + extension, NULL); +} + +void ExtensionSettingsHandler::HandleShowButtonMessage(const ListValue* args) { + const Extension* extension = GetExtension(args); + extension_service_->SetBrowserActionVisibility(extension, true); +} + +void ExtensionSettingsHandler::HandleLoadMessage(const ListValue* args) { + FilePath::StringType string_path; + CHECK_EQ(1U, args->GetSize()) << args->GetSize(); + CHECK(args->GetString(0, &string_path)); + extensions::UnpackedInstaller::Create(extension_service_)-> + Load(FilePath(string_path)); +} + +void ExtensionSettingsHandler::ShowAlert(const std::string& message) { + ListValue arguments; + arguments.Append(Value::CreateStringValue(message)); + web_ui_->CallJavascriptFunction("alert", arguments); +} + +void ExtensionSettingsHandler::HandleAutoUpdateMessage(const ListValue* args) { + ExtensionUpdater* updater = extension_service_->updater(); + if (updater) + updater->CheckNow(); +} + +void ExtensionSettingsHandler::HandleSelectFilePathMessage( + const ListValue* args) { + std::string select_type; + std::string operation; + CHECK_EQ(2U, args->GetSize()); + CHECK(args->GetString(0, &select_type)); + CHECK(args->GetString(1, &operation)); + + SelectFileDialog::Type type = SelectFileDialog::SELECT_FOLDER; + SelectFileDialog::FileTypeInfo info; + int file_type_index = 0; + if (select_type == "file") + type = SelectFileDialog::SELECT_OPEN_FILE; + + string16 select_title; + if (operation == "load") { + select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); + } else if (operation == "packRoot") { + select_title = l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_SELECT_ROOT); + } else if (operation == "pem") { + select_title = l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); + info.extensions.push_back(std::vector<FilePath::StringType>()); + info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); + info.extension_description_overrides.push_back( + l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); + info.include_all_files = true; + file_type_index = 1; + } else { + NOTREACHED(); + return; + } + + load_extension_dialog_ = SelectFileDialog::Create(this); + load_extension_dialog_->SelectFile(type, select_title, FilePath(), &info, + file_type_index, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), + web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); +} + + +void ExtensionSettingsHandler::FileSelected(const FilePath& path, int index, + void* params) { + // Add the extensions to the results structure. + ListValue results; + results.Append(Value::CreateStringValue(path.value())); + web_ui_->CallJavascriptFunction("window.handleFilePathSelected", results); +} + +void ExtensionSettingsHandler::MultiFilesSelected( + const std::vector<FilePath>& files, void* params) { + NOTREACHED(); +} + +void ExtensionSettingsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "extensionSettings", + IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE); + + localized_strings->SetString("extensionSettingsVisitWebsite", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE)); + + localized_strings->SetString("extensionSettingsDeveloperMode", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK)); + localized_strings->SetString("extensionSettingsNoExtensions", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED)); + localized_strings->SetString("extensionSettingsSuggestGallery", + l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY, + ASCIIToUTF16("<a href='") + + ASCIIToUTF16(google_util::AppendGoogleLocaleParam( + GURL(extension_urls::GetWebstoreLaunchURL())).spec()) + + ASCIIToUTF16("'>"), + ASCIIToUTF16("</a>"))); + localized_strings->SetString("extensionSettingsGetMoreExtensions", + ASCIIToUTF16("<a href='") + + ASCIIToUTF16(google_util::AppendGoogleLocaleParam( + GURL(extension_urls::GetWebstoreLaunchURL())).spec()) + + ASCIIToUTF16("'>") + + l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS) + + ASCIIToUTF16("</a>")); + localized_strings->SetString("extensionSettingsExtensionId", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID)); + localized_strings->SetString("extensionSettingsExtensionPath", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH)); + localized_strings->SetString("extensionSettingsInspectViews", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS)); + localized_strings->SetString("viewIncognito", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO)); + localized_strings->SetString("extensionSettingsEnable", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE)); + localized_strings->SetString("extensionSettingsEnabled", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED)); + localized_strings->SetString("extensionSettingsRemove", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE)); + localized_strings->SetString("extensionSettingsEnableIncognito", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO)); + localized_strings->SetString("extensionSettingsAllowFileAccess", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS)); + localized_strings->SetString("extensionSettingsIncognitoWarning", + l10n_util::GetStringFUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + localized_strings->SetString("extensionSettingsReload", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD)); + localized_strings->SetString("extensionSettingsOptions", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS)); + localized_strings->SetString("extensionSettingsPolicyControlled", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED)); + localized_strings->SetString("extensionSettingsShowButton", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON)); + localized_strings->SetString("extensionSettingsLoadUnpackedButton", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON)); + localized_strings->SetString("extensionSettingsPackButton", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON)); + localized_strings->SetString("extensionSettingsUpdateButton", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON)); + localized_strings->SetString("extensionSettingsCrashMessage", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION)); + localized_strings->SetString("extensionSettingsInDevelopment", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT)); + localized_strings->SetString("extensionSettingsWarningsTitle", + l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE)); + localized_strings->SetString("extensionSettingsShowDetails", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS)); + localized_strings->SetString("extensionSettingsHideDetails", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS)); +} + +void ExtensionSettingsHandler::Initialize() { +} + +WebUIMessageHandler* ExtensionSettingsHandler::Attach(WebUI* web_ui) { + // Call through to superclass. + WebUIMessageHandler* handler = OptionsPage2UIHandler::Attach(web_ui); + + extension_service_ = Profile::FromWebUI(web_ui_) + ->GetOriginalProfile()->GetExtensionService(); + + // Return result from the superclass. + return handler; +} + +void ExtensionSettingsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + Profile* profile = Profile::FromWebUI(web_ui_); + Profile* source_profile = NULL; + switch (type) { + // We listen for notifications that will result in the page being + // repopulated with data twice for the same event in certain cases. + // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because + // we don't know about the views for an extension at EXTENSION_LOADED, but + // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions + // that don't have a process at startup. + // + // Doing it this way gets everything but causes the page to be rendered + // more than we need. It doesn't seem to result in any noticeable flicker. + case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED: + deleting_rvh_ = content::Source<RenderViewHost>(source).ptr(); + // Fall through. + case content::NOTIFICATION_RENDER_VIEW_HOST_CREATED: + source_profile = Profile::FromBrowserContext( + content::Source<RenderViewHost>(source)->site_instance()-> + browsing_instance()->browser_context()); + if (!profile->IsSameProfile(source_profile)) + return; + MaybeUpdateAfterNotification(); + break; + case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: + deleting_rvh_ = content::Details<BackgroundContents>(details)-> + tab_contents()->render_view_host(); + // Fall through. + case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: + case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: + source_profile = content::Source<Profile>(source).ptr(); + if (!profile->IsSameProfile(source_profile)) + return; + MaybeUpdateAfterNotification(); + break; + case chrome::NOTIFICATION_EXTENSION_LOADED: + case chrome::NOTIFICATION_EXTENSION_UNLOADED: + case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: + case chrome::NOTIFICATION_EXTENSION_WARNING_CHANGED: + case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: + MaybeUpdateAfterNotification(); + break; + default: + NOTREACHED(); + } +} + +const Extension* ExtensionSettingsHandler::GetExtension(const ListValue* args) { + std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); + CHECK(!extension_id.empty()); + return extension_service_->GetExtensionById(extension_id, true); +} + +void ExtensionSettingsHandler::MaybeUpdateAfterNotification() { + TabContents* contents = web_ui_->tab_contents(); + if (!ignore_notifications_ && contents && contents->render_view_host()) + HandleRequestExtensionsData(NULL); + deleting_rvh_ = NULL; +} + +// Static +DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue( + ExtensionService* service, const Extension* extension, + const std::vector<ExtensionPage>& pages, + const ExtensionWarningSet* warnings_set, + bool enabled, bool terminated) { + DictionaryValue* extension_data = new DictionaryValue(); + GURL icon = + ExtensionIconSource::GetIconURL(extension, + Extension::EXTENSION_ICON_MEDIUM, + ExtensionIconSet::MATCH_BIGGER, + !enabled, NULL); + extension_data->SetString("id", extension->id()); + extension_data->SetString("name", extension->name()); + extension_data->SetString("description", extension->description()); + if (extension->location() == Extension::LOAD) + extension_data->SetString("path", extension->path().value()); + extension_data->SetString("version", extension->version()->GetString()); + extension_data->SetString("icon", icon.spec()); + extension_data->SetBoolean("isUnpacked", + extension->location() == Extension::LOAD); + extension_data->SetBoolean("mayDisable", + Extension::UserMayDisable(extension->location())); + extension_data->SetBoolean("enabled", enabled); + extension_data->SetBoolean("terminated", terminated); + extension_data->SetBoolean("enabledIncognito", + service ? service->IsIncognitoEnabled(extension->id()) : false); + extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access()); + extension_data->SetBoolean("allowFileAccess", + service ? service->AllowFileAccess(extension) : false); + extension_data->SetBoolean("allow_reload", + extension->location() == Extension::LOAD); + extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app()); + + // Determine the sort order: Extensions loaded through --load-extensions show + // up at the top. Disabled extensions show up at the bottom. + if (extension->location() == Extension::LOAD) + extension_data->SetInteger("order", 1); + else + extension_data->SetInteger("order", 2); + + if (!extension->options_url().is_empty() && enabled) + extension_data->SetString("options_url", extension->options_url().spec()); + + if (service && !service->GetBrowserActionVisibility(extension)) + extension_data->SetBoolean("enable_show_button", true); + + // Add views + ListValue* views = new ListValue; + for (std::vector<ExtensionPage>::const_iterator iter = pages.begin(); + iter != pages.end(); ++iter) { + DictionaryValue* view_value = new DictionaryValue; + if (iter->url.scheme() == chrome::kExtensionScheme) { + // No leading slash. + view_value->SetString("path", iter->url.path().substr(1)); + } else { + // For live pages, use the full URL. + view_value->SetString("path", iter->url.spec()); + } + view_value->SetInteger("renderViewId", iter->render_view_id); + view_value->SetInteger("renderProcessId", iter->render_process_id); + view_value->SetBoolean("incognito", iter->incognito); + views->Append(view_value); + } + extension_data->Set("views", views); + extension_data->SetBoolean("hasPopupAction", + extension->browser_action() || extension->page_action()); + extension_data->SetString("homepageUrl", extension->GetHomepageURL().spec()); + + // Add warnings. + ListValue* warnings_list = new ListValue; + if (warnings_set) { + std::set<ExtensionWarningSet::WarningType> warnings; + warnings_set->GetWarningsAffectingExtension(extension->id(), &warnings); + + for (std::set<ExtensionWarningSet::WarningType>::const_iterator iter = + warnings.begin(); + iter != warnings.end(); + ++iter) { + string16 warning_string(ExtensionWarningSet::GetLocalizedWarning(*iter)); + warnings_list->Append(Value::CreateStringValue(warning_string)); + } + } + extension_data->Set("warnings", warnings_list); + + return extension_data; +} + +std::vector<ExtensionPage> ExtensionSettingsHandler::GetActivePagesForExtension( + const Extension* extension) { + std::vector<ExtensionPage> result; + + // Get the extension process's active views. + ExtensionProcessManager* process_manager = + extension_service_->profile()->GetExtensionProcessManager(); + GetActivePagesForExtensionProcess( + process_manager->GetRenderViewHostsForExtension( + extension->id()), &result); + + // Repeat for the incognito process, if applicable. + if (extension_service_->profile()->HasOffTheRecordProfile() && + extension->incognito_split_mode()) { + ExtensionProcessManager* process_manager = + extension_service_->profile()->GetOffTheRecordProfile()-> + GetExtensionProcessManager(); + GetActivePagesForExtensionProcess( + process_manager->GetRenderViewHostsForExtension( + extension->id()), &result); + } + + return result; +} + +void ExtensionSettingsHandler::GetActivePagesForExtensionProcess( + const std::set<RenderViewHost*>& views, + std::vector<ExtensionPage> *result) { + for (std::set<RenderViewHost*>::const_iterator iter = views.begin(); + iter != views.end(); ++iter) { + RenderViewHost* host = *iter; + int host_type = host->delegate()->GetRenderViewType(); + if (host == deleting_rvh_ || + chrome::VIEW_TYPE_EXTENSION_POPUP == host_type || + chrome::VIEW_TYPE_EXTENSION_DIALOG == host_type) + continue; + + GURL url = host->delegate()->GetURL(); + content::RenderProcessHost* process = host->process(); + result->push_back( + ExtensionPage(url, process->GetID(), host->routing_id(), + process->GetBrowserContext()->IsOffTheRecord())); + } +} diff --git a/chrome/browser/ui/webui/options2/extension_settings_handler.h b/chrome/browser/ui/webui/options2/extension_settings_handler.h new file mode 100644 index 0000000..a03908d --- /dev/null +++ b/chrome/browser/ui/webui/options2/extension_settings_handler.h @@ -0,0 +1,200 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_EXTENSION_SETTINGS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_EXTENSION_SETTINGS_HANDLER_H_ +#pragma once + +#include <set> +#include <string> +#include <vector> + +#include "chrome/browser/extensions/extension_install_ui.h" +#include "chrome/browser/extensions/extension_uninstall_dialog.h" +#include "chrome/browser/extensions/extension_warning_set.h" +#include "chrome/browser/ui/select_file_dialog.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "chrome/browser/ui/webui/chrome_web_ui.h" +#include "chrome/common/extensions/extension_resource.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "googleurl/src/gurl.h" + +class Extension; +class ExtensionService; +class FilePath; +class PrefService; +class UserScript; + +namespace base { +class DictionaryValue; +class ListValue; +} + +// Information about a page running in an extension, for example a popup bubble, +// a background page, or a tab contents. +struct ExtensionPage { + ExtensionPage(const GURL& url, int render_process_id, int render_view_id, + bool incognito) + : url(url), + render_process_id(render_process_id), + render_view_id(render_view_id), + incognito(incognito) {} + GURL url; + int render_process_id; + int render_view_id; + bool incognito; +}; + +// Extension Settings UI handler. +class ExtensionSettingsHandler : public OptionsPage2UIHandler, + public SelectFileDialog::Listener, + public ExtensionUninstallDialog::Delegate { + public: + ExtensionSettingsHandler(); + virtual ~ExtensionSettingsHandler(); + + static void RegisterUserPrefs(PrefService* prefs); + + // Extension Detail JSON Struct for page. (static for ease of testing). + // Note: |service| and |warnings| can be NULL in unit tests. + static base::DictionaryValue* CreateExtensionDetailValue( + ExtensionService* service, + const Extension* extension, + const std::vector<ExtensionPage>& pages, + const ExtensionWarningSet* warnings, + bool enabled, + bool terminated); + + // ContentScript JSON Struct for page. (static for ease of testing). + static base::DictionaryValue* CreateContentScriptDetailValue( + const UserScript& script, + const FilePath& extension_path); + + // Callback for "requestExtensionsData" message. + void HandleRequestExtensionsData(const base::ListValue* args); + + // Callback for "toggleDeveloperMode" message. + void HandleToggleDeveloperMode(const base::ListValue* args); + + // Callback for "inspect" message. + void HandleInspectMessage(const base::ListValue* args); + + // Callback for "reload" message. + void HandleReloadMessage(const base::ListValue* args); + + // Callback for "enable" message. + void HandleEnableMessage(const base::ListValue* args); + + // Callback for "enableIncognito" message. + void HandleEnableIncognitoMessage(const base::ListValue* args); + + // Callback for "allowFileAcces" message. + void HandleAllowFileAccessMessage(const base::ListValue* args); + + // Callback for "uninstall" message. + void HandleUninstallMessage(const base::ListValue* args); + + // Callback for "options" message. + void HandleOptionsMessage(const base::ListValue* args); + + // Callback for "showButton" message. + void HandleShowButtonMessage(const base::ListValue* args); + + // Callback for "load" message. + void HandleLoadMessage(const base::ListValue* args); + + // Callback for "pack" message. + void HandlePackMessage(const base::ListValue* args); + + // Callback for "autoupdate" message. + void HandleAutoUpdateMessage(const base::ListValue* args); + + // Utility for calling javascript window.alert in the page. + void ShowAlert(const std::string& message); + + // Callback for "selectFilePath" message. + void HandleSelectFilePathMessage(const base::ListValue* args); + + // Utility for callbacks that get an extension ID as the sole argument. + const Extension* GetExtension(const base::ListValue* args); + + // Forces a UI update if appropriate after a notification is received. + void MaybeUpdateAfterNotification(); + + // Register for notifications that we need to reload the page. + void MaybeRegisterForNotifications(); + + // SelectFileDialog::Listener + virtual void FileSelected(const FilePath& path, + int index, void* params) OVERRIDE; + virtual void MultiFilesSelected( + const std::vector<FilePath>& files, void* params) OVERRIDE; + virtual void FileSelectionCanceled(void* params) OVERRIDE {} + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE; + + // OptionsUIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // ExtensionUninstallDialog::Delegate implementation, used for receiving + // notification about uninstall confirmation dialog selections. + virtual void ExtensionUninstallAccepted() OVERRIDE; + virtual void ExtensionUninstallCanceled() OVERRIDE; + + private: + // Helper that lists the current active html pages for an extension. + std::vector<ExtensionPage> GetActivePagesForExtension( + const Extension* extension); + void GetActivePagesForExtensionProcess( + const std::set<RenderViewHost*>& views, + std::vector<ExtensionPage> *result); + + // Returns the ExtensionUninstallDialog object for this class, creating it if + // needed. + ExtensionUninstallDialog* GetExtensionUninstallDialog(); + + // Our model. Outlives us since it's owned by our containing profile. + ExtensionService* extension_service_; + + // Used to pick the directory when loading an extension. + scoped_refptr<SelectFileDialog> load_extension_dialog_; + + // Used to show confirmation UI for uninstalling extensions in incognito mode. + scoped_ptr<ExtensionUninstallDialog> extension_uninstall_dialog_; + + // The id of the extension we are prompting the user about. + std::string extension_id_prompting_; + + // If true, we will ignore notifications in ::Observe(). This is needed + // to prevent reloading the page when we were the cause of the + // notification. + bool ignore_notifications_; + + // The page may be refreshed in response to a RENDER_VIEW_HOST_DELETED, + // but the iteration over RenderViewHosts will include the host because the + // notification is sent when it is in the process of being deleted (and before + // it is removed from the process). Keep a pointer to it so we can exclude + // it from the active views. + RenderViewHost* deleting_rvh_; + + // We want to register for notifications only after we've responded at least + // once to the page, otherwise we'd be calling javacsript functions on objects + // that don't exist yet when notifications come in. This variable makes sure + // we do so only once. + bool registered_for_notifications_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionSettingsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_EXTENSION_SETTINGS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/font_settings_browsertest.js b/chrome/browser/ui/webui/options2/font_settings_browsertest.js new file mode 100644 index 0000000..9800b41 --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for font settings WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function FontSettingsWebUITest() {} + +FontSettingsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the font settings page. + **/ + browsePreload: 'chrome://settings/fonts', +}; + +// Test opening font settings has correct location. +TEST_F('FontSettingsWebUITest', 'testOpenFontSettings', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/font_settings_handler.cc b/chrome/browser/ui/webui/options2/font_settings_handler.cc new file mode 100644 index 0000000..2ffef10b --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_handler.cc @@ -0,0 +1,211 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/font_settings_handler.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/i18n/rtl.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/character_encoding.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/options2/font_settings_utils.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/notification_details.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +FontSettingsHandler::FontSettingsHandler() { +} + +FontSettingsHandler::~FontSettingsHandler() { +} + +void FontSettingsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "fontSettingsStandard", + IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_STANDARD_LABEL }, + { "fontSettingsSerif", + IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SERIF_LABEL }, + { "fontSettingsSansSerif", + IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SANS_SERIF_LABEL }, + { "fontSettingsFixedWidth", + IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_FIXED_WIDTH_LABEL }, + { "fontSettingsMinimumSize", + IDS_FONT_LANGUAGE_SETTING_MINIMUM_FONT_SIZE_TITLE }, + { "fontSettingsEncoding", + IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_ENCODING_TITLE }, + { "fontSettingsSizeTiny", + IDS_FONT_LANGUAGE_SETTING_FONT_SIZE_TINY }, + { "fontSettingsSizeHuge", + IDS_FONT_LANGUAGE_SETTING_FONT_SIZE_HUGE }, + { "fontSettingsLoremIpsum", + IDS_FONT_LANGUAGE_SETTING_LOREM_IPSUM }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "fontSettingsPage", + IDS_FONT_LANGUAGE_SETTING_FONT_TAB_TITLE); + localized_strings->SetString("fontSettingsPlaceholder", + l10n_util::GetStringUTF16( + IDS_FONT_LANGUAGE_SETTING_PLACEHOLDER)); +} + +void FontSettingsHandler::Initialize() { + DCHECK(web_ui_); + SetUpStandardFontSample(); + SetUpSerifFontSample(); + SetUpSansSerifFontSample(); + SetUpFixedFontSample(); + SetUpMinimumFontSample(); +} + +WebUIMessageHandler* FontSettingsHandler::Attach(WebUI* web_ui) { + // Call through to superclass. + WebUIMessageHandler* handler = OptionsPage2UIHandler::Attach(web_ui); + + // Perform validation for saved fonts. + DCHECK(web_ui_); + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + FontSettingsUtilities::ValidateSavedFonts(pref_service); + + // Register for preferences that we need to observe manually. + standard_font_.Init(prefs::kWebKitStandardFontFamily, pref_service, this); + serif_font_.Init(prefs::kWebKitSerifFontFamily, pref_service, this); + sans_serif_font_.Init(prefs::kWebKitSansSerifFontFamily, pref_service, this); + fixed_font_.Init(prefs::kWebKitFixedFontFamily, pref_service, this); + font_encoding_.Init(prefs::kDefaultCharset, pref_service, this); + default_font_size_.Init(prefs::kWebKitDefaultFontSize, pref_service, this); + default_fixed_font_size_.Init(prefs::kWebKitDefaultFixedFontSize, + pref_service, this); + minimum_font_size_.Init(prefs::kWebKitMinimumFontSize, pref_service, this); + + // Return result from the superclass. + return handler; +} + +void FontSettingsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("fetchFontsData", + base::Bind(&FontSettingsHandler::HandleFetchFontsData, + base::Unretained(this))); +} + +void FontSettingsHandler::HandleFetchFontsData(const ListValue* args) { + content::GetFontListAsync( + base::Bind(&FontSettingsHandler::FontsListHasLoaded, + base::Unretained(this))); +} + +void FontSettingsHandler::FontsListHasLoaded( + scoped_refptr<content::FontListResult> list) { + ListValue encoding_list; + const std::vector<CharacterEncoding::EncodingInfo>* encodings; + PrefService* pref_service = Profile::FromWebUI(web_ui_)->GetPrefs(); + encodings = CharacterEncoding::GetCurrentDisplayEncodings( + g_browser_process->GetApplicationLocale(), + pref_service->GetString(prefs::kStaticEncodings), + pref_service->GetString(prefs::kRecentlySelectedEncoding)); + DCHECK(encodings); + DCHECK(!encodings->empty()); + + std::vector<CharacterEncoding::EncodingInfo>::const_iterator it; + for (it = encodings->begin(); it != encodings->end(); ++it) { + ListValue* option = new ListValue(); + if (it->encoding_id) { + int cmd_id = it->encoding_id; + std::string encoding = + CharacterEncoding::GetCanonicalEncodingNameByCommandId(cmd_id); + string16 name = it->encoding_display_name; + base::i18n::AdjustStringForLocaleDirection(&name); + option->Append(Value::CreateStringValue(encoding)); + option->Append(Value::CreateStringValue(name)); + } else { + // Add empty name/value to indicate a separator item. + option->Append(Value::CreateStringValue("")); + option->Append(Value::CreateStringValue("")); + } + encoding_list.Append(option); + } + + ListValue selected_values; + selected_values.Append(Value::CreateStringValue(standard_font_.GetValue())); + selected_values.Append(Value::CreateStringValue(serif_font_.GetValue())); + selected_values.Append(Value::CreateStringValue(sans_serif_font_.GetValue())); + selected_values.Append(Value::CreateStringValue(fixed_font_.GetValue())); + selected_values.Append(Value::CreateStringValue(font_encoding_.GetValue())); + + web_ui_->CallJavascriptFunction("FontSettings.setFontsData", + *list->list.get(), encoding_list, + selected_values); +} + +void FontSettingsHandler::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PREF_CHANGED) { + std::string* pref_name = content::Details<std::string>(details).ptr(); + if (*pref_name == prefs::kWebKitStandardFontFamily) { + SetUpStandardFontSample(); + } else if (*pref_name == prefs::kWebKitSerifFontFamily) { + SetUpSerifFontSample(); + } else if (*pref_name == prefs::kWebKitSansSerifFontFamily) { + SetUpSansSerifFontSample(); + } else if (*pref_name == prefs::kWebKitFixedFontFamily || + *pref_name == prefs::kWebKitDefaultFixedFontSize) { + SetUpFixedFontSample(); + } else if (*pref_name == prefs::kWebKitDefaultFontSize) { + SetUpStandardFontSample(); + SetUpSerifFontSample(); + SetUpSansSerifFontSample(); + } else if (*pref_name == prefs::kWebKitMinimumFontSize) { + SetUpMinimumFontSample(); + } + } +} + +void FontSettingsHandler::SetUpStandardFontSample() { + base::StringValue font_value(standard_font_.GetValue()); + base::FundamentalValue size_value(default_font_size_.GetValue()); + web_ui_->CallJavascriptFunction( + "FontSettings.setUpStandardFontSample", font_value, size_value); +} + +void FontSettingsHandler::SetUpSerifFontSample() { + base::StringValue font_value(serif_font_.GetValue()); + base::FundamentalValue size_value(default_font_size_.GetValue()); + web_ui_->CallJavascriptFunction( + "FontSettings.setUpSerifFontSample", font_value, size_value); +} + +void FontSettingsHandler::SetUpSansSerifFontSample() { + base::StringValue font_value(sans_serif_font_.GetValue()); + base::FundamentalValue size_value(default_font_size_.GetValue()); + web_ui_->CallJavascriptFunction( + "FontSettings.setUpSansSerifFontSample", font_value, size_value); +} + +void FontSettingsHandler::SetUpFixedFontSample() { + base::StringValue font_value(fixed_font_.GetValue()); + base::FundamentalValue size_value(default_fixed_font_size_.GetValue()); + web_ui_->CallJavascriptFunction( + "FontSettings.setUpFixedFontSample", font_value, size_value); +} + +void FontSettingsHandler::SetUpMinimumFontSample() { + base::FundamentalValue size_value(minimum_font_size_.GetValue()); + web_ui_->CallJavascriptFunction("FontSettings.setUpMinimumFontSample", + size_value); +} diff --git a/chrome/browser/ui/webui/options2/font_settings_handler.h b/chrome/browser/ui/webui/options2/font_settings_handler.h new file mode 100644 index 0000000..ff45f47 --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_handler.h @@ -0,0 +1,55 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_FONT_SETTINGS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_FONT_SETTINGS_HANDLER_H_ +#pragma once + +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "content/browser/font_list_async.h" + +// Font settings overlay page UI handler. +class FontSettingsHandler : public OptionsPage2UIHandler { + public: + FontSettingsHandler(); + virtual ~FontSettingsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler implementation. + virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + void HandleFetchFontsData(const ListValue* args); + + void FontsListHasLoaded(scoped_refptr<content::FontListResult> list); + + void SetUpStandardFontSample(); + void SetUpSerifFontSample(); + void SetUpSansSerifFontSample(); + void SetUpFixedFontSample(); + void SetUpMinimumFontSample(); + + StringPrefMember standard_font_; + StringPrefMember serif_font_; + StringPrefMember sans_serif_font_; + StringPrefMember fixed_font_; + StringPrefMember font_encoding_; + IntegerPrefMember default_font_size_; + IntegerPrefMember default_fixed_font_size_; + IntegerPrefMember minimum_font_size_; + + DISALLOW_COPY_AND_ASSIGN(FontSettingsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_FONT_SETTINGS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/font_settings_utils.h b/chrome/browser/ui/webui/options2/font_settings_utils.h new file mode 100644 index 0000000..9fb435c --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_utils.h @@ -0,0 +1,22 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_FONT_SETTINGS_UTILS_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_FONT_SETTINGS_UTILS_H_ +#pragma once + +#include "base/basictypes.h" + +class PrefService; + +// Chrome advanced options utility methods. +class FontSettingsUtilities { + public: + static void ValidateSavedFonts(PrefService* prefs); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(FontSettingsUtilities); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_FONT_SETTINGS_UTILS_H_ diff --git a/chrome/browser/ui/webui/options2/font_settings_utils_mac.mm b/chrome/browser/ui/webui/options2/font_settings_utils_mac.mm new file mode 100644 index 0000000..0d26d83 --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_utils_mac.mm @@ -0,0 +1,38 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/font_settings_utils.h" + +#import <Cocoa/Cocoa.h> + +#include "base/mac/scoped_nsautorelease_pool.h" +#include "base/sys_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/common/pref_names.h" + +static void ValidateFontFamily(PrefService* prefs, + const char* family_pref_name) { + // The native font settings dialog saved fonts by the font name, rather + // than the family name. This worked for the old dialog since + // -[NSFont fontWithName:size] accepted a font or family name, but the + // behavior was technically wrong. Since we really need the family name for + // the dom-ui options window, we will fix the saved preference if necessary. + NSString *family_name = + base::SysUTF8ToNSString(prefs->GetString(family_pref_name)); + NSFont *font = [NSFont fontWithName:family_name + size:[NSFont systemFontSize]]; + if (font && + [[font familyName] caseInsensitiveCompare:family_name] != NSOrderedSame) { + std::string new_family_name = base::SysNSStringToUTF8([font familyName]); + prefs->SetString(family_pref_name, new_family_name); + } +} + +// static +void FontSettingsUtilities::ValidateSavedFonts(PrefService* prefs) { + ValidateFontFamily(prefs, prefs::kWebKitSerifFontFamily); + ValidateFontFamily(prefs, prefs::kWebKitSansSerifFontFamily); + ValidateFontFamily(prefs, prefs::kWebKitFixedFontFamily); +} diff --git a/chrome/browser/ui/webui/options2/font_settings_utils_win.cc b/chrome/browser/ui/webui/options2/font_settings_utils_win.cc new file mode 100644 index 0000000..3c5ff5e --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_utils_win.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/font_settings_utils.h" + +// static +void FontSettingsUtilities::ValidateSavedFonts(PrefService* prefs) { + // Nothing to do for Windows. +} + diff --git a/chrome/browser/ui/webui/options2/font_settings_utils_x11.cc b/chrome/browser/ui/webui/options2/font_settings_utils_x11.cc new file mode 100644 index 0000000..61c2c6e --- /dev/null +++ b/chrome/browser/ui/webui/options2/font_settings_utils_x11.cc @@ -0,0 +1,10 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/font_settings_utils.h" + +// static +void FontSettingsUtilities::ValidateSavedFonts(PrefService* prefs) { + // Nothing to do for X11. +} diff --git a/chrome/browser/ui/webui/options2/handler_options_handler.cc b/chrome/browser/ui/webui/options2/handler_options_handler.cc new file mode 100644 index 0000000..4c4c30f --- /dev/null +++ b/chrome/browser/ui/webui/options2/handler_options_handler.cc @@ -0,0 +1,207 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/handler_options_handler.h" + +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_notification_types.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + + +HandlerOptionsHandler::HandlerOptionsHandler() { +} + +HandlerOptionsHandler::~HandlerOptionsHandler() { +} + +void HandlerOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "handlers_tab_label", IDS_HANDLERS_TAB_LABEL }, + { "handlers_allow", IDS_HANDLERS_ALLOW_RADIO }, + { "handlers_block", IDS_HANDLERS_DONOTALLOW_RADIO }, + { "handlers_type_column_header", IDS_HANDLERS_TYPE_COLUMN_HEADER }, + { "handlers_site_column_header", IDS_HANDLERS_SITE_COLUMN_HEADER }, + { "handlers_remove_link", IDS_HANDLERS_REMOVE_HANDLER_LINK }, + { "handlers_none_handler", IDS_HANDLERS_NONE_HANDLER }, + { "handlers_active_heading", IDS_HANDLERS_ACTIVE_HEADING }, + { "handlers_ignored_heading", IDS_HANDLERS_IGNORED_HEADING }, + }; + RegisterTitle(localized_strings, "handlersPage", + IDS_HANDLER_OPTIONS_WINDOW_TITLE); + RegisterStrings(localized_strings, resources, arraysize(resources)); +} + +void HandlerOptionsHandler::Initialize() { + UpdateHandlerList(); + notification_registrar_.Add( + this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, + content::Source<Profile>(Profile::FromWebUI(web_ui_))); +} + +void HandlerOptionsHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("clearDefault", + base::Bind(&HandlerOptionsHandler::ClearDefault, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeHandler", + base::Bind(&HandlerOptionsHandler::RemoveHandler, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setHandlersEnabled", + base::Bind(&HandlerOptionsHandler::SetHandlersEnabled, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("setDefault", + base::Bind(&HandlerOptionsHandler::SetDefault, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeIgnoredHandler", + base::Bind(&HandlerOptionsHandler::RemoveIgnoredHandler, + base::Unretained(this))); +} + +ProtocolHandlerRegistry* HandlerOptionsHandler::GetProtocolHandlerRegistry() { + DCHECK(web_ui_); + return Profile::FromWebUI(web_ui_)->GetProtocolHandlerRegistry(); +} + +static void GetHandlersAsListValue( + const ProtocolHandlerRegistry::ProtocolHandlerList& handlers, + ListValue* handler_list) { + ProtocolHandlerRegistry::ProtocolHandlerList::const_iterator handler; + for (handler = handlers.begin(); handler != handlers.end(); ++handler) { + ListValue* handlerValue = new ListValue(); + handlerValue->Append(Value::CreateStringValue(handler->protocol())); + handlerValue->Append(Value::CreateStringValue(handler->url().spec())); + handlerValue->Append(Value::CreateStringValue(handler->title())); + handler_list->Append(handlerValue); + } +} + +void HandlerOptionsHandler::GetHandlersForProtocol( + const std::string& protocol, + DictionaryValue* handlers_value) { + ProtocolHandlerRegistry* registry = GetProtocolHandlerRegistry(); + handlers_value->SetString("protocol", protocol); + handlers_value->SetInteger("default_handler", + registry->GetHandlerIndex(protocol)); + + ListValue* handlers_list = new ListValue(); + GetHandlersAsListValue(registry->GetHandlersFor(protocol), handlers_list); + handlers_value->Set("handlers", handlers_list); +} + +void HandlerOptionsHandler::GetIgnoredHandlers(ListValue* handlers) { + ProtocolHandlerRegistry* registry = GetProtocolHandlerRegistry(); + ProtocolHandlerRegistry::ProtocolHandlerList ignored_handlers = + registry->GetIgnoredHandlers(); + return GetHandlersAsListValue(ignored_handlers, handlers); +} + +void HandlerOptionsHandler::UpdateHandlerList() { +#if defined(ENABLE_REGISTER_PROTOCOL_HANDLER) + ProtocolHandlerRegistry* registry = GetProtocolHandlerRegistry(); + std::vector<std::string> protocols; + registry->GetRegisteredProtocols(&protocols); + + ListValue handlers; + for (std::vector<std::string>::iterator protocol = protocols.begin(); + protocol != protocols.end(); protocol++) { + DictionaryValue* handler_value = new DictionaryValue(); + GetHandlersForProtocol(*protocol, handler_value); + handlers.Append(handler_value); + } + + scoped_ptr<ListValue> ignored_handlers(new ListValue()); + GetIgnoredHandlers(ignored_handlers.get()); + web_ui_->CallJavascriptFunction("HandlerOptions.setHandlers", handlers); + web_ui_->CallJavascriptFunction("HandlerOptions.setIgnoredHandlers", + *ignored_handlers); +#endif // defined(ENABLE_REGISTER_PROTOCOL_HANDLER) +} + +void HandlerOptionsHandler::RemoveHandler(const ListValue* args) { + ListValue* list; + if (!args->GetList(0, &list)) { + NOTREACHED(); + return; + } + + ProtocolHandler handler(ParseHandlerFromArgs(list)); + GetProtocolHandlerRegistry()->RemoveHandler(handler); + + // No need to call UpdateHandlerList() - we should receive a notification + // that the ProtocolHandlerRegistry has changed and we will update the view + // then. +} + +void HandlerOptionsHandler::RemoveIgnoredHandler(const ListValue* args) { + ListValue* list; + if (!args->GetList(0, &list)) { + NOTREACHED(); + return; + } + + ProtocolHandler handler(ParseHandlerFromArgs(list)); + GetProtocolHandlerRegistry()->RemoveIgnoredHandler(handler); +} + +void HandlerOptionsHandler::SetHandlersEnabled(const ListValue* args) { + bool enabled = true; + CHECK(args->GetBoolean(0, &enabled)); + if (enabled) + GetProtocolHandlerRegistry()->Enable(); + else + GetProtocolHandlerRegistry()->Disable(); +} + +void HandlerOptionsHandler::ClearDefault(const ListValue* args) { + Value* value; + CHECK(args->Get(0, &value)); + std::string protocol_to_clear; + CHECK(value->GetAsString(&protocol_to_clear)); + GetProtocolHandlerRegistry()->ClearDefault(protocol_to_clear); +} + +void HandlerOptionsHandler::SetDefault(const ListValue* args) { + Value* value; + CHECK(args->Get(0, &value)); + ListValue* list; + CHECK(args->GetList(0, &list)); + const ProtocolHandler& handler(ParseHandlerFromArgs(list)); + CHECK(!handler.IsEmpty()); + GetProtocolHandlerRegistry()->OnAcceptRegisterProtocolHandler(handler); +} + +ProtocolHandler HandlerOptionsHandler::ParseHandlerFromArgs( + const ListValue* args) const { + string16 protocol; + string16 url; + string16 title; + bool ok = args->GetString(0, &protocol) && args->GetString(1, &url) && + args->GetString(2, &title); + if (!ok) + return ProtocolHandler::EmptyProtocolHandler(); + return ProtocolHandler::CreateProtocolHandler(UTF16ToUTF8(protocol), + GURL(UTF16ToUTF8(url)), + title); +} + +void HandlerOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED) + UpdateHandlerList(); + else + NOTREACHED(); +} diff --git a/chrome/browser/ui/webui/options2/handler_options_handler.h b/chrome/browser/ui/webui/options2/handler_options_handler.h new file mode 100644 index 0000000..87f9149 --- /dev/null +++ b/chrome/browser/ui/webui/options2/handler_options_handler.h @@ -0,0 +1,76 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_HANDLER_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_HANDLER_OPTIONS_HANDLER_H_ + +#include <string> + +#include "chrome/browser/custom_handlers/protocol_handler_registry.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "chrome/common/custom_handlers/protocol_handler.h" +#include "content/public/browser/notification_registrar.h" + +namespace base { +class DictionaryValue; +} + +class HandlerOptionsHandler : public OptionsPage2UIHandler { + public: + HandlerOptionsHandler(); + virtual ~HandlerOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + // Called when the user toggles whether custom handlers are enabled. + void SetHandlersEnabled(const ListValue* args); + + // Called when the user sets a new default handler for a protocol. + void SetDefault(const ListValue* args); + + // Called when the user clears the default handler for a protocol. + // |args| is the string name of the protocol to clear. + void ClearDefault(const ListValue* args); + + // Parses a ProtocolHandler out of the arguments passed back from the view. + // |args| is a list of [protocol, url, title]. + ProtocolHandler ParseHandlerFromArgs(const ListValue* args) const; + + // Returns a JSON object describing the set of protocol handlers for the + // given protocol. + void GetHandlersForProtocol(const std::string& protocol, + base::DictionaryValue* value); + + // Returns a JSON list of the ignored protocol handlers. + void GetIgnoredHandlers(ListValue* handlers); + + // Called when the JS PasswordManager object is initialized. + void UpdateHandlerList(); + + // Remove a handler. + // |args| is a list of [protocol, url, title]. + void RemoveHandler(const ListValue* args); + + // Remove an ignored handler. + // |args| is a list of [protocol, url, title]. + void RemoveIgnoredHandler(const ListValue* args); + + ProtocolHandlerRegistry* GetProtocolHandlerRegistry(); + + content::NotificationRegistrar notification_registrar_; + + DISALLOW_COPY_AND_ASSIGN(HandlerOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_HANDLER_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/import_data_handler.cc b/chrome/browser/ui/webui/options2/import_data_handler.cc new file mode 100644 index 0000000..76e5b83 --- /dev/null +++ b/chrome/browser/ui/webui/options2/import_data_handler.cc @@ -0,0 +1,177 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/import_data_handler.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "base/threading/thread_restrictions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/importer/external_process_importer_host.h" +#include "chrome/browser/importer/importer_host.h" +#include "chrome/browser/importer/importer_list.h" +#include "chrome/browser/profiles/profile.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +ImportDataHandler::ImportDataHandler() : importer_host_(NULL), + import_did_succeed_(false) { +} + +ImportDataHandler::~ImportDataHandler() { + if (importer_list_) + importer_list_->SetObserver(NULL); + + if (importer_host_) + importer_host_->SetObserver(NULL); +} + +void ImportDataHandler::GetLocalizedValues(DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "importFromLabel", IDS_IMPORT_FROM_LABEL }, + { "importLoading", IDS_IMPORT_LOADING_PROFILES }, + { "importDescription", IDS_IMPORT_ITEMS_LABEL }, + { "importHistory", IDS_IMPORT_HISTORY_CHKBOX }, + { "importFavorites", IDS_IMPORT_FAVORITES_CHKBOX }, + { "importSearch", IDS_IMPORT_SEARCH_ENGINES_CHKBOX }, + { "importPasswords", IDS_IMPORT_PASSWORDS_CHKBOX }, + { "importCommit", IDS_IMPORT_COMMIT }, + { "noProfileFound", IDS_IMPORT_NO_PROFILE_FOUND }, + { "importSucceeded", IDS_IMPORT_SUCCEEDED }, + { "findYourImportedBookmarks", IDS_IMPORT_FIND_YOUR_BOOKMARKS }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "importDataOverlay", + IDS_IMPORT_SETTINGS_TITLE); +} + +void ImportDataHandler::Initialize() { + Profile* profile = Profile::FromWebUI(web_ui_); + importer_list_ = new ImporterList(profile->GetRequestContext()); + importer_list_->DetectSourceProfiles(this); +} + +void ImportDataHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("importData", + base::Bind(&ImportDataHandler::ImportData, base::Unretained(this))); +} + +void ImportDataHandler::ImportData(const ListValue* args) { + std::string string_value; + + int browser_index; + if (!args->GetString(0, &string_value) || + !base::StringToInt(string_value, &browser_index)) { + NOTREACHED(); + return; + } + + uint16 selected_items = importer::NONE; + if (args->GetString(1, &string_value) && string_value == "true") { + selected_items |= importer::HISTORY; + } + if (args->GetString(2, &string_value) && string_value == "true") { + selected_items |= importer::FAVORITES; + } + if (args->GetString(3, &string_value) && string_value == "true") { + selected_items |= importer::PASSWORDS; + } + if (args->GetString(4, &string_value) && string_value == "true") { + selected_items |= importer::SEARCH_ENGINES; + } + + const importer::SourceProfile& source_profile = + importer_list_->GetSourceProfileAt(browser_index); + uint16 supported_items = source_profile.services_supported; + + uint16 import_services = (selected_items & supported_items); + if (import_services) { + base::FundamentalValue state(true); + web_ui_->CallJavascriptFunction("ImportDataOverlay.setImportingState", + state); + import_did_succeed_ = false; + + // TODO(csilv): Out-of-process import has only been qualified on MacOS X, + // so we will only use it on that platform since it is required. Remove this + // conditional logic once oop import is qualified for Linux/Windows. + // http://crbug.com/22142 +#if defined(OS_MACOSX) + importer_host_ = new ExternalProcessImporterHost; +#else + importer_host_ = new ImporterHost; +#endif + importer_host_->SetObserver(this); + Profile* profile = Profile::FromWebUI(web_ui_); + importer_host_->StartImportSettings(source_profile, profile, + import_services, + new ProfileWriter(profile), false); + } else { + LOG(WARNING) << "There were no settings to import from '" + << source_profile.importer_name << "'."; + } +} + +void ImportDataHandler::OnSourceProfilesLoaded() { + ListValue browser_profiles; + for (size_t i = 0; i < importer_list_->count(); ++i) { + const importer::SourceProfile& source_profile = + importer_list_->GetSourceProfileAt(i); + uint16 browser_services = source_profile.services_supported; + + DictionaryValue* browser_profile = new DictionaryValue(); + browser_profile->SetString("name", source_profile.importer_name); + browser_profile->SetInteger("index", i); + browser_profile->SetBoolean("history", + (browser_services & importer::HISTORY) != 0); + browser_profile->SetBoolean("favorites", + (browser_services & importer::FAVORITES) != 0); + browser_profile->SetBoolean("passwords", + (browser_services & importer::PASSWORDS) != 0); + browser_profile->SetBoolean("search", + (browser_services & importer::SEARCH_ENGINES) != 0); + + browser_profiles.Append(browser_profile); + } + + web_ui_->CallJavascriptFunction("ImportDataOverlay.updateSupportedBrowsers", + browser_profiles); +} + +void ImportDataHandler::ImportStarted() { +} + +void ImportDataHandler::ImportItemStarted(importer::ImportItem item) { + // TODO(csilv): show progress detail in the web view. +} + +void ImportDataHandler::ImportItemEnded(importer::ImportItem item) { + // TODO(csilv): show progress detail in the web view. + import_did_succeed_ = true; +} + +void ImportDataHandler::ImportEnded() { + importer_host_->SetObserver(NULL); + importer_host_ = NULL; + + if (import_did_succeed_) { + web_ui_->CallJavascriptFunction("ImportDataOverlay.confirmSuccess"); + } else { + base::FundamentalValue state(false); + web_ui_->CallJavascriptFunction("ImportDataOverlay.setImportingState", + state); + web_ui_->CallJavascriptFunction("ImportDataOverlay.dismiss"); + } +} diff --git a/chrome/browser/ui/webui/options2/import_data_handler.h b/chrome/browser/ui/webui/options2/import_data_handler.h new file mode 100644 index 0000000..da6b82c --- /dev/null +++ b/chrome/browser/ui/webui/options2/import_data_handler.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_IMPORT_DATA_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_IMPORT_DATA_HANDLER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "chrome/browser/importer/importer_list_observer.h" +#include "chrome/browser/importer/importer_progress_observer.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +class ImporterHost; +class ImporterList; + +// Chrome personal stuff import data overlay UI handler. +class ImportDataHandler : public OptionsPage2UIHandler, + public importer::ImporterListObserver, + public importer::ImporterProgressObserver { + public: + ImportDataHandler(); + virtual ~ImportDataHandler(); + + // OptionsPage2UIHandler: + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler: + virtual void RegisterMessages() OVERRIDE; + + private: + void ImportData(const base::ListValue* args); + + // importer::ImporterListObserver: + virtual void OnSourceProfilesLoaded() OVERRIDE; + + // importer::ImporterProgressObserver: + virtual void ImportStarted() OVERRIDE; + virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE; + virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE; + virtual void ImportEnded() OVERRIDE; + + scoped_refptr<ImporterList> importer_list_; + + // If non-null it means importing is in progress. ImporterHost takes care + // of deleting itself when import is complete. + ImporterHost* importer_host_; // weak + + bool import_did_succeed_; + + DISALLOW_COPY_AND_ASSIGN(ImportDataHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_IMPORT_DATA_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/language_options_browsertest.js b/chrome/browser/ui/webui/options2/language_options_browsertest.js new file mode 100644 index 0000000..4f1b87c --- /dev/null +++ b/chrome/browser/ui/webui/options2/language_options_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for languages options WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function LanguagesOptionsWebUITest() {} + +LanguagesOptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to languages options. + **/ + browsePreload: 'chrome://settings/languages', +}; + +// Test opening languages options has correct location. +TEST_F('LanguagesOptionsWebUITest', 'testOpenLanguagesOptions', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/language_options_handler.cc b/chrome/browser/ui/webui/options2/language_options_handler.cc new file mode 100644 index 0000000..c521b2c --- /dev/null +++ b/chrome/browser/ui/webui/options2/language_options_handler.cc @@ -0,0 +1,116 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/language_options_handler.h" + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/i18n/rtl.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "content/browser/user_metrics.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +LanguageOptionsHandler::LanguageOptionsHandler() { +} + +LanguageOptionsHandler::~LanguageOptionsHandler() { +} + +void LanguageOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + LanguageOptionsHandlerCommon::GetLocalizedValues(localized_strings); + + RegisterTitle(localized_strings, "languagePage", + IDS_OPTIONS_SETTINGS_LANGUAGES_DIALOG_TITLE); + localized_strings->SetString("restart_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_RELAUNCH_BUTTON)); + localized_strings->Set("languageList", GetLanguageList()); +} + +void LanguageOptionsHandler::RegisterMessages() { + LanguageOptionsHandlerCommon::RegisterMessages(); + + web_ui_->RegisterMessageCallback("uiLanguageRestart", + base::Bind(&LanguageOptionsHandler::RestartCallback, + base::Unretained(this))); +} + +ListValue* LanguageOptionsHandler::GetLanguageList() { + // Collect the language codes from the supported accept-languages. + const std::string app_locale = g_browser_process->GetApplicationLocale(); + std::vector<std::string> language_codes; + l10n_util::GetAcceptLanguagesForLocale(app_locale, &language_codes); + + // Map of display name -> {language code, native_display_name}. + // In theory, we should be able to create a map that is sorted by + // display names using ICU comparator, but doing it is hard, thus we'll + // use an auxiliary vector to achieve the same result. + typedef std::pair<std::string, string16> LanguagePair; + typedef std::map<string16, LanguagePair> LanguageMap; + LanguageMap language_map; + // The auxiliary vector mentioned above. + std::vector<string16> display_names; + + // Build the list of display names, and build the language map. + for (size_t i = 0; i < language_codes.size(); ++i) { + string16 display_name = + l10n_util::GetDisplayNameForLocale(language_codes[i], app_locale, + false); + base::i18n::AdjustStringForLocaleDirection(&display_name); + string16 native_display_name = + l10n_util::GetDisplayNameForLocale(language_codes[i], language_codes[i], + false); + base::i18n::AdjustStringForLocaleDirection(&native_display_name); + display_names.push_back(display_name); + language_map[display_name] = + std::make_pair(language_codes[i], native_display_name); + } + DCHECK_EQ(display_names.size(), language_map.size()); + + // Sort display names using locale specific sorter. + l10n_util::SortStrings16(app_locale, &display_names); + + // Build the language list from the language map. + ListValue* language_list = new ListValue(); + for (size_t i = 0; i < display_names.size(); ++i) { + const LanguagePair& pair = language_map[display_names[i]]; + DictionaryValue* dictionary = new DictionaryValue(); + dictionary->SetString("code", pair.first); + dictionary->SetString("displayName", display_names[i]); + dictionary->SetString("nativeDisplayName", pair.second); + language_list->Append(dictionary); + } + + return language_list; +} + +string16 LanguageOptionsHandler::GetProductName() { + return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); +} + +void LanguageOptionsHandler::SetApplicationLocale( + const std::string& language_code) { + PrefService* pref_service = g_browser_process->local_state(); + pref_service->SetString(prefs::kApplicationLocale, language_code); +} + +void LanguageOptionsHandler::RestartCallback(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("LanguageOptions_Restart")); + BrowserList::AttemptRestart(); +} diff --git a/chrome/browser/ui/webui/options2/language_options_handler.h b/chrome/browser/ui/webui/options2/language_options_handler.h new file mode 100644 index 0000000..1131b32 --- /dev/null +++ b/chrome/browser/ui/webui/options2/language_options_handler.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_LANGUAGE_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_LANGUAGE_OPTIONS_HANDLER_H_ +#pragma once + +#include "chrome/browser/ui/webui/options2/language_options_handler_common.h" + +// Language options UI page handler for non-Chrome OS platforms. For Chrome OS, +// see chromeos::CrosLanguageOptionsHandler. +class LanguageOptionsHandler : public LanguageOptionsHandlerCommon { + public: + LanguageOptionsHandler(); + virtual ~LanguageOptionsHandler(); + + // OptionsPageUIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // The following static method is public for ease of testing. + + // Gets the list of languages from the given input descriptors. + // The return value will look like: + // [{'code': 'fi', 'displayName': 'Finnish', 'nativeDisplayName': 'suomi'}, + // ...] + static base::ListValue* GetLanguageList(); + + private: + // LanguageOptionsHandlerCommon implementation. + virtual string16 GetProductName() OVERRIDE; + virtual void SetApplicationLocale(const std::string& language_code) OVERRIDE; + + // Called when the restart button is clicked. + void RestartCallback(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(LanguageOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_LANGUAGE_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/language_options_handler_common.cc b/chrome/browser/ui/webui/options2/language_options_handler_common.cc new file mode 100644 index 0000000..138db7c --- /dev/null +++ b/chrome/browser/ui/webui/options2/language_options_handler_common.cc @@ -0,0 +1,163 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/language_options_handler_common.h" + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/spellcheck_common.h" +#include "content/browser/user_metrics.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +LanguageOptionsHandlerCommon::LanguageOptionsHandlerCommon() { +} + +LanguageOptionsHandlerCommon::~LanguageOptionsHandlerCommon() { +} + +void LanguageOptionsHandlerCommon::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + string16 product_name = GetProductName(); + localized_strings->SetString("add_button", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_BUTTON)); + localized_strings->SetString("languages", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_LANGUAGES)); + localized_strings->SetString("please_add_another_language", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_LANGUAGE)); + localized_strings->SetString("remove_button", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_REMOVE_BUTTON)); + localized_strings->SetString("add_language_instructions", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_LANGUAGE_INSTRUCTIONS)); + localized_strings->SetString("cannot_be_displayed_in_this_language", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_CANNOT_BE_DISPLAYED_IN_THIS_LANGUAGE, + product_name)); + localized_strings->SetString("is_displayed_in_this_language", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE, + product_name)); + localized_strings->SetString("display_in_this_language", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE, + product_name)); + localized_strings->SetString("this_language_is_currently_in_use", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_THIS_LANGUAGE_IS_CURRENTLY_IN_USE, + product_name)); + localized_strings->SetString("use_this_for_spell_checking", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_USE_THIS_FOR_SPELL_CHECKING)); + localized_strings->SetString("cannot_be_used_for_spell_checking", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_CANNOT_BE_USED_FOR_SPELL_CHECKING)); + localized_strings->SetString("is_used_for_spell_checking", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_IS_USED_FOR_SPELL_CHECKING)); + localized_strings->SetString("restart_required", + l10n_util::GetStringUTF16(IDS_OPTIONS_RELAUNCH_REQUIRED)); + localized_strings->SetString("enable_spell_check", + l10n_util::GetStringUTF16(IDS_OPTIONS_ENABLE_SPELLCHECK)); + localized_strings->SetString("enable_auto_spell_correction", + l10n_util::GetStringUTF16(IDS_OPTIONS_ENABLE_AUTO_SPELL_CORRECTION)); + localized_strings->SetString("add_language_title", + l10n_util::GetStringUTF16(IDS_OPTIONS_LANGUAGES_ADD_TITLE)); + localized_strings->SetString("add_language_select_label", + l10n_util::GetStringUTF16(IDS_OPTIONS_LANGUAGES_ADD_SELECT_LABEL)); + localized_strings->SetString("restart_button", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_LANGUAGES_RELAUNCH_BUTTON)); + + // The following are resources, rather than local strings. + localized_strings->SetString("currentUiLanguageCode", + g_browser_process->GetApplicationLocale()); + localized_strings->Set("spellCheckLanguageCodeSet", + GetSpellCheckLanguageCodeSet()); + localized_strings->Set("uiLanguageCodeSet", GetUILanguageCodeSet()); + + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + bool experimental_spell_check_features = + command_line.HasSwitch(switches::kExperimentalSpellcheckerFeatures); + localized_strings->SetBoolean("experimentalSpellCheckFeatures", + experimental_spell_check_features); +} + +void LanguageOptionsHandlerCommon::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("languageOptionsOpen", + base::Bind( + &LanguageOptionsHandlerCommon::LanguageOptionsOpenCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("spellCheckLanguageChange", + base::Bind( + &LanguageOptionsHandlerCommon::SpellCheckLanguageChangeCallback, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("uiLanguageChange", + base::Bind( + &LanguageOptionsHandlerCommon::UiLanguageChangeCallback, + base::Unretained(this))); +} + +DictionaryValue* LanguageOptionsHandlerCommon::GetUILanguageCodeSet() { + DictionaryValue* dictionary = new DictionaryValue(); + const std::vector<std::string>& available_locales = + l10n_util::GetAvailableLocales(); + for (size_t i = 0; i < available_locales.size(); ++i) { + dictionary->SetBoolean(available_locales[i], true); + } + return dictionary; +} + +DictionaryValue* LanguageOptionsHandlerCommon::GetSpellCheckLanguageCodeSet() { + DictionaryValue* dictionary = new DictionaryValue(); + std::vector<std::string> spell_check_languages; + SpellCheckCommon::SpellCheckLanguages(&spell_check_languages); + for (size_t i = 0; i < spell_check_languages.size(); ++i) { + dictionary->SetBoolean(spell_check_languages[i], true); + } + return dictionary; +} + +void LanguageOptionsHandlerCommon::LanguageOptionsOpenCallback( + const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("LanguageOptions_Open")); +} + +void LanguageOptionsHandlerCommon::UiLanguageChangeCallback( + const ListValue* args) { + const std::string language_code = UTF16ToASCII(ExtractStringValue(args)); + CHECK(!language_code.empty()); + const std::string action = base::StringPrintf( + "LanguageOptions_UiLanguageChange_%s", language_code.c_str()); + UserMetrics::RecordComputedAction(action); + SetApplicationLocale(language_code); + web_ui_->CallJavascriptFunction("options.LanguageOptions.uiLanguageSaved"); +} + +void LanguageOptionsHandlerCommon::SpellCheckLanguageChangeCallback( + const ListValue* args) { + const std::string language_code = UTF16ToASCII(ExtractStringValue(args)); + CHECK(!language_code.empty()); + const std::string action = base::StringPrintf( + "LanguageOptions_SpellCheckLanguageChange_%s", language_code.c_str()); + UserMetrics::RecordComputedAction(action); +} diff --git a/chrome/browser/ui/webui/options2/language_options_handler_common.h b/chrome/browser/ui/webui/options2/language_options_handler_common.h new file mode 100644 index 0000000..88ba713 --- /dev/null +++ b/chrome/browser/ui/webui/options2/language_options_handler_common.h @@ -0,0 +1,69 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_LANGUAGE_OPTIONS_HANDLER_COMMON_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_LANGUAGE_OPTIONS_HANDLER_COMMON_H_ +#pragma once + +#include "chrome/browser/ui/webui/options2/options_ui.h" + +namespace base { +class DictionaryValue; +class ListValue; +} + +// The base class for language options page UI handlers. This class has code +// common to the Chrome OS and non-Chrome OS implementation of the handler. +class LanguageOptionsHandlerCommon : public OptionsPage2UIHandler { + public: + LanguageOptionsHandlerCommon(); + virtual ~LanguageOptionsHandlerCommon(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // DOMMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // The following static methods are public for ease of testing. + + // Gets the set of language codes that can be used as UI language. + // The return value will look like: + // {'en-US': true, 'fi': true, 'fr': true, ...} + // + // Note that true in values does not mean anything. We just use the + // dictionary as a set. + static base::DictionaryValue* GetUILanguageCodeSet(); + + // Gets the set of language codes that can be used for spellchecking. + // The return value will look like: + // {'en-US': true, 'fi': true, 'fr': true, ...} + // + // Note that true in values does not mean anything. We just use the + // dictionary as a set. + static base::DictionaryValue* GetSpellCheckLanguageCodeSet(); + + private: + // Returns the name of the product (ex. "Chrome" or "Chrome OS"). + virtual string16 GetProductName() = 0; + + // Sets the application locale. + virtual void SetApplicationLocale(const std::string& language_code) = 0; + + // Called when the language options is opened. + void LanguageOptionsOpenCallback(const base::ListValue* args); + + // Called when the UI language is changed. + // |args| will contain the language code as string (ex. "fr"). + void UiLanguageChangeCallback(const base::ListValue* args); + + // Called when the spell check language is changed. + // |args| will contain the language code as string (ex. "fr"). + void SpellCheckLanguageChangeCallback(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(LanguageOptionsHandlerCommon); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_LANGUAGE_OPTIONS_HANDLER_COMMON_H_ diff --git a/chrome/browser/ui/webui/options2/language_options_handler_unittest.cc b/chrome/browser/ui/webui/options2/language_options_handler_unittest.cc new file mode 100644 index 0000000..c889818 --- /dev/null +++ b/chrome/browser/ui/webui/options2/language_options_handler_unittest.cc @@ -0,0 +1,198 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/language_options_handler.h" + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/input_method/ibus_controller.h" +#include "chrome/browser/chromeos/input_method/input_method_manager.h" +#include "chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h" +#endif // defined(OS_CHROMEOS) + +#if defined(OS_CHROMEOS) + +using chromeos::input_method::IBusController; +using chromeos::input_method::InputMethodDescriptor; +using chromeos::input_method::InputMethodDescriptors; + +static InputMethodDescriptor GetDesc(IBusController* controller, + const std::string& id, + const std::string& raw_layout, + const std::string& language_code) { + return controller->CreateInputMethodDescriptor(id, "", raw_layout, + language_code); +} + +static InputMethodDescriptors CreateInputMethodDescriptors() { + scoped_ptr<IBusController> controller(IBusController::Create()); + + InputMethodDescriptors descriptors; + descriptors.push_back(GetDesc(controller.get(), "xkb:us::eng", "us", "eng")); + descriptors.push_back(GetDesc(controller.get(), "xkb:fr::fra", "fr", "fra")); + descriptors.push_back(GetDesc(controller.get(), "xkb:be::fra", "be", "fr")); + descriptors.push_back(GetDesc(controller.get(), "mozc", "us", "ja")); + return descriptors; +} + +TEST(LanguageOptionsHandlerTest, GetInputMethodList) { + InputMethodDescriptors descriptors = CreateInputMethodDescriptors(); + scoped_ptr<ListValue> list( + chromeos::CrosLanguageOptionsHandler::GetInputMethodList(descriptors)); + ASSERT_EQ(4U, list->GetSize()); + + DictionaryValue* entry = NULL; + DictionaryValue *language_code_set = NULL; + std::string input_method_id; + std::string display_name; + std::string language_code; + + // As shown below, the list should be input method ids should appear in + // the same order of the descriptors. + ASSERT_TRUE(list->GetDictionary(0, &entry)); + ASSERT_TRUE(entry->GetString("id", &input_method_id)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set)); + EXPECT_EQ("xkb:us::eng", input_method_id); + // Commented out as it depends on translation in generated_resources.grd + // (i.e. makes the test fragile). + // EXPECT_EQ("English (USA) keyboard layout", display_name); + ASSERT_TRUE(language_code_set->HasKey("en-US")); + ASSERT_TRUE(language_code_set->HasKey("id")); // From kExtraLanguages. + ASSERT_TRUE(language_code_set->HasKey("fil")); // From kExtraLanguages. + + ASSERT_TRUE(list->GetDictionary(1, &entry)); + ASSERT_TRUE(entry->GetString("id", &input_method_id)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set)); + EXPECT_EQ("xkb:fr::fra", input_method_id); + // Commented out. See above. + // EXPECT_EQ("French keyboard layout", display_name); + ASSERT_TRUE(language_code_set->HasKey("fr")); + + ASSERT_TRUE(list->GetDictionary(2, &entry)); + ASSERT_TRUE(entry->GetString("id", &input_method_id)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set)); + EXPECT_EQ("xkb:be::fra", input_method_id); + // Commented out. See above. + // EXPECT_EQ("Belgian keyboard layout", display_name); + ASSERT_TRUE(language_code_set->HasKey("fr")); + + ASSERT_TRUE(list->GetDictionary(3, &entry)); + ASSERT_TRUE(entry->GetString("id", &input_method_id)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set)); + EXPECT_EQ("mozc", input_method_id); + // Commented out. See above. + // EXPECT_EQ("Japanese input method (for US keyboard)", display_name); + ASSERT_TRUE(language_code_set->HasKey("ja")); +} + +TEST(LanguageOptionsHandlerTest, GetLanguageList) { + InputMethodDescriptors descriptors = CreateInputMethodDescriptors(); + scoped_ptr<ListValue> list( + chromeos::CrosLanguageOptionsHandler::GetLanguageList(descriptors)); + ASSERT_EQ(8U, list->GetSize()); + + DictionaryValue* entry = NULL; + std::string language_code; + std::string display_name; + std::string native_display_name; + + // As shown below, the list should be sorted by the display names, + // and these names should not have duplicates. + + // This comes from kExtraLanguages. + ASSERT_TRUE(list->GetDictionary(0, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("nl", language_code); + EXPECT_EQ("Dutch", display_name); + EXPECT_EQ("Nederlands", native_display_name); + + // This comes from kExtraLanguages. + ASSERT_TRUE(list->GetDictionary(1, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("en-AU", language_code); + EXPECT_EQ("English (Australia)", display_name); + EXPECT_EQ("English (Australia)", native_display_name); + + ASSERT_TRUE(list->GetDictionary(2, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("en-US", language_code); + EXPECT_EQ("English (United States)", display_name); + EXPECT_EQ("English (United States)", native_display_name); + + // This comes from kExtraLanguages. + ASSERT_TRUE(list->GetDictionary(3, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("fil", language_code); + EXPECT_EQ("Filipino", display_name); + EXPECT_EQ("Filipino", native_display_name); + + ASSERT_TRUE(list->GetDictionary(4, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("fr", language_code); + EXPECT_EQ("French", display_name); + EXPECT_EQ("fran\u00E7ais", native_display_name); + + // This comes from kExtraLanguages. + ASSERT_TRUE(list->GetDictionary(5, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("id", language_code); + EXPECT_EQ("Indonesian", display_name); + EXPECT_EQ("Bahasa Indonesia", native_display_name); + + ASSERT_TRUE(list->GetDictionary(6, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("ja", language_code); + EXPECT_EQ("Japanese", display_name); + EXPECT_EQ("\u65E5\u672C\u8A9E", native_display_name); + + // This comes from kExtraLanguages. + ASSERT_TRUE(list->GetDictionary(7, &entry)); + ASSERT_TRUE(entry->GetString("code", &language_code)); + ASSERT_TRUE(entry->GetString("displayName", &display_name)); + ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name)); + EXPECT_EQ("es-419", language_code); + EXPECT_EQ("Spanish (Latin America)", display_name); + EXPECT_EQ("espa\u00F1ol (Latinoam\u00E9rica)", native_display_name); +} +#endif // defined(OS_CHROMEOS) + +#if !defined(OS_MACOSX) +TEST(LanguageOptionsHandlerTest, GetUILanguageCodeSet) { + scoped_ptr<DictionaryValue> dictionary( + LanguageOptionsHandler::GetUILanguageCodeSet()); + EXPECT_TRUE(dictionary->HasKey("en-US")); + // Note that we don't test a false case, as such an expectation will + // fail when we add support for the language. + // EXPECT_FALSE(dictionary->HasKey("no")); +} +#endif // !defined(OS_MACOSX) + +TEST(LanguageOptionsHandlerTest, GetSpellCheckLanguageCodeSet) { + scoped_ptr<DictionaryValue> dictionary( + LanguageOptionsHandler::GetSpellCheckLanguageCodeSet()); + EXPECT_TRUE(dictionary->HasKey("en-US")); +} diff --git a/chrome/browser/ui/webui/options2/manage_profile_handler.cc b/chrome/browser/ui/webui/options2/manage_profile_handler.cc new file mode 100644 index 0000000..4c29788 --- /dev/null +++ b/chrome/browser/ui/webui/options2/manage_profile_handler.cc @@ -0,0 +1,300 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/manage_profile_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/value_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/gaia_info_update_service.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_info_util.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/ui/webui/web_ui_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/public/browser/notification_service.h" +#include "grit/generated_resources.h" + +ManageProfileHandler::ManageProfileHandler() { +} + +ManageProfileHandler::~ManageProfileHandler() { +} + +void ManageProfileHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "manageProfilesTitle", IDS_PROFILES_MANAGE_TITLE }, + { "manageProfilesNameLabel", IDS_PROFILES_MANAGE_NAME_LABEL }, + { "manageProfilesDuplicateNameError", + IDS_PROFILES_MANAGE_DUPLICATE_NAME_ERROR }, + { "manageProfilesIconLabel", IDS_PROFILES_MANAGE_ICON_LABEL }, + { "deleteProfileTitle", IDS_PROFILES_DELETE_TITLE }, + { "deleteProfileOK", IDS_PROFILES_DELETE_OK_BUTTON_LABEL }, + { "deleteProfileMessage", IDS_PROFILES_DELETE_MESSAGE }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); +} + +void ManageProfileHandler::Initialize() { + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllSources()); + SendProfileNames(); +} + +void ManageProfileHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("setProfileNameAndIcon", + base::Bind(&ManageProfileHandler::SetProfileNameAndIcon, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("deleteProfile", + base::Bind(&ManageProfileHandler::DeleteProfile, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("requestDefaultProfileIcons", + base::Bind(&ManageProfileHandler::RequestDefaultProfileIcons, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("requestProfileInfo", + base::Bind(&ManageProfileHandler::RequestProfileInfo, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("profileIconSelectionChanged", + base::Bind(&ManageProfileHandler::ProfileIconSelectionChanged, + base::Unretained(this))); +} + +void ManageProfileHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) { + SendProfileNames(); + SendProfileIcons(); + } else { + OptionsPage2UIHandler::Observe(type, source, details); + } +} + +void ManageProfileHandler::RequestDefaultProfileIcons(const ListValue* args) { + SendProfileIcons(); +} + +void ManageProfileHandler::SendProfileIcons() { + ListValue image_url_list; + + // First add the GAIA picture if it's available. + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + Profile* profile = Profile::FromWebUI(web_ui_); + size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath()); + if (profile_index != std::string::npos) { + const gfx::Image* icon = + cache.GetGAIAPictureOfProfileAtIndex(profile_index); + if (icon) { + gfx::Image icon2 = profiles::GetAvatarIconForWebUI(*icon, true); + gaia_picture_url_ = web_ui_util::GetImageDataUrl(icon2); + image_url_list.Append(Value::CreateStringValue(gaia_picture_url_)); + } + } + + // Next add the default avatar icons. + for (size_t i = 0; i < ProfileInfoCache::GetDefaultAvatarIconCount(); i++) { + std::string url = ProfileInfoCache::GetDefaultAvatarIconUrl(i); + image_url_list.Append(Value::CreateStringValue(url)); + } + + web_ui_->CallJavascriptFunction( + "ManageProfileOverlay.receiveDefaultProfileIcons", + image_url_list); +} + +void ManageProfileHandler::SendProfileNames() { + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + DictionaryValue profile_name_dict; + for (size_t i = 0, e = cache.GetNumberOfProfiles(); i < e; ++i) + profile_name_dict.SetBoolean(UTF16ToUTF8(cache.GetNameOfProfileAtIndex(i)), + true); + + web_ui_->CallJavascriptFunction("ManageProfileOverlay.receiveProfileNames", + profile_name_dict); +} + +void ManageProfileHandler::SetProfileNameAndIcon(const ListValue* args) { + DCHECK(args); + + Value* file_path_value; + FilePath profile_file_path; + if (!args->Get(0, &file_path_value) || + !base::GetValueAsFilePath(*file_path_value, &profile_file_path)) + return; + + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); + if (profile_index == std::string::npos) + return; + + string16 new_profile_name; + if (!args->GetString(1, &new_profile_name)) + return; + + if (new_profile_name == cache.GetGAIANameOfProfileAtIndex(profile_index)) { + // Set the profile to use the GAIA name as the profile name. Note, this + // is a little weird if the user typed their GAIA name manually but + // it's not a big deal. + cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, true); + // Using the GAIA name as the profile name can invalidate the profile index. + profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); + if (profile_index == std::string::npos) + return; + } else { + cache.SetNameOfProfileAtIndex(profile_index, new_profile_name); + // Changing the profile name can invalidate the profile index. + profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); + if (profile_index == std::string::npos) + return; + + cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, false); + // Unsetting the GAIA name as the profile name can invalidate the profile + // index. + profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); + if (profile_index == std::string::npos) + return; + } + + std::string icon_url; + if (!args->GetString(2, &icon_url)) + return; + + // Metrics logging variable. + bool previously_using_gaia_icon = + cache.IsUsingGAIANameOfProfileAtIndex(profile_index); + + size_t new_icon_index; + if (icon_url == gaia_picture_url_) { + cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, true); + if (!previously_using_gaia_icon) { + // Only log if they changed to the GAIA photo. + // Selection of GAIA photo as avatar is logged as part of the function + // below. + ProfileMetrics::LogProfileSwitchGaia(ProfileMetrics::GAIA_OPT_IN); + } + } else if (cache.IsDefaultAvatarIconUrl(icon_url, &new_icon_index)) { + ProfileMetrics::LogProfileAvatarSelection(new_icon_index); + cache.SetAvatarIconOfProfileAtIndex(profile_index, new_icon_index); + cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, false); + } + + ProfileMetrics::LogProfileUpdate(profile_file_path); +} + +void ManageProfileHandler::DeleteProfile(const ListValue* args) { + DCHECK(args); + + ProfileMetrics::LogProfileDeleteUser(ProfileMetrics::PROFILE_DELETED); + + Value* file_path_value; + FilePath profile_file_path; + if (!args->Get(0, &file_path_value) || + !base::GetValueAsFilePath(*file_path_value, &profile_file_path)) + return; + + g_browser_process->profile_manager()->ScheduleProfileForDeletion( + profile_file_path); +} + +void ManageProfileHandler::RequestProfileInfo(const ListValue* args) { + DCHECK(args); + + Value* index_value; + double index_double; + if (!args->Get(0, &index_value) || !index_value->GetAsDouble(&index_double)) + return; + + int index = static_cast<int>(index_double); + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + int profile_count = cache.GetNumberOfProfiles(); + if (index < 0 && index >= profile_count) + return; + + FilePath profile_path = cache.GetPathOfProfileAtIndex(index); + FilePath current_profile_path = Profile::FromWebUI(web_ui_)->GetPath(); + bool is_current_profile = + profile_path == Profile::FromWebUI(web_ui_)->GetPath(); + + DictionaryValue profile_value; + profile_value.SetString("name", cache.GetNameOfProfileAtIndex(index)); + profile_value.Set("filePath", base::CreateFilePathValue(profile_path)); + profile_value.SetBoolean("isCurrentProfile", is_current_profile); + + bool is_gaia_picture = + cache.IsUsingGAIAPictureOfProfileAtIndex(index) && + cache.GetGAIAPictureOfProfileAtIndex(index); + if (is_gaia_picture) { + gfx::Image icon = profiles::GetAvatarIconForWebUI( + cache.GetAvatarIconOfProfileAtIndex(index), true); + profile_value.SetString("iconURL", web_ui_util::GetImageDataUrl(icon)); + } else { + size_t icon_index = cache.GetAvatarIconIndexOfProfileAtIndex(index); + profile_value.SetString("iconURL", + cache.GetDefaultAvatarIconUrl(icon_index)); + } + + web_ui_->CallJavascriptFunction("ManageProfileOverlay.setProfileInfo", + profile_value); + + // Ensure that we have the most up to date GAIA picture. + if (is_current_profile) { + GAIAInfoUpdateService* service = + Profile::FromWebUI(web_ui_)->GetGAIAInfoUpdateService(); + if (service) + service->Update(); + } +} + +void ManageProfileHandler::ProfileIconSelectionChanged( + const base::ListValue* args) { + DCHECK(args); + + Value* file_path_value; + FilePath file_path; + if (!args->Get(0, &file_path_value) || + !base::GetValueAsFilePath(*file_path_value, &file_path)) { + return; + } + + // Currently this only supports editing the current profile's info. + if (file_path != Profile::FromWebUI(web_ui_)->GetPath()) + return; + + std::string icon_url; + if (!args->GetString(1, &icon_url)) + return; + + if (icon_url != gaia_picture_url_) + return; + + // If the selection is the GAIA picture then also show the GAIA name in the + // text field. + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + size_t i = cache.GetIndexOfProfileWithPath(file_path); + if (i == std::string::npos) + return; + string16 gaia_name = cache.GetGAIANameOfProfileAtIndex(i); + if (gaia_name.empty()) + return; + + StringValue gaia_name_value(gaia_name); + web_ui_->CallJavascriptFunction("ManageProfileOverlay.setProfileName", + gaia_name_value); +} diff --git a/chrome/browser/ui/webui/options2/manage_profile_handler.h b/chrome/browser/ui/webui/options2/manage_profile_handler.h new file mode 100644 index 0000000..5daa742 --- /dev/null +++ b/chrome/browser/ui/webui/options2/manage_profile_handler.h @@ -0,0 +1,82 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_MANAGE_PROFILE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_MANAGE_PROFILE_HANDLER_H_ +#pragma once + +#include "chrome/browser/ui/webui/options2/options_ui.h" + +// Chrome personal stuff profiles manage overlay UI handler. +class ManageProfileHandler : public OptionsPage2UIHandler { + public: + ManageProfileHandler(); + virtual ~ManageProfileHandler(); + + // OptionsPage2UIHandler: + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler: + virtual void RegisterMessages() OVERRIDE; + + // content::NotificationObserver: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + // Callback for the "requestDefaultProfileIcons" message. + // Sends the array of default profile icon URLs to WebUI. + // |args| is of the form: [ {string} iconURL ] + void RequestDefaultProfileIcons(const base::ListValue* args); + + // Sends an object to WebUI of the form: + // profileNames = { + // "Profile Name 1": true, + // "Profile Name 2": true, + // ... + // }; + // This is used to detect duplicate profile names. + void SendProfileNames(); + + // Callback for the "setProfileNameAndIcon" message. Sets the name and icon + // of a given profile. + // |args| is of the form: [ + // /*string*/ profileFilePath, + // /*string*/ newProfileName, + // /*string*/ newProfileIconURL + // ] + void SetProfileNameAndIcon(const base::ListValue* args); + + // Callback for the "deleteProfile" message. Deletes the given profile. + // |args| is of the form: [ {string} profileFilePath ] + void DeleteProfile(const base::ListValue* args); + + // Callback for the "requestProfileInfo" message. + // Given |args| of the form: [ {number} profileIndex ] + // Sends an object to WebUI of the form: + // profileInfo = { + // name: "Profile Name", + // iconURL: "chrome://path/to/icon/image", + // filePath: "/path/to/profile/data/on/disk" + // isCurrentProfile: false, + // }; + void RequestProfileInfo(const base::ListValue* args); + + // Callback for the 'profileIconSelectionChanged' message. Used to update the + // name in the manager profile dialog based on the selected icon. + void ProfileIconSelectionChanged(const base::ListValue* args); + + // Send all profile icons to the overlay. + void SendProfileIcons(); + + // URL for the current profile's GAIA picture. + std::string gaia_picture_url_; + + DISALLOW_COPY_AND_ASSIGN(ManageProfileHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_MANAGE_PROFILE_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/options_browsertest.js b/chrome/browser/ui/webui/options2/options_browsertest.js new file mode 100644 index 0000000..9be9041 --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_browsertest.js @@ -0,0 +1,93 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for OptionsPage WebUI testing. + * @extends {testing.Test} + * @constructor + */ +function OptionsWebUITest() {} + +OptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the options page & call our preLoad(). + */ + browsePreload: 'chrome://settings', + + /** + * Register a mock handler to ensure expectations are met and options pages + * behave correctly. + */ + preLoad: function() { + this.makeAndRegisterMockHandler( + ['coreOptionsInitialize', + 'fetchPrefs', + 'observePrefs', + 'setBooleanPref', + 'setIntegerPref', + 'setDoublePref', + 'setStringPref', + 'setObjectPref', + 'clearPref', + 'coreOptionsUserMetricsAction', + // TODO(scr): Handle this new message: + // getInstantFieldTrialStatus: function() {}, + ]); + + // Register stubs for methods expected to be called before our tests run. + // Specific expectations can be made in the tests themselves. + this.mockHandler.stubs().fetchPrefs(ANYTHING); + this.mockHandler.stubs().observePrefs(ANYTHING); + this.mockHandler.stubs().coreOptionsInitialize(); + }, +}; + +// Crashes on Mac only. See http://crbug.com/79181 +GEN('#if defined(OS_MACOSX)'); +GEN('#define MAYBE_testSetBooleanPrefTriggers ' + + 'DISABLED_testSetBooleanPrefTriggers'); +GEN('#else'); +GEN('#define MAYBE_testSetBooleanPrefTriggers testSetBooleanPrefTriggers'); +GEN('#endif // defined(OS_MACOSX)'); + +TEST_F('OptionsWebUITest', 'MAYBE_testSetBooleanPrefTriggers', function() { + // TODO(dtseng): make generic to click all buttons. + var showHomeButton = $('toolbarShowHomeButton'); + var trueListValue = [ + 'browser.show_home_button', + true, + 'Options_Homepage_HomeButton', + ]; + // Note: this expectation is checked in testing::Test::tearDown. + this.mockHandler.expects(once()).setBooleanPref(trueListValue); + + // Cause the handler to be called. + showHomeButton.click(); + showHomeButton.blur(); +}); + +// Not meant to run on ChromeOS at this time. +// Not finishing in windows. http://crbug.com/81723 +GEN('#if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN)'); +GEN('#define MAYBE_testRefreshStaysOnCurrentPage \\'); +GEN(' DISABLED_testRefreshStaysOnCurrentPage'); +GEN('#else'); +GEN('#define MAYBE_testRefreshStaysOnCurrentPage ' + + 'testRefreshStaysOnCurrentPage'); +GEN('#endif'); + +TEST_F('OptionsWebUITest', 'MAYBE_testRefreshStaysOnCurrentPage', function() { + var item = $('advancedPageNav'); + item.onclick(); + window.location.reload(); + var pageInstance = AdvancedOptions.getInstance(); + var topPage = OptionsPage.getTopmostVisiblePage(); + var expectedTitle = pageInstance.title; + var actualTitle = document.title; + assertEquals("chrome://settings/advanced", document.location.href); + assertEquals(expectedTitle, actualTitle); + assertEquals(pageInstance, topPage); +}); diff --git a/chrome/browser/ui/webui/options2/options_sync_setup_handler.cc b/chrome/browser/ui/webui/options2/options_sync_setup_handler.cc new file mode 100644 index 0000000..872c28b --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_sync_setup_handler.cc @@ -0,0 +1,37 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/options_sync_setup_handler.h" + +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service.h" + +OptionsSyncSetupHandler::OptionsSyncSetupHandler( + ProfileManager* profile_manager) : SyncSetupHandler2(profile_manager) { +} + +OptionsSyncSetupHandler::~OptionsSyncSetupHandler() { +} + +void OptionsSyncSetupHandler::ShowSetupUI() { + ProfileSyncService* service = + Profile::FromWebUI(web_ui_)->GetProfileSyncService(); + DCHECK(service); + + // The user is trying to manually load a syncSetup URL. We should bring up + // either a login or a configure flow based on the state of sync. + if (service->HasSyncSetupCompleted()) { + if (service->IsPassphraseRequiredForDecryption()) { + service->get_wizard().Step(SyncSetupWizard::ENTER_PASSPHRASE); + } else { + service->get_wizard().Step(SyncSetupWizard::CONFIGURE); + } + } else { + service->get_wizard().Step(SyncSetupWizard::GetLoginState()); + } + + // Show the Sync Setup page. + scoped_ptr<Value> page(Value::CreateStringValue("syncSetup")); + web_ui_->CallJavascriptFunction("OptionsPage.navigateToPage", *page); +} diff --git a/chrome/browser/ui/webui/options2/options_sync_setup_handler.h b/chrome/browser/ui/webui/options2/options_sync_setup_handler.h new file mode 100644 index 0000000..291fdbe --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_sync_setup_handler.h @@ -0,0 +1,21 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_SYNC_SETUP_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_SYNC_SETUP_HANDLER_H_ + +#include "chrome/browser/ui/webui/sync_setup_handler2.h" + +// The handler for Javascript messages related to sync setup UI in the options +// page. +class OptionsSyncSetupHandler : public SyncSetupHandler2 { + public: + explicit OptionsSyncSetupHandler(ProfileManager* profile_manager); + virtual ~OptionsSyncSetupHandler(); + + protected: + virtual void ShowSetupUI() OVERRIDE; +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_SYNC_SETUP_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/options_ui.cc b/chrome/browser/ui/webui/options2/options_ui.cc new file mode 100644 index 0000000..9b74dd6 --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_ui.cc @@ -0,0 +1,369 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/options_ui.h" + +#include <algorithm> +#include <vector> + +#include "base/callback.h" +#include "base/command_line.h" +#include "base/memory/singleton.h" +#include "base/message_loop.h" +#include "base/string_piece.h" +#include "base/string_util.h" +#include "base/threading/thread.h" +#include "base/time.h" +#include "base/values.h" +#include "chrome/browser/browser_about_handler.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/options2/advanced_options_handler.h" +#include "chrome/browser/ui/webui/options2/autofill_options_handler.h" +#include "chrome/browser/ui/webui/options2/browser_options_handler.h" +#include "chrome/browser/ui/webui/options2/clear_browser_data_handler.h" +#include "chrome/browser/ui/webui/options2/content_settings_handler.h" +#include "chrome/browser/ui/webui/options2/cookies_view_handler.h" +#include "chrome/browser/ui/webui/options2/core_options_handler.h" +#include "chrome/browser/ui/webui/options2/extension_settings_handler.h" +#include "chrome/browser/ui/webui/options2/font_settings_handler.h" +#include "chrome/browser/ui/webui/options2/handler_options_handler.h" +#include "chrome/browser/ui/webui/options2/import_data_handler.h" +#include "chrome/browser/ui/webui/options2/language_options_handler.h" +#include "chrome/browser/ui/webui/options2/manage_profile_handler.h" +#include "chrome/browser/ui/webui/options2/options_sync_setup_handler.h" +#include "chrome/browser/ui/webui/options2/pack_extension_handler.h" +#include "chrome/browser/ui/webui/options2/password_manager_handler.h" +#include "chrome/browser/ui/webui/options2/personal_options_handler.h" +#include "chrome/browser/ui/webui/options2/search_engine_manager_handler.h" +#include "chrome/browser/ui/webui/options2/stop_syncing_handler.h" +#include "chrome/browser/ui/webui/options2/web_intents_settings_handler.h" +#include "chrome/browser/ui/webui/theme_source.h" +#include "chrome/common/jstemplate_builder.h" +#include "chrome/common/time_format.h" +#include "chrome/common/url_constants.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_delegate.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_types.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/options2_resources.h" +#include "grit/theme_resources.h" +#include "grit/theme_resources_standard.h" +#include "net/base/escape.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/ui/webui/options2/chromeos/about_page_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/accounts_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/bluetooth_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/change_picture_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/core_chromeos_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/internet_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_chewing_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_customize_modifier_keys_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_hangul_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_mozc_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/language_pinyin_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/proxy_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/stats_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/system_options_handler.h" +#include "chrome/browser/ui/webui/options2/chromeos/user_image_source.h" +#include "chrome/browser/ui/webui/options2/chromeos/virtual_keyboard_manager_handler.h" +#endif + +#if defined(USE_NSS) +#include "chrome/browser/ui/webui/options2/certificate_manager_handler.h" +#endif + +static const char kLocalizedStringsFile[] = "strings.js"; +static const char kOptionsBundleJsFile[] = "options_bundle.js"; + +//////////////////////////////////////////////////////////////////////////////// +// +// Options2UIHTMLSource +// +//////////////////////////////////////////////////////////////////////////////// + +class Options2UIHTMLSource : public ChromeURLDataManager::DataSource { + public: + // The constructor takes over ownership of |localized_strings|. + explicit Options2UIHTMLSource(DictionaryValue* localized_strings); + virtual ~Options2UIHTMLSource(); + + // Called when the network layer has requested a resource underneath + // the path we registered. + virtual void StartDataRequest(const std::string& path, + bool is_incognito, + int request_id); + virtual std::string GetMimeType(const std::string&) const; + + private: + // Localized strings collection. + scoped_ptr<DictionaryValue> localized_strings_; + + DISALLOW_COPY_AND_ASSIGN(Options2UIHTMLSource); +}; + +Options2UIHTMLSource::Options2UIHTMLSource(DictionaryValue* localized_strings) + : DataSource(chrome::kChromeUISettingsFrameHost, MessageLoop::current()) { + DCHECK(localized_strings); + localized_strings_.reset(localized_strings); +} + +Options2UIHTMLSource::~Options2UIHTMLSource() {} + +void Options2UIHTMLSource::StartDataRequest(const std::string& path, + bool is_incognito, + int request_id) { + scoped_refptr<RefCountedMemory> response_bytes; + SetFontAndTextDirection(localized_strings_.get()); + + if (path == kLocalizedStringsFile) { + // Return dynamically-generated strings from memory. + std::string strings_js; + jstemplate_builder::AppendJsonJS(localized_strings_.get(), &strings_js); + response_bytes = base::RefCountedString::TakeString(&strings_js); + } else if (path == kOptionsBundleJsFile) { + // Return (and cache) the options javascript code. + response_bytes = ResourceBundle::GetSharedInstance().LoadDataResourceBytes( + IDR_OPTIONS2_BUNDLE_JS); + } else { + // Return (and cache) the main options html page as the default. + response_bytes = ResourceBundle::GetSharedInstance().LoadDataResourceBytes( + IDR_OPTIONS2_HTML); + } + + SendResponse(request_id, response_bytes); +} + +std::string Options2UIHTMLSource::GetMimeType(const std::string& path) const { + if (path == kLocalizedStringsFile || path == kOptionsBundleJsFile) + return "application/javascript"; + + return "text/html"; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// OptionsPage2UIHandler +// +//////////////////////////////////////////////////////////////////////////////// + +OptionsPage2UIHandler::OptionsPage2UIHandler() { +} + +OptionsPage2UIHandler::~OptionsPage2UIHandler() { +} + +bool OptionsPage2UIHandler::IsEnabled() { + return true; +} + +// static +void OptionsPage2UIHandler::RegisterStrings( + DictionaryValue* localized_strings, + const OptionsStringResource* resources, + size_t length) { + for (size_t i = 0; i < length; ++i) { + localized_strings->SetString( + resources[i].name, l10n_util::GetStringUTF16(resources[i].id)); + } +} + +void OptionsPage2UIHandler::RegisterTitle(DictionaryValue* localized_strings, + const std::string& variable_name, + int title_id) { + localized_strings->SetString(variable_name, + l10n_util::GetStringUTF16(title_id)); + localized_strings->SetString(variable_name + "TabTitle", + l10n_util::GetStringFUTF16(IDS_OPTIONS_TAB_TITLE, + l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE), + l10n_util::GetStringUTF16(title_id))); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Options2UI +// +//////////////////////////////////////////////////////////////////////////////// + +Options2UI::Options2UI(TabContents* contents) + : ChromeWebUI(contents), + initialized_handlers_(false) { + DictionaryValue* localized_strings = new DictionaryValue(); + + CoreOptionsHandler* core_handler; +#if defined(OS_CHROMEOS) + core_handler = new chromeos::CoreChromeOSOptionsHandler(); +#else + core_handler = new CoreOptionsHandler(); +#endif + core_handler->set_handlers_host(this); + AddOptionsPageUIHandler(localized_strings, core_handler); + + AddOptionsPageUIHandler(localized_strings, new AdvancedOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, new AutofillOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, new BrowserOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, new ClearBrowserDataHandler()); + AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler()); + AddOptionsPageUIHandler(localized_strings, new CookiesViewHandler()); + AddOptionsPageUIHandler(localized_strings, new ExtensionSettingsHandler()); + AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler()); + AddOptionsPageUIHandler(localized_strings, new WebIntentsSettingsHandler()); +#if defined(OS_CHROMEOS) + AddOptionsPageUIHandler(localized_strings, + new chromeos::CrosLanguageOptionsHandler()); +#else + AddOptionsPageUIHandler(localized_strings, new LanguageOptionsHandler()); +#endif + AddOptionsPageUIHandler(localized_strings, new ManageProfileHandler()); + AddOptionsPageUIHandler(localized_strings, new PackExtensionHandler()); + AddOptionsPageUIHandler(localized_strings, new PasswordManagerHandler()); + AddOptionsPageUIHandler(localized_strings, new PersonalOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, new SearchEngineManagerHandler()); + AddOptionsPageUIHandler(localized_strings, new ImportDataHandler()); + AddOptionsPageUIHandler(localized_strings, new StopSyncingHandler()); + AddOptionsPageUIHandler(localized_strings, new OptionsSyncSetupHandler( + g_browser_process->profile_manager())); +#if defined(OS_CHROMEOS) + AddOptionsPageUIHandler(localized_strings, + new chromeos::AboutPageHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::AccountsOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::BluetoothOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, new InternetOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::LanguageChewingHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::LanguageCustomizeModifierKeysHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::LanguageHangulHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::LanguageMozcHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::LanguagePinyinHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::VirtualKeyboardManagerHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::ProxyHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::ChangePictureOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, + new chromeos::StatsOptionsHandler()); + AddOptionsPageUIHandler(localized_strings, new SystemOptionsHandler()); +#endif +#if defined(USE_NSS) + AddOptionsPageUIHandler(localized_strings, new CertificateManagerHandler()); +#endif + AddOptionsPageUIHandler(localized_strings, new HandlerOptionsHandler()); + + // |localized_strings| ownership is taken over by this constructor. + Options2UIHTMLSource* html_source = + new Options2UIHTMLSource(localized_strings); + + // Set up the chrome://settings-frame/ source. + Profile* profile = Profile::FromBrowserContext(contents->browser_context()); + profile->GetChromeURLDataManager()->AddDataSource(html_source); + + // Set up the chrome://theme/ source. + ThemeSource* theme = new ThemeSource(profile); + profile->GetChromeURLDataManager()->AddDataSource(theme); + +#if defined(OS_CHROMEOS) + // Set up the chrome://userimage/ source. + chromeos::UserImageSource* user_image_source = + new chromeos::UserImageSource(); + profile->GetChromeURLDataManager()->AddDataSource(user_image_source); +#endif +} + +Options2UI::~Options2UI() { + // Uninitialize all registered handlers. The base class owns them and it will + // eventually delete them. Skip over the generic handler. + for (std::vector<WebUIMessageHandler*>::iterator iter = handlers_.begin() + 1; + iter != handlers_.end(); + ++iter) { + static_cast<OptionsPage2UIHandler*>(*iter)->Uninitialize(); + } +} + +// Override. +void Options2UI::RenderViewCreated(RenderViewHost* render_view_host) { + SetCommandLineString(render_view_host); + ChromeWebUI::RenderViewCreated(render_view_host); +} + +void Options2UI::RenderViewReused(RenderViewHost* render_view_host) { + SetCommandLineString(render_view_host); + ChromeWebUI::RenderViewReused(render_view_host); +} + +void Options2UI::DidBecomeActiveForReusedRenderView() { + // When the renderer is re-used (e.g., for back/forward navigation within + // options), the handlers are torn down and rebuilt, so are no longer + // initialized, but the web page's DOM may remain intact, in which case onload + // won't fire to initilize the handlers. To make sure initialization always + // happens, call reinitializeCore (which is a no-op unless the DOM was already + // initialized). + CallJavascriptFunction("OptionsPage.reinitializeCore"); + + ChromeWebUI::DidBecomeActiveForReusedRenderView(); +} + +// static +RefCountedMemory* Options2UI::GetFaviconResourceBytes() { + return ResourceBundle::GetSharedInstance(). + LoadDataResourceBytes(IDR_SETTINGS_FAVICON); +} + +void Options2UI::InitializeHandlers() { + DCHECK(!GetProfile()->IsOffTheRecord() || Profile::IsGuestSession()); + + // The reinitialize call from DidBecomeActiveForReusedRenderView end up being + // delivered after a new web page DOM has been brought up in an existing + // renderer (due to IPC delays), causing this method to be called twice. If + // that happens, ignore the second call. + if (initialized_handlers_) + return; + initialized_handlers_ = true; + + std::vector<WebUIMessageHandler*>::iterator iter; + // Skip over the generic handler. + for (iter = handlers_.begin() + 1; iter != handlers_.end(); ++iter) { + (static_cast<OptionsPage2UIHandler*>(*iter))->Initialize(); + } +} + +void Options2UI::AddOptionsPageUIHandler(DictionaryValue* localized_strings, + OptionsPage2UIHandler* handler_raw) { + scoped_ptr<OptionsPage2UIHandler> handler(handler_raw); + DCHECK(handler.get()); + // Add only if handler's service is enabled. + if (handler->IsEnabled()) { + handler->GetLocalizedValues(localized_strings); + // Add handler to the list and also pass the ownership. + AddMessageHandler(handler.release()->Attach(this)); + } +} + +void Options2UI::SetCommandLineString(RenderViewHost* render_view_host) { + std::string command_line_string; + +#if defined(OS_WIN) + command_line_string = + WideToASCII(CommandLine::ForCurrentProcess()->GetCommandLineString()); +#else + command_line_string = + CommandLine::ForCurrentProcess()->GetCommandLineString(); +#endif + + render_view_host->SetWebUIProperty("commandLineString", command_line_string); +} diff --git a/chrome/browser/ui/webui/options2/options_ui.h b/chrome/browser/ui/webui/options2/options_ui.h new file mode 100644 index 0000000..9a7a759 --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_ui.h @@ -0,0 +1,111 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_UI_H_ +#pragma once + +#include <string> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/webui/chrome_url_data_manager.h" +#include "chrome/browser/ui/webui/chrome_web_ui.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_types.h" + +// The base class handler of Javascript messages of options pages. +class OptionsPage2UIHandler : public WebUIMessageHandler, + public content::NotificationObserver { + public: + OptionsPage2UIHandler(); + virtual ~OptionsPage2UIHandler(); + + // Is this handler enabled? + virtual bool IsEnabled(); + + // Collects localized strings for options page. + virtual void GetLocalizedValues(base::DictionaryValue* localized_strings) = 0; + + // Initialize the page. Called once the DOM is available for manipulation. + // This will be called only once. + virtual void Initialize() {} + + // Uninitializes the page. Called just before the object is destructed. + virtual void Uninitialize() {} + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE {} + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE {} + + protected: + struct OptionsStringResource { + // The name of the resource in templateData. + const char* name; + // The .grd ID for the resource (IDS_*). + int id; + }; + // A helper for simplifying the process of registering strings in WebUI. + static void RegisterStrings(base::DictionaryValue* localized_strings, + const OptionsStringResource* resources, + size_t length); + + // Registers string resources for a page's header and tab title. + static void RegisterTitle(base::DictionaryValue* localized_strings, + const std::string& variable_name, + int title_id); + + content::NotificationRegistrar registrar_; + + private: + DISALLOW_COPY_AND_ASSIGN(OptionsPage2UIHandler); +}; + +// An interface for common operations that a host of OptionsPage2UIHandlers +// should provide. +class OptionsPage2UIHandlerHost { + public: + virtual void InitializeHandlers() = 0; + + protected: + virtual ~OptionsPage2UIHandlerHost() {} +}; + +// The WebUI for chrome:settings-frame. +class Options2UI : public ChromeWebUI, + public OptionsPage2UIHandlerHost { + public: + explicit Options2UI(TabContents* contents); + virtual ~Options2UI(); + + static RefCountedMemory* GetFaviconResourceBytes(); + + // WebUI implementation. + virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE; + virtual void RenderViewReused(RenderViewHost* render_view_host) OVERRIDE; + virtual void DidBecomeActiveForReusedRenderView() OVERRIDE; + + // Overridden from OptionsPage2UIHandlerHost: + virtual void InitializeHandlers() OVERRIDE; + + private: + // Adds OptionsPageUiHandler to the handlers list if handler is enabled. + void AddOptionsPageUIHandler(base::DictionaryValue* localized_strings, + OptionsPage2UIHandler* handler); + + // Sets the WebUI CommandLineString property with arguments passed while + // launching chrome. + void SetCommandLineString(RenderViewHost* render_view_host); + + bool initialized_handlers_; + + DISALLOW_COPY_AND_ASSIGN(Options2UI); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_UI_H_ diff --git a/chrome/browser/ui/webui/options2/options_ui_uitest.cc b/chrome/browser/ui/webui/options2/options_ui_uitest.cc new file mode 100644 index 0000000..b292213 --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_ui_uitest.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/options_ui_uitest.h" + +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/automation/automation_proxy.h" +#include "chrome/test/automation/browser_proxy.h" +#include "chrome/test/automation/tab_proxy.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +OptionsUITest::OptionsUITest() { + dom_automation_enabled_ = true; +} + +void OptionsUITest::NavigateToSettings(scoped_refptr<TabProxy> tab) { + const GURL& url = GURL(chrome::kChromeUISettingsURL); + ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, + tab->NavigateToURLBlockUntilNavigationsComplete(url, 1)) << url.spec(); +} + +void OptionsUITest::VerifyNavbar(scoped_refptr<TabProxy> tab) { + bool navbar_exist = false; + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"domAutomationController.send(" + L"!!document.getElementById('navbar'))", &navbar_exist)); + EXPECT_EQ(true, navbar_exist); +} + +void OptionsUITest::VerifyTitle(scoped_refptr<TabProxy> tab) { + std::wstring title; + EXPECT_TRUE(tab->GetTabTitle(&title)); + string16 expected_title = l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE); + EXPECT_NE(WideToUTF16Hack(title).find(expected_title), string16::npos); +} + +void OptionsUITest::VerifySections(scoped_refptr<TabProxy> tab) { +#if defined(OS_CHROMEOS) + const int kExpectedSections = 1 + 7; +#else + const int kExpectedSections = 1 + 4; +#endif + int num_of_sections = 0; + EXPECT_TRUE(tab->ExecuteAndExtractInt(L"", + L"domAutomationController.send(" + L"document.getElementById('navbar').children.length)", &num_of_sections)); + EXPECT_EQ(kExpectedSections, num_of_sections); +} + +TEST_F(OptionsUITest, LoadOptionsByURL) { + scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); + ASSERT_TRUE(browser.get()); + + scoped_refptr<TabProxy> tab = browser->GetActiveTab(); + ASSERT_TRUE(tab.get()); + + NavigateToSettings(tab); + VerifyTitle(tab); + VerifyNavbar(tab); + VerifySections(tab); +} diff --git a/chrome/browser/ui/webui/options2/options_ui_uitest.h b/chrome/browser/ui/webui/options2/options_ui_uitest.h new file mode 100644 index 0000000..3cc6806 --- /dev/null +++ b/chrome/browser/ui/webui/options2/options_ui_uitest.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_UI_UITEST_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_UI_UITEST_H_ +#pragma once + +#include "base/memory/scoped_ptr.h" +#include "chrome/test/ui/ui_test.h" + +class TabProxy; + +class OptionsUITest : public UITest { + public: + OptionsUITest(); + + // Navigate to the settings tab and block until complete. + void NavigateToSettings(scoped_refptr<TabProxy> tab); + + // Check navbar's existence. + void VerifyNavbar(scoped_refptr<TabProxy> tab); + + // Verify that the page title is correct. + // The only guarantee we can make about the title of a settings tab is that + // it should contain IDS_SETTINGS_TITLE somewhere. + void VerifyTitle(scoped_refptr<TabProxy> tab); + + // Check section headers in navbar. + // For ChromeOS, there should be 1 + 7: + // Search, Basics, Personal, System, Internet, Under the Hood, + // Users and Extensions. + // For other platforms, there should 1 + 4: + // Search, Basics, Personal, Under the Hood and Extensions. + void VerifySections(scoped_refptr<TabProxy> tab); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_OPTIONS_UI_UITEST_H_ diff --git a/chrome/browser/ui/webui/options2/pack_extension_handler.cc b/chrome/browser/ui/webui/options2/pack_extension_handler.cc new file mode 100644 index 0000000..0790482 --- /dev/null +++ b/chrome/browser/ui/webui/options2/pack_extension_handler.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/pack_extension_handler.h" + +#include "base/bind.h" +#include "base/utf_string_conversions.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +PackExtensionHandler::PackExtensionHandler() { +} + +PackExtensionHandler::~PackExtensionHandler() { + if (pack_job_.get()) + pack_job_->ClearClient(); +} + +void PackExtensionHandler::Initialize() { +} + +void PackExtensionHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + RegisterTitle(localized_strings, "clearBrowserDataOverlay", + IDS_CLEAR_BROWSING_DATA_TITLE); + + localized_strings->SetString("packExtensionOverlay", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE)); + localized_strings->SetString("packExtensionHeading", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING)); + localized_strings->SetString("packExtensionCommit", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON)); + localized_strings->SetString("packExtensionRootDir", + l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL)); + localized_strings->SetString("packExtensionPrivateKey", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL)); + localized_strings->SetString("packExtensionBrowseButton", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE)); +} + +void PackExtensionHandler::RegisterMessages() { + // Setup handlers specific to this panel. + web_ui_->RegisterMessageCallback("pack", + base::Bind(&PackExtensionHandler::HandlePackMessage, + base::Unretained(this))); +} + +void PackExtensionHandler::OnPackSuccess(const FilePath& crx_file, + const FilePath& pem_file) { + ListValue results; + web_ui_->CallJavascriptFunction("OptionsPage.closeOverlay", results); + + ShowAlert(UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file, + pem_file))); +} + +void PackExtensionHandler::OnPackFailure(const std::string& error) { + ShowAlert(error); +} + +void PackExtensionHandler::HandlePackMessage(const ListValue* args) { + std::string extension_path; + std::string private_key_path; + CHECK_EQ(2U, args->GetSize()); + CHECK(args->GetString(0, &extension_path)); + CHECK(args->GetString(1, &private_key_path)); + + FilePath root_directory = + FilePath::FromWStringHack(UTF8ToWide(extension_path)); + FilePath key_file = FilePath::FromWStringHack(UTF8ToWide(private_key_path)); + + if (root_directory.empty()) { + if (extension_path.empty()) { + ShowAlert(l10n_util::GetStringUTF8( + IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED)); + } else { + ShowAlert(l10n_util::GetStringUTF8( + IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID)); + } + + return; + } + + if (!private_key_path.empty() && key_file.empty()) { + ShowAlert(l10n_util::GetStringUTF8( + IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID)); + return; + } + + pack_job_ = new PackExtensionJob(this, root_directory, key_file); + pack_job_->Start(); +} + +void PackExtensionHandler::ShowAlert(const std::string& message) { + ListValue arguments; + arguments.Append(Value::CreateStringValue(message)); + web_ui_->CallJavascriptFunction("alert", arguments); +} diff --git a/chrome/browser/ui/webui/options2/pack_extension_handler.h b/chrome/browser/ui/webui/options2/pack_extension_handler.h new file mode 100644 index 0000000..1ae63c4 --- /dev/null +++ b/chrome/browser/ui/webui/options2/pack_extension_handler.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_PACK_EXTENSION_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_PACK_EXTENSION_HANDLER_H_ +#pragma once + +#include <string> + +#include "chrome/browser/browsing_data_remover.h" +#include "chrome/browser/extensions/pack_extension_job.h" +#include "chrome/browser/plugin_data_remover_helper.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +// Clear browser data handler page UI handler. +class PackExtensionHandler : public OptionsPage2UIHandler, + public PackExtensionJob::Client { + public: + PackExtensionHandler(); + virtual ~PackExtensionHandler(); + + // OptionsPage2UIHandler implementation. + virtual void Initialize() OVERRIDE; + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // ExtensionPackJob::Client + virtual void OnPackSuccess(const FilePath& crx_file, + const FilePath& key_file) OVERRIDE; + + virtual void OnPackFailure(const std::string& error) OVERRIDE; + + private: + // Javascript callback to start packing an extension. + void HandlePackMessage(const ListValue* args); + + // A function to ask the webpage to show an alert. + void ShowAlert(const std::string& message); + + // Used to package the extension. + scoped_refptr<PackExtensionJob> pack_job_; + + DISALLOW_COPY_AND_ASSIGN(PackExtensionHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_PACK_EXTENSION_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/password_manager_browsertest.js b/chrome/browser/ui/webui/options2/password_manager_browsertest.js new file mode 100644 index 0000000..98c632d --- /dev/null +++ b/chrome/browser/ui/webui/options2/password_manager_browsertest.js @@ -0,0 +1,25 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for password manager WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function PasswordManagerWebUITest() {} + +PasswordManagerWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the password manager. + **/ + browsePreload: 'chrome://settings/passwords', +}; + +// Test opening the password manager has correct location. +TEST_F('PasswordManagerWebUITest', 'testOpenPasswordManager', + function() { + assertEquals(this.browsePreload, document.location.href); + }); diff --git a/chrome/browser/ui/webui/options2/password_manager_handler.cc b/chrome/browser/ui/webui/options2/password_manager_handler.cc new file mode 100644 index 0000000..b0990bb --- /dev/null +++ b/chrome/browser/ui/webui/options2/password_manager_handler.cc @@ -0,0 +1,291 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/password_manager_handler.h" + +#include "base/bind.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "net/base/net_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "webkit/glue/password_form.h" + +PasswordManagerHandler::PasswordManagerHandler() + : ALLOW_THIS_IN_INITIALIZER_LIST(populater_(this)), + ALLOW_THIS_IN_INITIALIZER_LIST(exception_populater_(this)) { +} + +PasswordManagerHandler::~PasswordManagerHandler() { + PasswordStore* store = GetPasswordStore(); + if (store) + store->RemoveObserver(this); +} + +void PasswordManagerHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static const OptionsStringResource resources[] = { + { "savedPasswordsTitle", + IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE }, + { "passwordExceptionsTitle", + IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE }, + { "passwordSearchPlaceholder", + IDS_PASSWORDS_PAGE_SEARCH_PASSWORDS }, + { "passwordShowButton", + IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON }, + { "passwordHideButton", + IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON }, + { "passwordsSiteColumn", + IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN }, + { "passwordsUsernameColumn", + IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN }, + { "passwordsRemoveButton", + IDS_PASSWORDS_PAGE_VIEW_REMOVE_BUTTON }, + { "passwordsNoPasswordsDescription", + IDS_PASSWORDS_PAGE_VIEW_NO_PASSWORDS_DESCRIPTION }, + { "passwordsNoExceptionsDescription", + IDS_PASSWORDS_PAGE_VIEW_NO_EXCEPTIONS_DESCRIPTION }, + { "passwordsRemoveAllButton", + IDS_PASSWORDS_PAGE_VIEW_REMOVE_ALL_BUTTON }, + { "passwordsRemoveAllTitle", + IDS_PASSWORDS_PAGE_VIEW_CAPTION_DELETE_ALL_PASSWORDS }, + { "passwordsRemoveAllWarning", + IDS_PASSWORDS_PAGE_VIEW_TEXT_DELETE_ALL_PASSWORDS }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "passwordsPage", + IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE); + + localized_strings->SetString("passwordManagerLearnMoreURL", + google_util::AppendGoogleLocaleParam( + GURL(chrome::kPasswordManagerLearnMoreURL)).spec()); +} + +void PasswordManagerHandler::Initialize() { + // Due to the way that handlers are (re)initialized under certain types of + // navigation, we may already be initialized. (See bugs 88986 and 86448.) + // If this is the case, return immediately. This is a hack. + // TODO(mdm): remove this hack once it is no longer necessary. + if (!show_passwords_.GetPrefName().empty()) + return; + + show_passwords_.Init(prefs::kPasswordManagerAllowShowPasswords, + Profile::FromWebUI(web_ui_)->GetPrefs(), this); + // We should not cache web_ui_->GetProfile(). See crosbug.com/6304. + PasswordStore* store = GetPasswordStore(); + if (store) + store->AddObserver(this); +} + +void PasswordManagerHandler::RegisterMessages() { + DCHECK(web_ui_); + + web_ui_->RegisterMessageCallback("updatePasswordLists", + base::Bind(&PasswordManagerHandler::UpdatePasswordLists, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeSavedPassword", + base::Bind(&PasswordManagerHandler::RemoveSavedPassword, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removePasswordException", + base::Bind(&PasswordManagerHandler::RemovePasswordException, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeAllSavedPasswords", + base::Bind(&PasswordManagerHandler::RemoveAllSavedPasswords, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("removeAllPasswordExceptions", + base::Bind(&PasswordManagerHandler::RemoveAllPasswordExceptions, + base::Unretained(this))); +} + +void PasswordManagerHandler::OnLoginsChanged() { + UpdatePasswordLists(NULL); +} + +PasswordStore* PasswordManagerHandler::GetPasswordStore() { + return Profile::FromWebUI(web_ui_)-> + GetPasswordStore(Profile::EXPLICIT_ACCESS); +} + +void PasswordManagerHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_PREF_CHANGED) { + std::string* pref_name = content::Details<std::string>(details).ptr(); + if (*pref_name == prefs::kPasswordManagerAllowShowPasswords) { + UpdatePasswordLists(NULL); + } + } + + OptionsPage2UIHandler::Observe(type, source, details); +} + +void PasswordManagerHandler::UpdatePasswordLists(const ListValue* args) { + // Reset the current lists. + password_list_.reset(); + password_exception_list_.reset(); + + languages_ = Profile::FromWebUI(web_ui_)->GetPrefs()-> + GetString(prefs::kAcceptLanguages); + populater_.Populate(); + exception_populater_.Populate(); +} + +void PasswordManagerHandler::RemoveSavedPassword(const ListValue* args) { + PasswordStore* store = GetPasswordStore(); + if (!store) + return; + std::string string_value = UTF16ToUTF8(ExtractStringValue(args)); + int index; + if (base::StringToInt(string_value, &index) && index >= 0 && + static_cast<size_t>(index) < password_list_.size()) + store->RemoveLogin(*password_list_[index]); +} + +void PasswordManagerHandler::RemovePasswordException( + const ListValue* args) { + PasswordStore* store = GetPasswordStore(); + if (!store) + return; + std::string string_value = UTF16ToUTF8(ExtractStringValue(args)); + int index; + if (base::StringToInt(string_value, &index) && index >= 0 && + static_cast<size_t>(index) < password_exception_list_.size()) + store->RemoveLogin(*password_exception_list_[index]); +} + +void PasswordManagerHandler::RemoveAllSavedPasswords( + const ListValue* args) { + // TODO(jhawkins): This will cause a list refresh for every password in the + // list. Add PasswordStore::RemoveAllLogins(). + PasswordStore* store = GetPasswordStore(); + if (!store) + return; + for (size_t i = 0; i < password_list_.size(); ++i) + store->RemoveLogin(*password_list_[i]); +} + +void PasswordManagerHandler::RemoveAllPasswordExceptions( + const ListValue* args) { + PasswordStore* store = GetPasswordStore(); + if (!store) + return; + for (size_t i = 0; i < password_exception_list_.size(); ++i) + store->RemoveLogin(*password_exception_list_[i]); +} + +void PasswordManagerHandler::SetPasswordList() { + // Due to the way that handlers are (re)initialized under certain types of + // navigation, we may not be initialized yet. (See bugs 88986 and 86448.) + // If this is the case, initialize on demand. This is a hack. + // TODO(mdm): remove this hack once it is no longer necessary. + if (show_passwords_.GetPrefName().empty()) + Initialize(); + + ListValue entries; + bool show_passwords = *show_passwords_; + string16 empty; + for (size_t i = 0; i < password_list_.size(); ++i) { + ListValue* entry = new ListValue(); + entry->Append(new StringValue(net::FormatUrl(password_list_[i]->origin, + languages_))); + entry->Append(new StringValue(password_list_[i]->username_value)); + entry->Append(new StringValue( + show_passwords ? password_list_[i]->password_value : empty)); + entries.Append(entry); + } + + web_ui_->CallJavascriptFunction("PasswordManager.setSavedPasswordsList", + entries); +} + +void PasswordManagerHandler::SetPasswordExceptionList() { + ListValue entries; + for (size_t i = 0; i < password_exception_list_.size(); ++i) { + entries.Append(new StringValue( + net::FormatUrl(password_exception_list_[i]->origin, languages_))); + } + + web_ui_->CallJavascriptFunction("PasswordManager.setPasswordExceptionsList", + entries); +} + +PasswordManagerHandler::ListPopulater::ListPopulater( + PasswordManagerHandler* page) + : page_(page), + pending_login_query_(0) { +} + +PasswordManagerHandler::ListPopulater::~ListPopulater() { +} + +PasswordManagerHandler::PasswordListPopulater::PasswordListPopulater( + PasswordManagerHandler* page) : ListPopulater(page) { +} + +void PasswordManagerHandler::PasswordListPopulater::Populate() { + PasswordStore* store = page_->GetPasswordStore(); + if (store != NULL) { + if (pending_login_query_) + store->CancelRequest(pending_login_query_); + + pending_login_query_ = store->GetAutofillableLogins(this); + } else { + LOG(ERROR) << "No password store! Cannot display passwords."; + } +} + +void PasswordManagerHandler::PasswordListPopulater:: + OnPasswordStoreRequestDone( + CancelableRequestProvider::Handle handle, + const std::vector<webkit_glue::PasswordForm*>& result) { + DCHECK_EQ(pending_login_query_, handle); + pending_login_query_ = 0; + page_->password_list_.reset(); + page_->password_list_.insert(page_->password_list_.end(), + result.begin(), result.end()); + page_->SetPasswordList(); +} + +PasswordManagerHandler::PasswordExceptionListPopulater:: + PasswordExceptionListPopulater(PasswordManagerHandler* page) + : ListPopulater(page) { +} + +void PasswordManagerHandler::PasswordExceptionListPopulater::Populate() { + PasswordStore* store = page_->GetPasswordStore(); + if (store != NULL) { + if (pending_login_query_) + store->CancelRequest(pending_login_query_); + + pending_login_query_ = store->GetBlacklistLogins(this); + } else { + LOG(ERROR) << "No password store! Cannot display exceptions."; + } +} + +void PasswordManagerHandler::PasswordExceptionListPopulater:: + OnPasswordStoreRequestDone( + CancelableRequestProvider::Handle handle, + const std::vector<webkit_glue::PasswordForm*>& result) { + DCHECK_EQ(pending_login_query_, handle); + pending_login_query_ = 0; + page_->password_exception_list_.reset(); + page_->password_exception_list_.insert(page_->password_exception_list_.end(), + result.begin(), result.end()); + page_->SetPasswordExceptionList(); +} diff --git a/chrome/browser/ui/webui/options2/password_manager_handler.h b/chrome/browser/ui/webui/options2/password_manager_handler.h new file mode 100644 index 0000000..a475055 --- /dev/null +++ b/chrome/browser/ui/webui/options2/password_manager_handler.h @@ -0,0 +1,129 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_PASSWORD_MANAGER_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_PASSWORD_MANAGER_HANDLER_H_ + +#include <string> +#include <vector> + +#include "base/memory/scoped_vector.h" +#include "chrome/browser/password_manager/password_store.h" +#include "chrome/browser/password_manager/password_store_consumer.h" +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +class PasswordManagerHandler : public OptionsPage2UIHandler, + public PasswordStore::Observer { + public: + PasswordManagerHandler(); + virtual ~PasswordManagerHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // PasswordStore::Observer implementation. + virtual void OnLoginsChanged() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + // The password store associated with the currently active profile. + PasswordStore* GetPasswordStore(); + + // Called when the JS PasswordManager object is initialized. + void UpdatePasswordLists(const ListValue* args); + + // Remove an entry. + // @param value the entry index to be removed. + void RemoveSavedPassword(const ListValue* args); + + // Remove an password exception. + // @param value the entry index to be removed. + void RemovePasswordException(const ListValue* args); + + // Remove all saved passwords + void RemoveAllSavedPasswords(const ListValue* args); + + // Remove All password exceptions + void RemoveAllPasswordExceptions(const ListValue* args); + + // Get password value for the selected entry. + // @param value the selected entry index. + void ShowSelectedPassword(const ListValue* args); + + // Sets the password and exception list contents to the given data. + // We take ownership of the PasswordForms in the vector. + void SetPasswordList(); + void SetPasswordExceptionList(); + + // A short class to mediate requests to the password store. + class ListPopulater : public PasswordStoreConsumer { + public: + explicit ListPopulater(PasswordManagerHandler* page); + virtual ~ListPopulater(); + + // Send a query to the password store to populate a list. + virtual void Populate() = 0; + + // Send the password store's reply back to the handler. + virtual void OnPasswordStoreRequestDone( + CancelableRequestProvider::Handle handle, + const std::vector<webkit_glue::PasswordForm*>& result) = 0; + + protected: + PasswordManagerHandler* page_; + CancelableRequestProvider::Handle pending_login_query_; + }; + + // A short class to mediate requests to the password store for passwordlist. + class PasswordListPopulater : public ListPopulater { + public: + explicit PasswordListPopulater(PasswordManagerHandler* page); + + // Send a query to the password store to populate a password list. + virtual void Populate() OVERRIDE; + + // Send the password store's reply back to the handler. + virtual void OnPasswordStoreRequestDone( + CancelableRequestProvider::Handle handle, + const std::vector<webkit_glue::PasswordForm*>& result) OVERRIDE; + }; + + // A short class to mediate requests to the password store for exceptions. + class PasswordExceptionListPopulater : public ListPopulater { + public: + explicit PasswordExceptionListPopulater(PasswordManagerHandler* page); + + // Send a query to the password store to populate a passwordException list. + virtual void Populate() OVERRIDE; + + // Send the password store's reply back to the handler. + virtual void OnPasswordStoreRequestDone( + CancelableRequestProvider::Handle handle, + const std::vector<webkit_glue::PasswordForm*>& result) OVERRIDE; + }; + + // Password store consumer for populating the password list and exceptions. + PasswordListPopulater populater_; + PasswordExceptionListPopulater exception_populater_; + + ScopedVector<webkit_glue::PasswordForm> password_list_; + ScopedVector<webkit_glue::PasswordForm> password_exception_list_; + + // User's pref + std::string languages_; + + // Whether to show stored passwords or not. + BooleanPrefMember show_passwords_; + + DISALLOW_COPY_AND_ASSIGN(PasswordManagerHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_PASSWORD_MANAGER_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/personal_options_browsertest.js b/chrome/browser/ui/webui/options2/personal_options_browsertest.js new file mode 100644 index 0000000..222adfa --- /dev/null +++ b/chrome/browser/ui/webui/options2/personal_options_browsertest.js @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for personal options WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function PersonalOptionsWebUITest() {} + +PersonalOptionsWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to personal options. + **/ + browsePreload: 'chrome://settings/personal', +}; + +// Test opening personal options has correct location. +TEST_F('PersonalOptionsWebUITest', 'testOpenPersonalOptions', function() { + assertEquals(this.browsePreload, document.location.href); +}); diff --git a/chrome/browser/ui/webui/options2/personal_options_handler.cc b/chrome/browser/ui/webui/options2/personal_options_handler.cc new file mode 100644 index 0000000..e50f810 --- /dev/null +++ b/chrome/browser/ui/webui/options2/personal_options_handler.cc @@ -0,0 +1,442 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/personal_options_handler.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/path_service.h" +#include "base/stl_util.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/value_conversions.h" +#include "base/values.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_info_util.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_setup_flow.h" +#include "chrome/browser/sync/sync_ui_util.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" +#include "chrome/browser/ui/webui/web_ui_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/net/gaia/google_service_auth_error.h" +#include "chrome/common/url_constants.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/user_metrics.h" +#include "content/public/browser/notification_service.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/options2/take_photo_dialog.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/views/window.h" +#include "third_party/skia/include/core/SkBitmap.h" +#endif // defined(OS_CHROMEOS) +#if defined(TOOLKIT_GTK) +#include "chrome/browser/ui/gtk/gtk_theme_service.h" +#endif // defined(TOOLKIT_GTK) + +PersonalOptionsHandler::PersonalOptionsHandler() { + multiprofile_ = ProfileManager::IsMultipleProfilesEnabled(); +#if defined(OS_CHROMEOS) + registrar_.Add(this, + chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, + content::NotificationService::AllSources()); +#endif +} + +PersonalOptionsHandler::~PersonalOptionsHandler() { + ProfileSyncService* sync_service = + Profile::FromWebUI(web_ui_)->GetProfileSyncService(); + if (sync_service) + sync_service->RemoveObserver(this); +} + +void PersonalOptionsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "personalPage", + IDS_OPTIONS_CONTENT_TAB_LABEL); + + + localized_strings->SetString( + "syncOverview", + l10n_util::GetStringFUTF16(IDS_SYNC_OVERVIEW, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + localized_strings->SetString("syncSection", + l10n_util::GetStringUTF16(IDS_SYNC_OPTIONS_GROUP_NAME)); + localized_strings->SetString("customizeSync", + l10n_util::GetStringUTF16(IDS_SYNC_CUSTOMIZE_BUTTON_LABEL)); + localized_strings->SetString("syncLearnMoreURL", + google_util::StringAppendGoogleLocaleParam(chrome::kSyncLearnMoreURL)); + + localized_strings->SetString("profiles", + l10n_util::GetStringUTF16(IDS_PROFILES_OPTIONS_GROUP_NAME)); + localized_strings->SetString("profilesCreate", + l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_BUTTON_LABEL)); + localized_strings->SetString("profilesManage", + l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_BUTTON_LABEL)); + localized_strings->SetString("profilesDelete", + l10n_util::GetStringUTF16(IDS_PROFILES_DELETE_BUTTON_LABEL)); + localized_strings->SetString("profilesDeleteSingle", + l10n_util::GetStringUTF16(IDS_PROFILES_DELETE_SINGLE_BUTTON_LABEL)); + localized_strings->SetString("profilesListItemCurrent", + l10n_util::GetStringUTF16(IDS_PROFILES_LIST_ITEM_CURRENT)); + localized_strings->SetString("profilesSingleUser", + l10n_util::GetStringFUTF16(IDS_PROFILES_SINGLE_USER_MESSAGE, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + + localized_strings->SetString("passwords", + l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_GROUP_NAME)); + localized_strings->SetString("passwordsAskToSave", + l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_ASKTOSAVE)); + localized_strings->SetString("passwordsNeverSave", + l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_NEVERSAVE)); + localized_strings->SetString("manage_passwords", + l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS)); +#if defined(OS_MACOSX) + ProfileManager* profile_manager = g_browser_process->profile_manager(); + if (profile_manager->GetNumberOfProfiles() > 1) { + localized_strings->SetString("macPasswordsWarning", + l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MAC_WARNING)); + } +#endif + localized_strings->SetString("autologinEnabled", + l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_AUTOLOGIN)); + + localized_strings->SetString("autofill", + l10n_util::GetStringUTF16(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME)); + localized_strings->SetString("autofillEnabled", + l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOFILL_ENABLE)); + localized_strings->SetString("manageAutofillSettings", + l10n_util::GetStringUTF16(IDS_OPTIONS_MANAGE_AUTOFILL_SETTINGS)); + + localized_strings->SetString("browsingData", + l10n_util::GetStringUTF16(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME)); + localized_strings->SetString("importData", + l10n_util::GetStringUTF16(IDS_OPTIONS_IMPORT_DATA_BUTTON)); + + localized_strings->SetString("themesGallery", + l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_BUTTON)); + localized_strings->SetString("themesGalleryURL", + l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_URL)); + +#if defined(TOOLKIT_GTK) + localized_strings->SetString("appearance", + l10n_util::GetStringUTF16(IDS_APPEARANCE_GROUP_NAME)); + localized_strings->SetString("themesGTKButton", + l10n_util::GetStringUTF16(IDS_THEMES_GTK_BUTTON)); + localized_strings->SetString("themesSetClassic", + l10n_util::GetStringUTF16(IDS_THEMES_SET_CLASSIC)); + localized_strings->SetString("showWindowDecorations", + l10n_util::GetStringUTF16(IDS_SHOW_WINDOW_DECORATIONS_RADIO)); + localized_strings->SetString("hideWindowDecorations", + l10n_util::GetStringUTF16(IDS_HIDE_WINDOW_DECORATIONS_RADIO)); +#else + localized_strings->SetString("themes", + l10n_util::GetStringUTF16(IDS_THEMES_GROUP_NAME)); + localized_strings->SetString("themesReset", + l10n_util::GetStringUTF16(IDS_THEMES_RESET_BUTTON)); +#endif + + // Sync select control. + ListValue* sync_select_list = new ListValue; + ListValue* datatypes = new ListValue; + datatypes->Append(Value::CreateBooleanValue(false)); + datatypes->Append( + Value::CreateStringValue( + l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_DATATYPES))); + sync_select_list->Append(datatypes); + ListValue* everything = new ListValue; + everything->Append(Value::CreateBooleanValue(true)); + everything->Append( + Value::CreateStringValue( + l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_EVERYTHING))); + sync_select_list->Append(everything); + localized_strings->Set("syncSelectList", sync_select_list); + + // Sync page. + localized_strings->SetString("syncPage", + l10n_util::GetStringUTF16(IDS_SYNC_NTP_SYNC_SECTION_TITLE)); + localized_strings->SetString("sync_title", + l10n_util::GetStringUTF16(IDS_CUSTOMIZE_SYNC_DESCRIPTION)); + localized_strings->SetString("syncsettings", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PREFERENCES)); + localized_strings->SetString("syncbookmarks", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_BOOKMARKS)); + localized_strings->SetString("synctypedurls", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TYPED_URLS)); + localized_strings->SetString("syncpasswords", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PASSWORDS)); + localized_strings->SetString("syncextensions", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_EXTENSIONS)); + localized_strings->SetString("syncautofill", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_AUTOFILL)); + localized_strings->SetString("syncthemes", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_THEMES)); + localized_strings->SetString("syncapps", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_APPS)); + localized_strings->SetString("syncsessions", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TABS)); + +#if defined(OS_CHROMEOS) + localized_strings->SetString("account", + l10n_util::GetStringUTF16(IDS_OPTIONS_PERSONAL_ACCOUNT_GROUP_NAME)); + localized_strings->SetString("enableScreenlock", + l10n_util::GetStringUTF16(IDS_OPTIONS_ENABLE_SCREENLOCKER_CHECKBOX)); + localized_strings->SetString("changePicture", + l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE)); + if (chromeos::UserManager::Get()->user_is_logged_in()) { + localized_strings->SetString("username", + chromeos::UserManager::Get()->logged_in_user().email()); + } +#endif +} + +void PersonalOptionsHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback( + "themesReset", + base::Bind(&PersonalOptionsHandler::ThemesReset, + base::Unretained(this))); +#if defined(TOOLKIT_GTK) + web_ui_->RegisterMessageCallback( + "themesSetGTK", + base::Bind(&PersonalOptionsHandler::ThemesSetGTK, + base::Unretained(this))); +#endif + web_ui_->RegisterMessageCallback( + "createProfile", + base::Bind(&PersonalOptionsHandler::CreateProfile, + base::Unretained(this))); +} + +void PersonalOptionsHandler::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) { + ObserveThemeChanged(); + } else if (multiprofile_ && + type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) { + SendProfilesInfo(); +#if defined(OS_CHROMEOS) + } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) { + UpdateAccountPicture(); +#endif + } else { + OptionsPage2UIHandler::Observe(type, source, details); + } +} + +void PersonalOptionsHandler::OnStateChanged() { + string16 status_label; + string16 link_label; + ProfileSyncService* service = + Profile::FromWebUI(web_ui_)->GetProfileSyncService(); + DCHECK(service); + bool managed = service->IsManaged(); + bool sync_setup_completed = service->HasSyncSetupCompleted(); + bool status_has_error = sync_ui_util::GetStatusLabels( + service, sync_ui_util::WITH_HTML, &status_label, &link_label) == + sync_ui_util::SYNC_ERROR; + + string16 start_stop_button_label; + bool is_start_stop_button_visible = false; + bool is_start_stop_button_enabled = false; + if (sync_setup_completed) { + start_stop_button_label = + l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL); +#if defined(OS_CHROMEOS) + is_start_stop_button_visible = false; +#else + is_start_stop_button_visible = true; +#endif // defined(OS_CHROMEOS) + is_start_stop_button_enabled = !managed; + } else if (service->SetupInProgress()) { + start_stop_button_label = + l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS); + is_start_stop_button_visible = true; + is_start_stop_button_enabled = false; + } else { + start_stop_button_label = + l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL, + l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); + is_start_stop_button_visible = true; + is_start_stop_button_enabled = !managed; + } + + scoped_ptr<Value> completed(Value::CreateBooleanValue(sync_setup_completed)); + web_ui_->CallJavascriptFunction("PersonalOptions.setSyncSetupCompleted", + *completed); + + scoped_ptr<Value> label(Value::CreateStringValue(status_label)); + web_ui_->CallJavascriptFunction("PersonalOptions.setSyncStatus", *label); + + scoped_ptr<Value> enabled( + Value::CreateBooleanValue(is_start_stop_button_enabled)); + web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonEnabled", + *enabled); + + scoped_ptr<Value> visible( + Value::CreateBooleanValue(is_start_stop_button_visible)); + web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonVisible", + *visible); + + label.reset(Value::CreateStringValue(start_stop_button_label)); + web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonLabel", + *label); + + label.reset(Value::CreateStringValue(link_label)); + web_ui_->CallJavascriptFunction("PersonalOptions.setSyncActionLinkLabel", + *label); + + enabled.reset(Value::CreateBooleanValue(!managed)); + web_ui_->CallJavascriptFunction("PersonalOptions.setSyncActionLinkEnabled", + *enabled); + + visible.reset(Value::CreateBooleanValue(status_has_error)); + web_ui_->CallJavascriptFunction("PersonalOptions.setSyncStatusErrorVisible", + *visible); + + enabled.reset(Value::CreateBooleanValue( + !service->unrecoverable_error_detected())); + web_ui_->CallJavascriptFunction( + "PersonalOptions.setCustomizeSyncButtonEnabled", + *enabled); + + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAutologin)) { + visible.reset(Value::CreateBooleanValue( + service->AreCredentialsAvailable())); + web_ui_->CallJavascriptFunction("PersonalOptions.setAutoLoginVisible", + *visible); + } + + // Set profile creation text and button if multi-profiles switch is on. + visible.reset(Value::CreateBooleanValue(multiprofile_)); + web_ui_->CallJavascriptFunction("PersonalOptions.setProfilesSectionVisible", + *visible); + if (multiprofile_) + SendProfilesInfo(); +} + +void PersonalOptionsHandler::ObserveThemeChanged() { + Profile* profile = Profile::FromWebUI(web_ui_); +#if defined(TOOLKIT_GTK) + GtkThemeService* theme_service = GtkThemeService::GetFrom(profile); + bool is_gtk_theme = theme_service->UsingNativeTheme(); + base::FundamentalValue gtk_enabled(!is_gtk_theme); + web_ui_->CallJavascriptFunction( + "options.PersonalOptions.setGtkThemeButtonEnabled", gtk_enabled); +#else + ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile); + bool is_gtk_theme = false; +#endif + + bool is_classic_theme = !is_gtk_theme && theme_service->UsingDefaultTheme(); + base::FundamentalValue enabled(!is_classic_theme); + web_ui_->CallJavascriptFunction( + "options.PersonalOptions.setThemesResetButtonEnabled", enabled); +} + +void PersonalOptionsHandler::Initialize() { + Profile* profile = Profile::FromWebUI(web_ui_); + + // Listen for theme installation. + registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>( + ThemeServiceFactory::GetForProfile(profile))); + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllSources()); + ObserveThemeChanged(); + + ProfileSyncService* sync_service = profile->GetProfileSyncService(); + if (sync_service) { + sync_service->AddObserver(this); + OnStateChanged(); + } else { + web_ui_->CallJavascriptFunction("options.PersonalOptions.hideSyncSection"); + } +} + +void PersonalOptionsHandler::ThemesReset(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_ThemesReset")); + Profile* profile = Profile::FromWebUI(web_ui_); + ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme(); +} + +#if defined(TOOLKIT_GTK) +void PersonalOptionsHandler::ThemesSetGTK(const ListValue* args) { + UserMetrics::RecordAction(UserMetricsAction("Options_GtkThemeSet")); + Profile* profile = Profile::FromWebUI(web_ui_); + ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme(); +} +#endif + +#if defined(OS_CHROMEOS) +void PersonalOptionsHandler::UpdateAccountPicture() { + std::string email = chromeos::UserManager::Get()->logged_in_user().email(); + if (!email.empty()) { + web_ui_->CallJavascriptFunction("PersonalOptions.updateAccountPicture"); + base::StringValue email_value(email); + web_ui_->CallJavascriptFunction("AccountsOptions.updateAccountPicture", + email_value); + } +} +#endif + +void PersonalOptionsHandler::SendProfilesInfo() { + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + ListValue profile_info_list; + FilePath current_profile_path = + web_ui_->tab_contents()->browser_context()->GetPath(); + for (size_t i = 0, e = cache.GetNumberOfProfiles(); i < e; ++i) { + DictionaryValue* profile_value = new DictionaryValue(); + FilePath profile_path = cache.GetPathOfProfileAtIndex(i); + profile_value->SetString("name", cache.GetNameOfProfileAtIndex(i)); + profile_value->Set("filePath", base::CreateFilePathValue(profile_path)); + profile_value->SetBoolean("isCurrentProfile", + profile_path == current_profile_path); + + bool is_gaia_picture = + cache.IsUsingGAIAPictureOfProfileAtIndex(i) && + cache.GetGAIAPictureOfProfileAtIndex(i); + if (is_gaia_picture) { + gfx::Image icon = profiles::GetAvatarIconForWebUI( + cache.GetAvatarIconOfProfileAtIndex(i), true); + profile_value->SetString("iconURL", web_ui_util::GetImageDataUrl(icon)); + } else { + size_t icon_index = cache.GetAvatarIconIndexOfProfileAtIndex(i); + profile_value->SetString("iconURL", + cache.GetDefaultAvatarIconUrl(icon_index)); + } + + profile_info_list.Append(profile_value); + } + + web_ui_->CallJavascriptFunction("PersonalOptions.setProfilesInfo", + profile_info_list); +} + +void PersonalOptionsHandler::CreateProfile(const ListValue* args) { + ProfileManager::CreateMultiProfileAsync(); +} diff --git a/chrome/browser/ui/webui/options2/personal_options_handler.h b/chrome/browser/ui/webui/options2/personal_options_handler.h new file mode 100644 index 0000000..06e364b --- /dev/null +++ b/chrome/browser/ui/webui/options2/personal_options_handler.h @@ -0,0 +1,70 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_PERSONAL_OPTIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_PERSONAL_OPTIONS_HANDLER_H_ +#pragma once + +#include "base/basictypes.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#if defined(OS_CHROMEOS) +#include "content/public/browser/notification_registrar.h" +#endif + +// Chrome personal options page UI handler. +class PersonalOptionsHandler : public OptionsPage2UIHandler, + public ProfileSyncServiceObserver { + public: + PersonalOptionsHandler(); + virtual ~PersonalOptionsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE; + virtual void Initialize() OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // ProfileSyncServiceObserver implementation. + virtual void OnStateChanged() OVERRIDE; + + private: + void ObserveThemeChanged(); + void ThemesReset(const ListValue* args); +#if defined(TOOLKIT_GTK) + void ThemesSetGTK(const ListValue* args); +#endif + +#if defined(OS_CHROMEOS) + void UpdateAccountPicture(); + content::NotificationRegistrar registrar_; +#endif + + // Sends an array of Profile objects to javascript. + // Each object is of the form: + // profileInfo = { + // name: "Profile Name", + // iconURL: "chrome://path/to/icon/image", + // filePath: "/path/to/profile/data/on/disk", + // isCurrentProfile: false + // }; + void SendProfilesInfo(); + + // Asynchronously opens a new browser window to create a new profile. + // |args| is not used. + void CreateProfile(const ListValue* args); + + // True if the multiprofiles switch is enabled. + bool multiprofile_; + + DISALLOW_COPY_AND_ASSIGN(PersonalOptionsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_PERSONAL_OPTIONS_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/search_engine_manager_browsertest.js b/chrome/browser/ui/webui/options2/search_engine_manager_browsertest.js new file mode 100644 index 0000000..9fe2165 --- /dev/null +++ b/chrome/browser/ui/webui/options2/search_engine_manager_browsertest.js @@ -0,0 +1,33 @@ +// Copyright (c) 2011 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. + +/** + * TestFixture for search engine manager WebUI testing. + * @extends {testing.Test} + * @constructor + **/ +function SearchEngineManagerWebUITest() {} + +SearchEngineManagerWebUITest.prototype = { + __proto__: testing.Test.prototype, + + /** + * Browse to the search engine manager. + **/ + browsePreload: 'chrome://settings/searchEngines', +}; + +// See crosbug.com/22673 +GEN('#if defined(OS_CHROMEOS)'); +GEN('#define MAYBE_testOpenSearchEngineManager ' + + 'DISABLED_testOpenSearchEngineManager'); +GEN('#else'); +GEN('#define MAYBE_testOpenSearchEngineManager testOpenSearchEngineManager'); +GEN('#endif // defined(OS_CHROMEOS)'); + +// Test opening the search engine manager has correct location. +TEST_F('SearchEngineManagerWebUITest', 'MAYBE_testOpenSearchEngineManager', + function() { + assertEquals(this.browsePreload, document.location.href); + }); diff --git a/chrome/browser/ui/webui/options2/search_engine_manager_handler.cc b/chrome/browser/ui/webui/options2/search_engine_manager_handler.cc new file mode 100644 index 0000000..1e289d8 --- /dev/null +++ b/chrome/browser/ui/webui/options2/search_engine_manager_handler.cc @@ -0,0 +1,313 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/search_engine_manager_handler.h" + +#include "base/bind.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_service.h" +#include "chrome/browser/ui/search_engines/keyword_editor_controller.h" +#include "chrome/browser/ui/search_engines/template_url_table_model.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/url_constants.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +enum EngineInfoIndexes { + ENGINE_NAME, + ENGINE_KEYWORD, + ENGINE_URL, +}; + +}; // namespace + +SearchEngineManagerHandler::SearchEngineManagerHandler() { +} + +SearchEngineManagerHandler::~SearchEngineManagerHandler() { + if (list_controller_.get() && list_controller_->table_model()) + list_controller_->table_model()->SetObserver(NULL); +} + +void SearchEngineManagerHandler::Initialize() { + list_controller_.reset( + new KeywordEditorController(Profile::FromWebUI(web_ui_))); + if (list_controller_.get()) { + list_controller_->table_model()->SetObserver(this); + OnModelChanged(); + } +} + +void SearchEngineManagerHandler::GetLocalizedValues( + base::DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + RegisterTitle(localized_strings, "searchEngineManagerPage", + IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE); + localized_strings->SetString("defaultSearchEngineListTitle", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAIN_SEPARATOR)); + localized_strings->SetString("otherSearchEngineListTitle", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_OTHER_SEPARATOR)); + localized_strings->SetString("extensionKeywordsListTitle", + l10n_util::GetStringUTF16( + IDS_SEARCH_ENGINES_EDITOR_EXTENSIONS_SEPARATOR)); + localized_strings->SetString("manageExtensionsLinkText", + l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS)); + localized_strings->SetString("searchEngineTableNameHeader", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN)); + localized_strings->SetString("searchEngineTableKeywordHeader", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN)); + localized_strings->SetString("searchEngineTableURLHeader", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_EDIT_BUTTON)); + localized_strings->SetString("makeDefaultSearchEngineButton", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAKE_DEFAULT_BUTTON)); + localized_strings->SetString("searchEngineTableNamePlaceholder", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINE_ADD_NEW_NAME_PLACEHOLDER)); + localized_strings->SetString("searchEngineTableKeywordPlaceholder", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINE_ADD_NEW_KEYWORD_PLACEHOLDER)); + localized_strings->SetString("searchEngineTableURLPlaceholder", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINE_ADD_NEW_URL_PLACEHOLDER)); + localized_strings->SetString("editSearchEngineInvalidTitleToolTip", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_INVALID_TITLE_TT)); + localized_strings->SetString("editSearchEngineInvalidKeywordToolTip", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT)); + localized_strings->SetString("editSearchEngineInvalidURLToolTip", + l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_INVALID_URL_TT)); +} + +void SearchEngineManagerHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback( + "managerSetDefaultSearchEngine", + base::Bind(&SearchEngineManagerHandler::SetDefaultSearchEngine, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "removeSearchEngine", + base::Bind(&SearchEngineManagerHandler::RemoveSearchEngine, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "editSearchEngine", + base::Bind(&SearchEngineManagerHandler::EditSearchEngine, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "checkSearchEngineInfoValidity", + base::Bind(&SearchEngineManagerHandler::CheckSearchEngineInfoValidity, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "searchEngineEditCancelled", + base::Bind(&SearchEngineManagerHandler::EditCancelled, + base::Unretained(this))); + web_ui_->RegisterMessageCallback( + "searchEngineEditCompleted", + base::Bind(&SearchEngineManagerHandler::EditCompleted, + base::Unretained(this))); +} + +void SearchEngineManagerHandler::OnModelChanged() { + if (!list_controller_->loaded()) + return; + + // Find the default engine. + const TemplateURL* default_engine = + list_controller_->url_model()->GetDefaultSearchProvider(); + int default_index = list_controller_->table_model()->IndexOfTemplateURL( + default_engine); + + // Build the first list (default search engine options). + ListValue defaults_list; + int last_default_engine_index = + list_controller_->table_model()->last_search_engine_index(); + for (int i = 0; i < last_default_engine_index; ++i) { + defaults_list.Append(CreateDictionaryForEngine(i, i == default_index)); + } + + // Build the second list (other search templates). + ListValue others_list; + if (last_default_engine_index < 0) + last_default_engine_index = 0; + int engine_count = list_controller_->table_model()->RowCount(); + for (int i = last_default_engine_index; i < engine_count; ++i) { + others_list.Append(CreateDictionaryForEngine(i, i == default_index)); + } + + // Build the extension keywords list. + ListValue keyword_list; + ExtensionService* extension_service = + Profile::FromWebUI(web_ui_)->GetExtensionService(); + if (extension_service) { + const ExtensionSet* extensions = extension_service->extensions(); + for (ExtensionSet::const_iterator it = extensions->begin(); + it != extensions->end(); ++it) { + if ((*it)->omnibox_keyword().size() > 0) + keyword_list.Append(CreateDictionaryForExtension(*(*it))); + } + } + + web_ui_->CallJavascriptFunction("SearchEngineManager.updateSearchEngineList", + defaults_list, others_list, keyword_list); +} + +void SearchEngineManagerHandler::OnItemsChanged(int start, int length) { + OnModelChanged(); +} + +void SearchEngineManagerHandler::OnItemsAdded(int start, int length) { + OnModelChanged(); +} + +void SearchEngineManagerHandler::OnItemsRemoved(int start, int length) { + OnModelChanged(); +} + +base::DictionaryValue* SearchEngineManagerHandler::CreateDictionaryForExtension( + const Extension& extension) { + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetString("name", extension.name()); + dict->SetString("displayName", extension.name()); + dict->SetString("keyword", extension.omnibox_keyword()); + GURL icon = extension.GetIconURL(16, ExtensionIconSet::MATCH_BIGGER); + dict->SetString("iconURL", icon.spec()); + dict->SetString("url", string16()); + return dict; +} + +base::DictionaryValue* SearchEngineManagerHandler::CreateDictionaryForEngine( + int index, bool is_default) { + TemplateURLTableModel* table_model = list_controller_->table_model(); + const TemplateURL* template_url = list_controller_->GetTemplateURL(index); + + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetString("name", template_url->short_name()); + dict->SetString("displayName", table_model->GetText( + index, IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN)); + dict->SetString("keyword", table_model->GetText( + index, IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN)); + dict->SetString("url", template_url->url()->DisplayURL()); + dict->SetBoolean("urlLocked", template_url->prepopulate_id() > 0); + GURL icon_url = template_url->GetFaviconURL(); + if (icon_url.is_valid()) + dict->SetString("iconURL", icon_url.spec()); + dict->SetString("modelIndex", base::IntToString(index)); + + if (list_controller_->CanRemove(template_url)) + dict->SetString("canBeRemoved", "1"); + if (list_controller_->CanMakeDefault(template_url)) + dict->SetString("canBeDefault", "1"); + if (is_default) + dict->SetString("default", "1"); + if (list_controller_->CanEdit(template_url)) + dict->SetString("canBeEdited", "1"); + + return dict; +} + +void SearchEngineManagerHandler::SetDefaultSearchEngine(const ListValue* args) { + int index; + if (!ExtractIntegerValue(args, &index)) { + NOTREACHED(); + return; + } + if (index < 0 || index >= list_controller_->table_model()->RowCount()) + return; + + list_controller_->MakeDefaultTemplateURL(index); +} + +void SearchEngineManagerHandler::RemoveSearchEngine(const ListValue* args) { + int index; + if (!ExtractIntegerValue(args, &index)) { + NOTREACHED(); + return; + } + if (index < 0 || index >= list_controller_->table_model()->RowCount()) + return; + + if (list_controller_->CanRemove(list_controller_->GetTemplateURL(index))) + list_controller_->RemoveTemplateURL(index); +} + +void SearchEngineManagerHandler::EditSearchEngine(const ListValue* args) { + int index; + if (!ExtractIntegerValue(args, &index)) { + NOTREACHED(); + return; + } + // Allow -1, which means we are adding a new engine. + if (index < -1 || index >= list_controller_->table_model()->RowCount()) + return; + + const TemplateURL* edit_url = NULL; + if (index != -1) + edit_url = list_controller_->GetTemplateURL(index); + edit_controller_.reset(new EditSearchEngineController( + edit_url, this, Profile::FromWebUI(web_ui_))); +} + +void SearchEngineManagerHandler::OnEditedKeyword( + const TemplateURL* template_url, + const string16& title, + const string16& keyword, + const std::string& url) { + if (template_url) { + list_controller_->ModifyTemplateURL(template_url, title, keyword, url); + } else { + list_controller_->AddTemplateURL(title, keyword, url); + } + edit_controller_.reset(); +} + +void SearchEngineManagerHandler::CheckSearchEngineInfoValidity( + const ListValue* args) +{ + if (!edit_controller_.get()) + return; + string16 name; + string16 keyword; + std::string url; + std::string modelIndex; + if (!args->GetString(ENGINE_NAME, &name) || + !args->GetString(ENGINE_KEYWORD, &keyword) || + !args->GetString(ENGINE_URL, &url) || + !args->GetString(3, &modelIndex)) { + NOTREACHED(); + return; + } + + base::DictionaryValue validity; + validity.SetBoolean("name", edit_controller_->IsTitleValid(name)); + validity.SetBoolean("keyword", edit_controller_->IsKeywordValid(keyword)); + validity.SetBoolean("url", edit_controller_->IsURLValid(url)); + StringValue indexValue(modelIndex); + web_ui_->CallJavascriptFunction("SearchEngineManager.validityCheckCallback", + validity, indexValue); +} + +void SearchEngineManagerHandler::EditCancelled(const ListValue* args) { + if (!edit_controller_.get()) + return; + edit_controller_->CleanUpCancelledAdd(); + edit_controller_.reset(); +} + +void SearchEngineManagerHandler::EditCompleted(const ListValue* args) { + if (!edit_controller_.get()) + return; + string16 name; + string16 keyword; + std::string url; + if (!args->GetString(ENGINE_NAME, &name) || + !args->GetString(ENGINE_KEYWORD, &keyword) || + !args->GetString(ENGINE_URL, &url)) { + NOTREACHED(); + return; + } + edit_controller_->AcceptAddOrEdit(name, keyword, url); +} diff --git a/chrome/browser/ui/webui/options2/search_engine_manager_handler.h b/chrome/browser/ui/webui/options2/search_engine_manager_handler.h new file mode 100644 index 0000000..0d71764 --- /dev/null +++ b/chrome/browser/ui/webui/options2/search_engine_manager_handler.h @@ -0,0 +1,79 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_SEARCH_ENGINE_MANAGER_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_SEARCH_ENGINE_MANAGER_HANDLER_H_ + +#include "chrome/browser/ui/search_engines/edit_search_engine_controller.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" +#include "ui/base/models/table_model_observer.h" + +class Extension; +class KeywordEditorController; + +class SearchEngineManagerHandler : public OptionsPage2UIHandler, + public ui::TableModelObserver, + public EditSearchEngineControllerDelegate { + public: + SearchEngineManagerHandler(); + virtual ~SearchEngineManagerHandler(); + + virtual void Initialize() OVERRIDE; + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // ui::TableModelObserver implementation. + virtual void OnModelChanged() OVERRIDE; + virtual void OnItemsChanged(int start, int length) OVERRIDE; + virtual void OnItemsAdded(int start, int length) OVERRIDE; + virtual void OnItemsRemoved(int start, int length) OVERRIDE; + + // EditSearchEngineControllerDelegate implementation. + virtual void OnEditedKeyword(const TemplateURL* template_url, + const string16& title, + const string16& keyword, + const std::string& url) OVERRIDE; + + virtual void RegisterMessages() OVERRIDE; + + private: + scoped_ptr<KeywordEditorController> list_controller_; + scoped_ptr<EditSearchEngineController> edit_controller_; + + // Removes the search engine at the given index. Called from WebUI. + void RemoveSearchEngine(const base::ListValue* args); + + // Sets the search engine at the given index to be default. Called from WebUI. + void SetDefaultSearchEngine(const base::ListValue* args); + + // Starts an edit session for the search engine at the given index. If the + // index is -1, starts editing a new search engine instead of an existing one. + // Called from WebUI. + void EditSearchEngine(const base::ListValue* args); + + // Validates the given search engine values, and reports the results back + // to WebUI. Called from WebUI. + void CheckSearchEngineInfoValidity(const base::ListValue* args); + + // Called when an edit is cancelled. + // Called from WebUI. + void EditCancelled(const base::ListValue* args); + + // Called when an edit is finished and should be saved. + // Called from WebUI. + void EditCompleted(const base::ListValue* args); + + // Returns a dictionary to pass to WebUI representing the given search engine. + base::DictionaryValue* CreateDictionaryForEngine(int index, bool is_default); + + // Returns a dictionary to pass to WebUI representing the extension. + base::DictionaryValue* CreateDictionaryForExtension( + const Extension& extension); + + DISALLOW_COPY_AND_ASSIGN(SearchEngineManagerHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_SEARCH_ENGINE_MANAGER_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/stop_syncing_handler.cc b/chrome/browser/ui/webui/options2/stop_syncing_handler.cc new file mode 100644 index 0000000..550cc4c --- /dev/null +++ b/chrome/browser/ui/webui/options2/stop_syncing_handler.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/stop_syncing_handler.h" + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/common/url_constants.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +StopSyncingHandler::StopSyncingHandler() { +} + +StopSyncingHandler::~StopSyncingHandler() { +} + +void StopSyncingHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + localized_strings->SetString("stopSyncingExplanation", + l10n_util::GetStringFUTF16( + IDS_SYNC_STOP_SYNCING_EXPLANATION_LABEL, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), + ASCIIToUTF16(google_util::StringAppendGoogleLocaleParam( + chrome::kSyncGoogleDashboardURL)))); + localized_strings->SetString("stopSyncingTitle", + l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_DIALOG_TITLE)); + localized_strings->SetString("stopSyncingConfirm", + l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_CONFIRM_BUTTON_LABEL)); +} + +void StopSyncingHandler::RegisterMessages() { + DCHECK(web_ui_); + web_ui_->RegisterMessageCallback("stopSyncing", + base::Bind(&StopSyncingHandler::StopSyncing, base::Unretained(this))); +} + +void StopSyncingHandler::StopSyncing(const ListValue* args){ + ProfileSyncService* service = + Profile::FromWebUI(web_ui_)->GetProfileSyncService(); + if (service != NULL && ProfileSyncService::IsSyncEnabled()) { + service->DisableForUser(); + ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS); + } +} diff --git a/chrome/browser/ui/webui/options2/stop_syncing_handler.h b/chrome/browser/ui/webui/options2/stop_syncing_handler.h new file mode 100644 index 0000000..b9c3ad5 --- /dev/null +++ b/chrome/browser/ui/webui/options2/stop_syncing_handler.h @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_STOP_SYNCING_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_STOP_SYNCING_HANDLER_H_ + +#include "chrome/browser/ui/webui/options2/options_ui.h" + +// Chrome personal stuff stop syncing overlay UI handler. +class StopSyncingHandler : public OptionsPage2UIHandler { + public: + StopSyncingHandler(); + virtual ~StopSyncingHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + + // WebUIMessageHandler implementation. + virtual void RegisterMessages() OVERRIDE; + + private: + void StopSyncing(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(StopSyncingHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_STOP_SYNCING_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options2/web_intents_settings_handler.cc b/chrome/browser/ui/webui/options2/web_intents_settings_handler.cc new file mode 100644 index 0000000..874cf834 --- /dev/null +++ b/chrome/browser/ui/webui/options2/web_intents_settings_handler.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/ui/webui/options2/web_intents_settings_handler.h" + +#include "base/bind.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browsing_data_appcache_helper.h" +#include "chrome/browser/browsing_data_database_helper.h" +#include "chrome/browser/browsing_data_file_system_helper.h" +#include "chrome/browser/browsing_data_indexed_db_helper.h" +#include "chrome/browser/browsing_data_local_storage_helper.h" +#include "chrome/browser/intents/web_intents_registry.h" +#include "chrome/browser/intents/web_intents_registry_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/webdata/web_data_service.h" +#include "content/browser/webui/web_ui.h" +#include "grit/generated_resources.h" +#include "net/url_request/url_request_context_getter.h" +#include "ui/base/l10n/l10n_util.h" + +WebIntentsSettingsHandler::WebIntentsSettingsHandler() + : web_intents_registry_(NULL), + batch_update_(false) { +} + +WebIntentsSettingsHandler::~WebIntentsSettingsHandler() { +} + +void WebIntentsSettingsHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + static OptionsStringResource resources[] = { + { "intentsDomain", IDS_INTENTS_DOMAIN_COLUMN_HEADER }, + { "intentsServiceData", IDS_INTENTS_SERVICE_DATA_COLUMN_HEADER }, + { "manageIntents", IDS_INTENTS_MANAGE_BUTTON }, + { "removeIntent", IDS_INTENTS_REMOVE_INTENT_BUTTON }, + }; + + RegisterStrings(localized_strings, resources, arraysize(resources)); + RegisterTitle(localized_strings, "intentsViewPage", + IDS_INTENTS_MANAGER_WINDOW_TITLE); +} + +void WebIntentsSettingsHandler::RegisterMessages() { + web_ui_->RegisterMessageCallback("removeIntent", + base::Bind(&WebIntentsSettingsHandler::RemoveIntent, + base::Unretained(this))); + web_ui_->RegisterMessageCallback("loadIntents", + base::Bind(&WebIntentsSettingsHandler::LoadChildren, + base::Unretained(this))); +} + +void WebIntentsSettingsHandler::TreeNodesAdded(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) { + SendChildren(intents_tree_model_->GetRoot()); +} + +void WebIntentsSettingsHandler::TreeNodesRemoved(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) { + SendChildren(intents_tree_model_->GetRoot()); +} + +void WebIntentsSettingsHandler::TreeModelBeginBatch(WebIntentsModel* model) { + batch_update_ = true; +} + +void WebIntentsSettingsHandler::TreeModelEndBatch(WebIntentsModel* model) { + batch_update_ = false; + + SendChildren(intents_tree_model_->GetRoot()); +} + +void WebIntentsSettingsHandler::EnsureWebIntentsModelCreated() { + if (intents_tree_model_.get()) return; + + Profile* profile = Profile::FromWebUI(web_ui_); + web_intents_registry_ = WebIntentsRegistryFactory::GetForProfile(profile); + intents_tree_model_.reset(new WebIntentsModel(web_intents_registry_)); + intents_tree_model_->AddWebIntentsTreeObserver(this); +} + +void WebIntentsSettingsHandler::RemoveIntent(const base::ListValue* args) { + std::string node_path; + if (!args->GetString(0, &node_path)) { + return; + } + + EnsureWebIntentsModelCreated(); + + WebIntentsTreeNode* node = intents_tree_model_->GetTreeNode(node_path); + if (node->Type() == WebIntentsTreeNode::TYPE_ORIGIN) { + RemoveOrigin(node); + } else if (node->Type() == WebIntentsTreeNode::TYPE_SERVICE) { + ServiceTreeNode* snode = static_cast<ServiceTreeNode*>(node); + RemoveService(snode); + } +} + +void WebIntentsSettingsHandler::RemoveOrigin(WebIntentsTreeNode* node) { + // TODO(gbillock): This is a known batch update. Worth optimizing? + while (!node->empty()) { + WebIntentsTreeNode* cnode = node->GetChild(0); + CHECK(cnode->Type() == WebIntentsTreeNode::TYPE_SERVICE); + ServiceTreeNode* snode = static_cast<ServiceTreeNode*>(cnode); + RemoveService(snode); + } + delete intents_tree_model_->Remove(node->parent(), node); +} + +void WebIntentsSettingsHandler::RemoveService(ServiceTreeNode* snode) { + webkit_glue::WebIntentServiceData service; + service.service_url = GURL(snode->ServiceUrl()); + service.action = snode->Action(); + string16 stype; + if (snode->Types().GetString(0, &stype)) { + service.type = stype; // Really need to iterate here. + } + service.title = snode->ServiceName(); + web_intents_registry_->UnregisterIntentProvider(service); + delete intents_tree_model_->Remove(snode->parent(), snode); +} + +void WebIntentsSettingsHandler::LoadChildren(const base::ListValue* args) { + EnsureWebIntentsModelCreated(); + + std::string node_path; + if (!args->GetString(0, &node_path)) { + SendChildren(intents_tree_model_->GetRoot()); + return; + } + + WebIntentsTreeNode* node = intents_tree_model_->GetTreeNode(node_path); + SendChildren(node); +} + +void WebIntentsSettingsHandler::SendChildren(WebIntentsTreeNode* parent) { + // Early bailout during batch updates. We'll get one after the batch concludes + // with batch_update_ set false. + if (batch_update_) return; + + ListValue* children = new ListValue; + intents_tree_model_->GetChildNodeList(parent, 0, parent->child_count(), + children); + + ListValue args; + args.Append(parent == intents_tree_model_->GetRoot() ? + Value::CreateNullValue() : + Value::CreateStringValue(intents_tree_model_->GetTreeNodeId(parent))); + args.Append(children); + + web_ui_->CallJavascriptFunction("IntentsView.loadChildren", args); +} diff --git a/chrome/browser/ui/webui/options2/web_intents_settings_handler.h b/chrome/browser/ui/webui/options2/web_intents_settings_handler.h new file mode 100644 index 0000000..6a8edf2 --- /dev/null +++ b/chrome/browser/ui/webui/options2/web_intents_settings_handler.h @@ -0,0 +1,77 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_WEB_INTENTS_SETTINGS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS2_WEB_INTENTS_SETTINGS_HANDLER_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/intents/web_intents_model.h" +#include "chrome/browser/ui/webui/options2/options_ui.h" + +class WebIntentsRegistry; + +// Manage setting up the backing data for the web intents options page. +class WebIntentsSettingsHandler : public OptionsPage2UIHandler, + public WebIntentsModel::Observer { + public: + WebIntentsSettingsHandler(); + virtual ~WebIntentsSettingsHandler(); + + // OptionsPage2UIHandler implementation. + virtual void GetLocalizedValues( + base::DictionaryValue* localized_strings) OVERRIDE; + virtual void RegisterMessages() OVERRIDE; + + // WebIntentsModel::Observer implementation. + virtual void TreeNodesAdded(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) OVERRIDE; + virtual void TreeNodesRemoved(ui::TreeModel* model, + ui::TreeModelNode* parent, + int start, + int count) OVERRIDE; + virtual void TreeNodeChanged(ui::TreeModel* model, + ui::TreeModelNode* node) OVERRIDE {} + virtual void TreeModelBeginBatch(WebIntentsModel* model) OVERRIDE; + virtual void TreeModelEndBatch(WebIntentsModel* model) OVERRIDE; + + private: + // Creates the WebIntentsModel if neccessary. + void EnsureWebIntentsModelCreated(); + + // Updates search filter for cookies tree model. + void UpdateSearchResults(const base::ListValue* args); + + // Remove all sites data. + void RemoveAll(const base::ListValue* args); + + // Remove selected sites data. + void RemoveIntent(const base::ListValue* args); + + // Helper functions for removals. + void RemoveOrigin(WebIntentsTreeNode* node); + void RemoveService(ServiceTreeNode* snode); + + // Trigger for SendChildren to load the JS model. + void LoadChildren(const base::ListValue* args); + + // Get children nodes data and pass it to 'IntentsView.loadChildren' to + // update the WebUI. + void SendChildren(WebIntentsTreeNode* parent); + + WebIntentsRegistry* web_intents_registry_; // Weak pointer. + + // Backing data model for the intents list. + scoped_ptr<WebIntentsModel> intents_tree_model_; + + // Flag to indicate whether there is a batch update in progress. + bool batch_update_; + + DISALLOW_COPY_AND_ASSIGN(WebIntentsSettingsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS2_WEB_INTENTS_SETTINGS_HANDLER_H_ |
