diff options
-rw-r--r-- | chrome/browser/browser.cc | 27 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros_settings.h | 2 | ||||
-rw-r--r-- | chrome/browser/dom_ui/app_launcher_handler.cc | 58 | ||||
-rw-r--r-- | chrome/browser/dom_ui/app_launcher_handler.h | 17 | ||||
-rw-r--r-- | chrome/browser/dom_ui/ntp_resource_cache.cc | 14 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.cc | 96 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.h | 34 | ||||
-rw-r--r-- | chrome/browser/prefs/pref_notifier.h | 2 | ||||
-rw-r--r-- | chrome/browser/prefs/pref_service.h | 6 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.html | 10 | ||||
-rw-r--r-- | chrome/browser/resources/ntp/apps.js | 51 | ||||
-rw-r--r-- | chrome/browser/resources/shared/css/menu.css | 17 | ||||
-rw-r--r-- | chrome/browser/resources/shared/js/cr/ui/command.js | 6 | ||||
-rw-r--r-- | chrome/browser/resources/shared/js/cr/ui/menu_item.js | 11 | ||||
-rwxr-xr-x | tools/grit/grit/format/html_inline.py | 16 |
15 files changed, 307 insertions, 60 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 1d2c82f..13bfbc1 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -47,6 +47,7 @@ #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" #include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/find_bar.h" @@ -556,16 +557,28 @@ TabContents* Browser::OpenApplicationTab(Profile* profile, Extension* extension, Browser** browser) { Browser* local_browser = BrowserList::GetLastActiveWithProfile(profile); + TabContents* tab_contents = NULL; if (!local_browser || local_browser->type() != Browser::TYPE_NORMAL) - return NULL; + return tab_contents; + + // Check the prefs for overridden mode. + ExtensionsService* extensions_service = profile->GetExtensionsService(); + DCHECK(extensions_service); - // TODO(erikkay): This doesn't seem like the right transition in all cases. - PageTransition::Type transition = PageTransition::START_PAGE; + ExtensionPrefs::LaunchType launch_type = + extensions_service->extension_prefs()->GetLaunchType(extension->id()); + int add_type = TabStripModel::ADD_SELECTED; + if (launch_type == ExtensionPrefs::LAUNCH_PINNED) + add_type |= TabStripModel::ADD_PINNED; - return local_browser->AddTabWithURL( - extension->GetFullLaunchURL(), GURL(), transition, -1, - TabStripModel::ADD_PINNED | TabStripModel::ADD_SELECTED, - NULL, "", browser); + // TODO(erikkay): START_PAGE doesn't seem like the right transition in all + // cases. + tab_contents = local_browser->AddTabWithURL(extension->GetFullLaunchURL(), + GURL(), PageTransition::START_PAGE, -1, add_type, NULL, "", browser); + if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN) + local_browser->window()->SetFullscreen(true); + + return tab_contents; } // static diff --git a/chrome/browser/chromeos/cros_settings.h b/chrome/browser/chromeos/cros_settings.h index 596b093..226ec08 100644 --- a/chrome/browser/chromeos/cros_settings.h +++ b/chrome/browser/chromeos/cros_settings.h @@ -62,7 +62,7 @@ class CrosSettings : public NonThreadSafe { bool RemoveSettingsProvider(CrosSettingsProvider* provider); // If the pref at the given path changes, we call the observer's Observe - // method with NOTIFY_PREF_CHANGED. + // method with PREF_CHANGED. void AddSettingsObserver(const char* path, NotificationObserver* obs); void RemoveSettingsObserver(const char* path, NotificationObserver* obs); diff --git a/chrome/browser/dom_ui/app_launcher_handler.cc b/chrome/browser/dom_ui/app_launcher_handler.cc index d85c2c5..9c867d1 100644 --- a/chrome/browser/dom_ui/app_launcher_handler.cc +++ b/chrome/browser/dom_ui/app_launcher_handler.cc @@ -12,6 +12,7 @@ #include "chrome/browser/app_launched_animation.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/tab_contents/tab_contents.h" @@ -68,6 +69,8 @@ void AppLauncherHandler::RegisterMessages() { NewCallback(this, &AppLauncherHandler::HandleGetApps)); dom_ui_->RegisterMessageCallback("launchApp", NewCallback(this, &AppLauncherHandler::HandleLaunchApp)); + dom_ui_->RegisterMessageCallback("setLaunchType", + NewCallback(this, &AppLauncherHandler::HandleSetLaunchType)); dom_ui_->RegisterMessageCallback("uninstallApp", NewCallback(this, &AppLauncherHandler::HandleUninstallApp)); } @@ -81,7 +84,15 @@ void AppLauncherHandler::Observe(NotificationType type, if (dom_ui_->tab_contents()) HandleGetApps(NULL); break; + case NotificationType::PREF_CHANGED: { + if (!dom_ui_->tab_contents()) + break; + DictionaryValue dictionary; + FillAppDictionary(&dictionary); + dom_ui_->CallJavascriptFunction(L"appsPrefChangeCallback", dictionary); + break; + } default: NOTREACHED(); } @@ -89,6 +100,7 @@ void AppLauncherHandler::Observe(NotificationType type, // static void AppLauncherHandler::CreateAppInfo(Extension* extension, + ExtensionPrefs* extension_prefs, DictionaryValue* value) { value->Clear(); value->SetString("id", extension->id()); @@ -96,22 +108,18 @@ void AppLauncherHandler::CreateAppInfo(Extension* extension, value->SetString("description", extension->description()); value->SetString("launch_url", extension->GetFullLaunchURL().spec()); value->SetString("options_url", extension->options_url().spec()); - value->SetString("icon_big", GetIconURL( extension, Extension::EXTENSION_ICON_LARGE, "chrome://theme/IDR_APP_DEFAULT_ICON")); value->SetString("icon_small", GetIconURL( extension, Extension::EXTENSION_ICON_BITTY, std::string("chrome://favicon/") + extension->GetFullLaunchURL().spec())); + value->SetInteger("launch_container", extension->launch_container()); + value->SetInteger("launch_type", + extension_prefs->GetLaunchType(extension->id())); } -void AppLauncherHandler::HandleGetApps(const ListValue* args) { - bool show_debug_link = CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAppsDebug); - - DictionaryValue dictionary; - dictionary.SetBoolean("showDebugLink", show_debug_link); - +void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) { ListValue* list = new ListValue(); const ExtensionList* extensions = extensions_service_->extensions(); for (ExtensionList::const_iterator it = extensions->begin(); @@ -120,12 +128,16 @@ void AppLauncherHandler::HandleGetApps(const ListValue* args) { // gets special treatment in ntp/apps.js. if ((*it)->is_app() && (*it)->id() != extension_misc::kWebStoreAppId) { DictionaryValue* app_info = new DictionaryValue(); - CreateAppInfo(*it, app_info); + CreateAppInfo(*it, extensions_service_->extension_prefs(), app_info); list->Append(app_info); } } + dictionary->Set("apps", list); +} - dictionary.Set("apps", list); +void AppLauncherHandler::HandleGetApps(const ListValue* args) { + DictionaryValue dictionary; + FillAppDictionary(&dictionary); dom_ui_->CallJavascriptFunction(L"getAppsCallback", dictionary); // First time we get here we set up the observer so that we can tell update @@ -136,6 +148,11 @@ void AppLauncherHandler::HandleGetApps(const ListValue* args) { registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, NotificationService::AllSources()); } + if (pref_change_registrar_.IsEmpty()) { + pref_change_registrar_.Init( + extensions_service_->extension_prefs()->pref_service()); + pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, this); + } } void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { @@ -165,7 +182,6 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { extensions_service_->GetExtensionById(extension_id, false); DCHECK(extension); Profile* profile = extensions_service_->profile(); - extension_misc::LaunchContainer container = extension->launch_container(); // To give a more "launchy" experience when using the NTP launcher, we close // it automatically. @@ -175,7 +191,7 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { old_contents = browser->GetSelectedTabContents(); AnimateAppIcon(extension, rect); - Browser::OpenApplication(profile, extension, container); + Browser::OpenApplication(profile, extension, extension->launch_container()); if (old_contents && old_contents->GetURL().GetOrigin() == @@ -184,6 +200,24 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { } } +void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) { + std::string extension_id; + int launch_type; + if (!args->GetString(0, &extension_id) || + !ExtractInt(args, 1, &launch_type)) { + NOTREACHED(); + return; + } + + Extension* extension = + extensions_service_->GetExtensionById(extension_id, false); + DCHECK(extension); + + extensions_service_->extension_prefs()->SetLaunchType( + extension_id, + static_cast<ExtensionPrefs::LaunchType>(launch_type)); +} + void AppLauncherHandler::AnimateAppIcon(Extension* extension, const gfx::Rect& rect) { // We make this check for the case of minimized windows, unit tests, etc. diff --git a/chrome/browser/dom_ui/app_launcher_handler.h b/chrome/browser/dom_ui/app_launcher_handler.h index ac29dfb..23c1753 100644 --- a/chrome/browser/dom_ui/app_launcher_handler.h +++ b/chrome/browser/dom_ui/app_launcher_handler.h @@ -9,11 +9,15 @@ #include "base/scoped_ptr.h" #include "chrome/browser/dom_ui/dom_ui.h" #include "chrome/browser/extensions/extension_install_ui.h" +#include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" class Extension; +class ExtensionPrefs; class ExtensionsService; +class NotificationRegistrar; +class PrefChangeRegistrar; namespace gfx { class Rect; @@ -38,7 +42,12 @@ class AppLauncherHandler const NotificationDetails& details); // Populate a dictionary with the information from an extension. - static void CreateAppInfo(Extension* extension, DictionaryValue* value); + static void CreateAppInfo(Extension* extension, + ExtensionPrefs* extension_prefs, + DictionaryValue* value); + + // Populate the given dictionary with all installed app info. + void FillAppDictionary(DictionaryValue* value); // Callback for the "getApps" message. void HandleGetApps(const ListValue* args); @@ -46,6 +55,9 @@ class AppLauncherHandler // Callback for the "launchApp" message. void HandleLaunchApp(const ListValue* args); + // Callback for the "setLaunchType" message. + void HandleSetLaunchType(const ListValue* args); + // Callback for the "uninstallApp" message. void HandleUninstallApp(const ListValue* args); @@ -69,6 +81,9 @@ class AppLauncherHandler // when necessary. NotificationRegistrar registrar_; + // Monitor extension preference changes so that the DOM UI can be notified. + PrefChangeRegistrar pref_change_registrar_; + // Used to show confirmation UI for uninstalling/enabling extensions in // incognito mode. scoped_ptr<ExtensionInstallUI> install_ui_; diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc index bd7ff37..377d3eb 100644 --- a/chrome/browser/dom_ui/ntp_resource_cache.cc +++ b/chrome/browser/dom_ui/ntp_resource_cache.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -268,11 +268,11 @@ void NTPResourceCache::CreateNewTabHTML() { l10n_util::GetStringUTF16(IDS_NEW_TAB_TIPS)); localized_strings.SetString("close", l10n_util::GetStringUTF16(IDS_CLOSE)); localized_strings.SetString("history", - l10n_util::GetStringUTF16(IDS_NEW_TAB_HISTORY)); + l10n_util::GetStringUTF16(IDS_NEW_TAB_HISTORY)); localized_strings.SetString("downloads", - l10n_util::GetStringUTF16(IDS_NEW_TAB_DOWNLOADS)); + l10n_util::GetStringUTF16(IDS_NEW_TAB_DOWNLOADS)); localized_strings.SetString("help", - l10n_util::GetStringUTF16(IDS_NEW_TAB_HELP)); + l10n_util::GetStringUTF16(IDS_NEW_TAB_HELP)); localized_strings.SetString("helpurl", GetUrlWithLang(GURL(kHelpContentUrl))); localized_strings.SetString("appsettings", @@ -281,6 +281,12 @@ void NTPResourceCache::CreateNewTabHTML() { l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_UNINSTALL)); localized_strings.SetString("appoptions", l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_OPTIONS)); + localized_strings.SetString("applaunchtypepinned", + l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_PINNED)); + localized_strings.SetString("applaunchtyperegular", + l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_REGULAR)); + localized_strings.SetString("applaunchtypefullscreen", + l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN)); localized_strings.SetString("web_store_title", l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); localized_strings.SetString("web_store_url", diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index 058ede3..3fbea88 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -14,11 +14,7 @@ using base::Time; namespace { -// Preferences keys - -// A preference that keeps track of per-extension settings. This is a dictionary -// object read from the Preferences file, keyed off of extension id's. -const char kExtensionsPref[] = "extensions.settings"; +// Additional preferences keys // Where an extension was installed from. (see Extension::Location) const char kPrefLocation[] = "location"; @@ -79,6 +75,10 @@ const char kPrefAllowFileAccess[] = "allowFileAccess"; // purchased apps. const char kWebStoreLogin[] = "extensions.webstore_login"; +// A preference set by the the NTP to persist the desired launch container type +// used for apps. +const char kPrefLaunchType[] = "launchType"; + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -90,7 +90,8 @@ namespace { // id. We can remove this in a couple of months. (See http://crbug.com/40017 // and http://crbug.com/39745 for more details). static void CleanupBadExtensionKeys(PrefService* prefs) { - DictionaryValue* dictionary = prefs->GetMutableDictionary(kExtensionsPref); + DictionaryValue* dictionary = + prefs->GetMutableDictionary(ExtensionPrefs::kExtensionsPref); std::set<std::string> bad_keys; for (DictionaryValue::key_iterator i = dictionary->begin_keys(); i != dictionary->end_keys(); ++i) { @@ -121,6 +122,9 @@ ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir) MakePathsRelative(); } +// static +const char ExtensionPrefs::kExtensionsPref[] = "extensions.settings"; + static FilePath::StringType MakePathRelative(const FilePath& parent, const FilePath& child, bool *dirty) { @@ -164,7 +168,7 @@ void ExtensionPrefs::MakePathsRelative() { } } if (dirty) - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } void ExtensionPrefs::MakePathsAbsolute(DictionaryValue* dict) { @@ -233,6 +237,36 @@ bool ExtensionPrefs::ReadExtensionPrefBoolean( return ReadBooleanFromPref(ext, pref_key); } +bool ExtensionPrefs::ReadIntegerFromPref( + DictionaryValue* ext, const std::string& pref_key, int* out_value) { + if (!ext->HasKey(pref_key)) return false; + if (!ext->GetInteger(pref_key, out_value)) { + NOTREACHED() << "Failed to fetch " << pref_key << " flag."; + // In case we could not fetch the flag, we treat it as false. + return false; + } + return out_value != NULL; +} + +bool ExtensionPrefs::ReadExtensionPrefInteger( + const std::string& extension_id, const std::string& pref_key, + int* out_value) { + const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); + if (!extensions) + return false; + DictionaryValue* ext = NULL; + if (!extensions->GetDictionary(extension_id, &ext)) { + // No such extension yet. + return false; + } + return ReadIntegerFromPref(ext, pref_key, out_value); +} + +void ExtensionPrefs::SavePrefsAndNotify() { + prefs_->ScheduleSavePersistentPrefs(); + prefs_->pref_notifier()->OnUserPreferenceSet(kExtensionsPref); +} + bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) { return ReadBooleanFromPref(ext, kPrefBlacklist); } @@ -289,7 +323,7 @@ void ExtensionPrefs::SetDidExtensionEscalatePermissions( Extension* extension, bool did_escalate) { UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions, Value::CreateBooleanValue(did_escalate)); - prefs_->SavePersistentPrefs(); + prefs_->ScheduleSavePersistentPrefs(); } void ExtensionPrefs::UpdateBlacklist( @@ -343,8 +377,7 @@ void ExtensionPrefs::UpdateBlacklist( for (unsigned int i = 0; i < remove_pref_ids.size(); ++i) { DeleteExtensionPrefs(remove_pref_ids[i]); } - // Update persistent registry - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); return; } @@ -368,7 +401,7 @@ void ExtensionPrefs::SetLastPingDayImpl(const Time& time, } std::string value = base::Int64ToString(time.ToInternalValue()); dictionary->SetString(kLastPingDay, value); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const { @@ -399,7 +432,7 @@ void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id, bool enabled) { UpdateExtensionPref(extension_id, kPrefIncognitoEnabled, Value::CreateBooleanValue(enabled)); - prefs_->SavePersistentPrefs(); + SavePrefsAndNotify(); } bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) { @@ -410,7 +443,26 @@ void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id, bool allow) { UpdateExtensionPref(extension_id, kPrefAllowFileAccess, Value::CreateBooleanValue(allow)); - prefs_->SavePersistentPrefs(); + SavePrefsAndNotify(); +} + +ExtensionPrefs::LaunchType ExtensionPrefs::GetLaunchType( + const std::string& extension_id) { + int value; + if (ReadExtensionPrefInteger(extension_id, kPrefLaunchType, &value) && ( + value == LAUNCH_PINNED || + value == LAUNCH_REGULAR || + value == LAUNCH_FULLSCREEN)) { + return static_cast<LaunchType>(value); + } + return LAUNCH_PINNED; +} + +void ExtensionPrefs::SetLaunchType(const std::string& extension_id, + LaunchType launch_type) { + UpdateExtensionPref(extension_id, kPrefLaunchType, + Value::CreateIntegerValue(static_cast<int>(launch_type))); + SavePrefsAndNotify(); } void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) { @@ -462,7 +514,7 @@ void ExtensionPrefs::SetToolbarOrder( iter != extension_ids.end(); ++iter) { toolbar_order->Append(new StringValue(*iter)); } - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } void ExtensionPrefs::OnExtensionInstalled( @@ -484,7 +536,7 @@ void ExtensionPrefs::OnExtensionInstalled( UpdateExtensionPref(id, kPrefManifest, extension->manifest_value()->DeepCopy()); } - prefs_->SavePersistentPrefs(); + SavePrefsAndNotify(); } void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id, @@ -497,7 +549,7 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id, if (!external_uninstall && Extension::IsExternalLocation(location)) { UpdateExtensionPref(extension_id, kPrefState, Value::CreateIntegerValue(Extension::KILLBIT)); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } else { DeleteExtensionPrefs(extension_id); } @@ -525,7 +577,7 @@ void ExtensionPrefs::SetExtensionState(Extension* extension, Extension::State state) { UpdateExtensionPref(extension->id(), kPrefState, Value::CreateIntegerValue(state)); - prefs_->SavePersistentPrefs(); + SavePrefsAndNotify(); } std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) { @@ -546,7 +598,7 @@ void ExtensionPrefs::UpdateManifest(Extension* extension) { if (extension->location() != Extension::LOAD) { UpdateExtensionPref(extension->id(), kPrefManifest, extension->manifest_value()->DeepCopy()); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } } @@ -577,7 +629,7 @@ void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) { DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref); if (dict->HasKey(extension_id)) { dict->Remove(extension_id, NULL); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } } @@ -717,7 +769,7 @@ void ExtensionPrefs::SetIdleInstallInfo(const std::string& extension_id, info->SetString(kIdleInstallInfoFetchTime, base::Int64ToString(fetch_time.ToInternalValue())); extension_prefs->Set(kIdleInstallInfo, info); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) { @@ -725,7 +777,7 @@ bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) { if (!extension_prefs) return false; bool result = extension_prefs->Remove(kIdleInstallInfo, NULL); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); return result; } @@ -807,7 +859,7 @@ bool ExtensionPrefs::GetWebStoreLogin(std::string* result) { void ExtensionPrefs::SetWebStoreLogin(const std::string& login) { prefs_->SetString(kWebStoreLogin, login); - prefs_->ScheduleSavePersistentPrefs(); + SavePrefsAndNotify(); } // static diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index d753e08..01226cd 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -21,8 +21,21 @@ // from there. class ExtensionPrefs { public: + // Key name for a preference that keeps track of per-extension settings. This + // is a dictionary object read from the Preferences file, keyed off of + // extension ids. + static const char kExtensionsPref[]; + typedef std::vector<linked_ptr<ExtensionInfo> > ExtensionsInfo; + // This enum is used for the launch type the user wants to use for an + // application. + enum LaunchType { + LAUNCH_PINNED, + LAUNCH_REGULAR, + LAUNCH_FULLSCREEN + }; + explicit ExtensionPrefs(PrefService* prefs, const FilePath& root_dir_); // Returns a copy of the Extensions prefs. @@ -116,6 +129,9 @@ class ExtensionPrefs { bool AllowFileAccess(const std::string& extension_id); void SetAllowFileAccess(const std::string& extension_id, bool allow); + ExtensionPrefs::LaunchType GetLaunchType(const std::string& extension_id); + void SetLaunchType(const std::string& extension_id, LaunchType launch_type); + // Saves ExtensionInfo for each installed extension with the path to the // version directory and the location. Blacklisted extensions won't be saved // and neither will external extensions the user has explicitly uninstalled. @@ -185,12 +201,30 @@ class ExtensionPrefs { bool ReadExtensionPrefBoolean(const std::string& extension_id, const std::string& pref_key); + // Reads an integer pref from |ext| with key |pref_key|. + // Return false if the value does not exist. + bool ReadIntegerFromPref(DictionaryValue* ext, const std::string& pref_key, + int* out_value); + + // Reads an integer pref |pref_key| from extension with id |extension_id|. + bool ReadExtensionPrefInteger(const std::string& extension_id, + const std::string& pref_key, + int* out_value); + // Ensures and returns a mutable dictionary for extension |id|'s prefs. DictionaryValue* GetOrCreateExtensionPref(const std::string& id); // Same as above, but returns NULL if it doesn't exist. DictionaryValue* GetExtensionPref(const std::string& id) const; + // Serializes the data and schedules a persistent save via the |PrefService|. + // Additionally fires a PREF_CHANGED notification with the top-level + // |kExtensionsPref| path set. + // TODO(andybons): Switch this to EXTENSION_PREF_CHANGED to be more granular. + // TODO(andybons): Use a ScopedPrefUpdate to update observers on changes to + // the mutable extension dictionary. + void SavePrefsAndNotify(); + // Checks if kPrefBlacklist is set to true in the DictionaryValue. // Return false if the value is false or kPrefBlacklist does not exist. // This is used to decide if an extension is blacklisted. diff --git a/chrome/browser/prefs/pref_notifier.h b/chrome/browser/prefs/pref_notifier.h index d981310..98dc1e3 100644 --- a/chrome/browser/prefs/pref_notifier.h +++ b/chrome/browser/prefs/pref_notifier.h @@ -71,7 +71,7 @@ class PrefNotifier : public NonThreadSafe, virtual void FireObservers(const char* path); // If the pref at the given path changes, we call the observer's Observe - // method with NOTIFY_PREF_CHANGED. + // method with PREF_CHANGED. void AddPrefObserver(const char* path, NotificationObserver* obs); void RemovePrefObserver(const char* path, NotificationObserver* obs); diff --git a/chrome/browser/prefs/pref_service.h b/chrome/browser/prefs/pref_service.h index 5cedd52..3e90db6 100644 --- a/chrome/browser/prefs/pref_service.h +++ b/chrome/browser/prefs/pref_service.h @@ -239,9 +239,9 @@ class PrefService : public NonThreadSafe { friend class subtle::PrefMemberBase; // If the pref at the given path changes, we call the observer's Observe - // method with NOTIFY_PREF_CHANGED. Note that observers should not call - // these methods directly but rather use a PrefChangeRegistrar to make sure - // the observer gets cleaned up properly. + // method with PREF_CHANGED. Note that observers should not call these methods + // directly but rather use a PrefChangeRegistrar to make sure the observer + // gets cleaned up properly. virtual void AddPrefObserver(const char* path, NotificationObserver* obs); virtual void RemovePrefObserver(const char* path, NotificationObserver* obs); diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html index 23e8e24..7290e32 100644 --- a/chrome/browser/resources/new_new_tab.html +++ b/chrome/browser/resources/new_new_tab.html @@ -176,10 +176,20 @@ if ('mode' in hashParams) { <command id="apps-launch-command"> <command id="apps-options-command" i18n-values=".label:appoptions"> <command id="apps-uninstall-command" i18n-values=".label:appuninstall"> +<command id="apps-launch-type-pinned" i18n-values=".label:applaunchtypepinned" + launch-type="0"> +<command id="apps-launch-type-regular" i18n-values=".label:applaunchtyperegular" + launch-type="1"> +<command id="apps-launch-type-fullscreen" + i18n-values=".label:applaunchtypefullscreen" launch-type="2"> <menu id="app-context-menu"> <button class="default" command="#apps-launch-command"></button> <hr> + <button command="#apps-launch-type-pinned" launch-type="0"></button> + <button command="#apps-launch-type-regular" launch-type="1"></button> + <button command="#apps-launch-type-fullscreen" launch-type="2"></button> + <hr> <button command="#apps-options-command"></button> <button command="#apps-uninstall-command"></button> </menu> diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js index d9098d5..b128f05 100644 --- a/chrome/browser/resources/ntp/apps.js +++ b/chrome/browser/resources/ntp/apps.js @@ -36,6 +36,15 @@ function getAppsCallback(data) { } } +function appsPrefChangeCallback(data) { + // Currently the only pref that is watched is the launch type. + data.apps.forEach(function(app) { + var appLink = document.querySelector('.app a[app-id=' + app['id'] + ']'); + if (appLink) + appLink.setAttribute('launch-type', app['launch_type']); + }); +} + var apps = (function() { function createElement(app) { @@ -44,6 +53,7 @@ var apps = (function() { var a = div.appendChild(document.createElement('a')); a.setAttribute('app-id', app['id']); + a.setAttribute('launch-type', app['launch_type']); a.xtitle = a.textContent = app['name']; a.href = app['launch_url']; @@ -99,6 +109,20 @@ var apps = (function() { return false; } + // Keep in sync with LaunchType in extension_prefs.h + var LaunchType = { + LAUNCH_PINNED: 0, + LAUNCH_REGULAR: 1, + LAUNCH_FULLSCREEN: 2 + }; + + // Keep in sync with LaunchContainer in extension.h + var LaunchContainer = { + LAUNCH_WINDOW: 0, + LAUNCH_PANEL: 1, + LAUNCH_TAB: 2 + }; + var currentApp; function addContextMenu(el, app) { @@ -113,6 +137,24 @@ var apps = (function() { $('apps-launch-command').label = app['name']; $('apps-options-command').canExecuteChange(); + var appLinkSel = '.app a[app-id=' + app['id'] + ']'; + var launchType = + el.querySelector(appLinkSel).getAttribute('launch-type'); + + var launchContainer = app['launch_container']; + var isPanel = launchContainer == LaunchContainer.LAUNCH_PANEL; + + // Update the commands related to the launch type. + var launchTypeIds = ['apps-launch-type-pinned', + 'apps-launch-type-regular', + 'apps-launch-type-fullscreen']; + launchTypeIds.forEach(function(id) { + var command = $(id); + command.disabled = isPanel; + command.checked = !isPanel && + launchType == command.getAttribute('launch-type'); + }); + return $('app-context-menu'); } }); @@ -122,7 +164,8 @@ var apps = (function() { if (!currentApp) return; - switch (e.command.id) { + var commandId = e.command.id; + switch (commandId) { case 'apps-options-command': window.location = currentApp['options_url']; break; @@ -132,6 +175,12 @@ var apps = (function() { case 'apps-uninstall-command': chrome.send('uninstallApp', [currentApp['id']]); break; + case 'apps-launch-type-pinned': + case 'apps-launch-type-regular': + case 'apps-launch-type-fullscreen': + chrome.send('setLaunchType', + [currentApp['id'], e.command.getAttribute('launch-type')]); + break; } }); diff --git a/chrome/browser/resources/shared/css/menu.css b/chrome/browser/resources/shared/css/menu.css index a891a42..19f5248 100644 --- a/chrome/browser/resources/shared/css/menu.css +++ b/chrome/browser/resources/shared/css/menu.css @@ -57,3 +57,20 @@ menu > :not(hr)[selected]:active { background-color: #426dc9; color: #fff; } + +menu > [checked]:before { + content: url("../images/checkbox_black.png"); + width: 9px; + height: 9px; + display: inline-block; + vertical-align: 50%; + margin: 0 5px; +} + +menu > [checked] { + -webkit-padding-start: 0; +} + +menu > [selected][checked]:active:before { + content: url("../images/checkbox_white.png"); +}
\ No newline at end of file diff --git a/chrome/browser/resources/shared/js/cr/ui/command.js b/chrome/browser/resources/shared/js/cr/ui/command.js index 1011398..61294f3 100644 --- a/chrome/browser/resources/shared/js/cr/ui/command.js +++ b/chrome/browser/resources/shared/js/cr/ui/command.js @@ -172,6 +172,12 @@ cr.define('cr.ui', function() { cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR); /** + * Whether the command is checked or not. + * @type {boolean} + */ + cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR); + + /** * Dispatches a canExecute event on the target. * @param {cr.ui.Command} command The command that we are testing for. * @param {Element} target The target element to dispatch the event on. diff --git a/chrome/browser/resources/shared/js/cr/ui/menu_item.js b/chrome/browser/resources/shared/js/cr/ui/menu_item.js index d570f78..c3e3169 100644 --- a/chrome/browser/resources/shared/js/cr/ui/menu_item.js +++ b/chrome/browser/resources/shared/js/cr/ui/menu_item.js @@ -52,6 +52,7 @@ cr.define('cr.ui', function() { this.command_.removeEventListener('labelChange', this); this.command_.removeEventListener('disabledChange', this); this.command_.removeEventListener('hiddenChange', this); + this.command_.removeEventListener('checkedChange', this); } if (typeof command == 'string' && command[0] == '#') { @@ -71,6 +72,7 @@ cr.define('cr.ui', function() { this.command_.addEventListener('labelChange', this); this.command_.addEventListener('disabledChange', this); this.command_.addEventListener('hiddenChange', this); + this.command_.addEventListener('checkedChange', this); } }, @@ -124,6 +126,9 @@ cr.define('cr.ui', function() { case 'labelChange': this.label = this.command.label; break; + case 'checkedChange': + this.checked = this.command.checked; + break; } } }; @@ -146,6 +151,12 @@ cr.define('cr.ui', function() { */ cr.defineProperty(MenuItem, 'selected', cr.PropertyKind.BOOL_ATTR); + /** + * Whether the menu item is checked or not. + * @type {boolean} + */ + cr.defineProperty(MenuItem, 'checked', cr.PropertyKind.BOOL_ATTR); + // Export return { MenuItem: MenuItem diff --git a/tools/grit/grit/format/html_inline.py b/tools/grit/grit/format/html_inline.py index b23f951..71d0f68 100755 --- a/tools/grit/grit/format/html_inline.py +++ b/tools/grit/grit/format/html_inline.py @@ -136,12 +136,12 @@ def InlineFile(input_filename, output_filename, grd_node): """Helper function to inline external script files""" return InlineFileContents(src_match, '<script>%s</script>') - def InlineCssText(text, css_filepath): + def InlineCSSText(text, css_filepath): """Helper function that inlines external resources in CSS text""" filepath = os.path.dirname(css_filepath) - return InlineCssBackgroundImages(text, filepath) + return InlineCSSImages(text, filepath) - def InlineCssFile(src_match, inlined_files=inlined_files): + def InlineCSSFile(src_match, inlined_files=inlined_files): """Helper function to inline external css files. Args: @@ -157,11 +157,11 @@ def InlineFile(input_filename, output_filename, grd_node): inlined_files.add(filepath) # When resolving CSS files we need to pass in the path so that relative URLs # can be resolved. - return '<style>%s</style>' % InlineCssText(ReadFile(filepath), filepath) + return '<style>%s</style>' % InlineCSSText(ReadFile(filepath), filepath) - def InlineCssBackgroundImages(text, filepath=input_filepath): + def InlineCSSImages(text, filepath=input_filepath): """Helper function that inlines external images in CSS backgrounds.""" - return re.sub('background(?:-image)?:[ ]*url\((?:\'|\")' + + return re.sub('(?:content|background(?:-image)?):[ ]*url\((?:\'|\")' + '(?P<filename>[^"\'\)\(]*)(?:\'|\")', lambda m: SrcReplace(m, filepath), text) @@ -174,7 +174,7 @@ def InlineFile(input_filename, output_filename, grd_node): flat_text = re.sub( '<link rel="stylesheet".+?href="(?P<filename>[^"\']*)".*?>', - InlineCssFile, + InlineCSSFile, flat_text) flat_text = re.sub( @@ -194,7 +194,7 @@ def InlineFile(input_filename, output_filename, grd_node): flat_text) # TODO(arv): Only do this inside <style> tags. - flat_text = InlineCssBackgroundImages(flat_text) + flat_text = InlineCSSImages(flat_text) flat_text = re.sub('<link rel="icon".+?href="(?P<filename>[^"\']*)"', SrcReplace, |