Index: chrome/browser/extensions/extension_prefs.cc |
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc |
index 92412645bc76dc65f1c8531c4d385367bb72c0f3..759593aaeab6d347b2bd1aacad9c04438a00c615 100644 |
--- a/chrome/browser/extensions/extension_prefs.cc |
+++ b/chrome/browser/extensions/extension_prefs.cc |
@@ -110,10 +110,12 @@ const char kWebStoreLogin[] = "extensions.webstore_login"; |
const char kPrefLaunchType[] = "launchType"; |
// A preference determining the order of which the apps appear on the NTP. |
-const char kPrefAppLaunchIndex[] = "app_launcher_index"; |
+const char kPrefAppLaunchIndexDeprecated[] = "app_launcher_index"; |
+const char kPrefAppLaunchIndex[] = "app_launcher_index_string_ordinal"; |
// A preference determining the page on which an app appears in the NTP. |
-const char kPrefPageIndex[] = "page_index"; |
+const char kPrefPageIndexDeprecated[] = "page_index"; |
+const char kPrefPageIndex[] = "page_index_string_ordinal"; |
// A preference specifying if the user dragged the app on the NTP. |
const char kPrefUserDraggedApp[] = "user_dragged_app_ntp"; |
@@ -239,6 +241,30 @@ std::string JoinPrefs(std::string parent, const char* child) { |
return parent + "." + child; |
} |
+// A simple structure used when sorting extension based on the order they |
Finnur
2011/11/17 14:59:25
extension -> apps?
csharp
2011/11/17 19:51:58
Done.
|
+// appear on the NTP. This is used by the code that migrates the data |
+// from integers to StringOrdinals. |
+struct ExtensionNTPOldPosition { |
+ const std::string* extension_id; |
+ const int page_index; |
+ const int app_launch_index; |
+ |
+ ExtensionNTPOldPosition(const std::string& ext_id, int page, int app_launch) |
+ : extension_id(&ext_id), |
+ page_index(page), |
+ app_launch_index(app_launch) {} |
+}; |
+ |
+struct SortByNTPOldPosition { |
+ bool operator() (const ExtensionNTPOldPosition& lhs, |
+ const ExtensionNTPOldPosition& rhs) const { |
+ if (lhs.page_index != rhs.page_index) |
+ return lhs.page_index < rhs.page_index; |
+ |
+ return lhs.app_launch_index < rhs.app_launch_index; |
+ } |
+}; |
+ |
} // namespace |
ExtensionPrefs::ExtensionPrefs( |
@@ -415,6 +441,17 @@ bool ExtensionPrefs::ReadExtensionPrefList( |
return true; |
} |
+bool ExtensionPrefs::ReadExtensionPrefString( |
+ const std::string& extension_id, const std::string& pref_key, |
+ std::string* out_value) const { |
+ const DictionaryValue* ext = GetExtensionPref(extension_id); |
+ |
+ if (!ext || !ext->GetString(pref_key, out_value)) |
+ return false; |
+ |
+ return true; |
+} |
+ |
bool ExtensionPrefs::ReadExtensionPrefURLPatternSet( |
const std::string& extension_id, |
const std::string& pref_key, |
@@ -858,6 +895,63 @@ void ExtensionPrefs::MigratePermissions(const ExtensionIdSet& extension_ids) { |
} |
} |
+void ExtensionPrefs::MigrateAppIndex(const ExtensionIdSet& extension_ids) { |
+ if (extension_ids.begin() == extension_ids.end()) { |
+ return; |
+ } |
Finnur
2011/11/17 14:59:25
No braces for single line if clauses.
csharp
2011/11/17 19:51:58
Done.
|
+ |
+ // Create a sorted set of all the extensions that need either their page |
+ // or launch index converted. |
+ std::set<ExtensionNTPOldPosition, SortByNTPOldPosition> apps_to_convert; |
+ for (ExtensionIdSet::const_iterator ext_id = extension_ids.begin(); |
+ ext_id != extension_ids.end(); ++ext_id) { |
+ int old_page_index(0); |
+ int old_app_launch_index(0); |
Finnur
2011/11/17 14:59:25
nit: Even though you can, we never initialize ints
csharp
2011/11/17 19:51:58
Done.
|
+ |
+ bool has_old_values = ReadExtensionPrefInteger(*ext_id, |
+ kPrefPageIndexDeprecated, |
+ &old_page_index); |
+ has_old_values |= ReadExtensionPrefInteger(*ext_id, |
+ kPrefAppLaunchIndexDeprecated, |
+ &old_app_launch_index); |
+ |
+ if (has_old_values) { |
+ // Its ok to use both values, even if they weren't read, because this |
+ // only affects the sorting, which can handle apps with the default |
+ // integer values. |
+ apps_to_convert.insert(ExtensionNTPOldPosition( |
+ *ext_id, old_page_index, old_app_launch_index)); |
+ } |
+ } |
+ |
+ if (apps_to_convert.empty()) |
+ return; |
+ |
+ // Create the new values and remove the old preferences. |
+ for (std::set<ExtensionNTPOldPosition, SortByNTPOldPosition>::iterator ext = |
+ apps_to_convert.begin(); ext != apps_to_convert.end(); ++ext) { |
+ int old_page_index; |
+ if (ReadExtensionPrefInteger(*(ext->extension_id), |
+ kPrefPageIndexDeprecated, |
+ &old_page_index)) { |
+ SetPageIndex(*(ext->extension_id), |
+ PageIndexAsStringOrdinal(old_page_index)); |
+ UpdateExtensionPref(*(ext->extension_id), kPrefPageIndexDeprecated, NULL); |
+ } |
+ |
+ int old_app_launch_index; |
+ if (ReadExtensionPrefInteger(*(ext->extension_id), |
+ kPrefAppLaunchIndexDeprecated, |
+ &old_app_launch_index)) { |
Finnur
2011/11/17 14:59:25
old_page_index is read and used above.
old_app_lau
csharp
2011/11/17 19:51:58
I don't think the order can change, because set th
|
+ StringOrdinal page = GetPageIndex(*(ext->extension_id)); |
+ SetAppLaunchIndex(*(ext->extension_id), |
+ GetNextAppLaunchIndex(page)); |
+ UpdateExtensionPref( |
+ *(ext->extension_id), kPrefAppLaunchIndexDeprecated, NULL); |
+ } |
+ } |
+} |
+ |
ExtensionPermissionSet* ExtensionPrefs::GetGrantedPermissions( |
const std::string& extension_id) { |
CHECK(Extension::IdIsValid(extension_id)); |
@@ -1072,7 +1166,7 @@ void ExtensionPrefs::OnExtensionInstalled( |
const Extension* extension, |
Extension::State initial_state, |
bool from_webstore, |
- int page_index) { |
+ StringOrdinal page_index) { |
const std::string& id = extension->id(); |
CHECK(Extension::IdIsValid(id)); |
ScopedExtensionPrefUpdate update(prefs_, id); |
@@ -1104,12 +1198,15 @@ void ExtensionPrefs::OnExtensionInstalled( |
} |
if (extension->is_app()) { |
- if (page_index == -1) |
+ if (!page_index.IsValid()) |
page_index = GetNaturalAppPageIndex(); |
extension_dict->Set(kPrefPageIndex, |
- Value::CreateIntegerValue(page_index)); |
+ Value::CreateStringValue(page_index.ToString())); |
+ UpdatePageIndexMap(StringOrdinal(), page_index); |
+ |
extension_dict->Set(kPrefAppLaunchIndex, |
- Value::CreateIntegerValue(GetNextAppLaunchIndex(page_index))); |
+ Value::CreateStringValue( |
+ GetNextAppLaunchIndex(page_index).ToString())); |
} |
extension_pref_value_map_->RegisterExtension( |
id, install_time, initial_state == Extension::ENABLED); |
@@ -1442,59 +1539,126 @@ void ExtensionPrefs::SetWebStoreLogin(const std::string& login) { |
SavePrefs(); |
} |
-int ExtensionPrefs::GetAppLaunchIndex(const std::string& extension_id) { |
- int value; |
- if (ReadExtensionPrefInteger(extension_id, kPrefAppLaunchIndex, &value)) |
- return value; |
+void ExtensionPrefs::GetAllAppsOnPageSorted( |
Finnur
2011/11/17 14:59:25
This doesn't really get all Apps on the page as mu
csharp
2011/11/17 19:51:58
Correct, function name updated
On 2011/11/17 14:5
|
+ const StringOrdinal& target_page_index, |
+ std::set<StringOrdinal, StringOrdinal::Comparsion>* indexes_on_page) const { |
Finnur
2011/11/17 14:59:25
indexes -> indices?
csharp
2011/11/17 19:51:58
Done.
|
+ const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); |
+ if (!extensions || !target_page_index.IsValid()) |
+ return; |
+ |
+ for (DictionaryValue::key_iterator ext_it = extensions->begin_keys(); |
+ ext_it != extensions->end_keys(); ++ext_it) { |
+ StringOrdinal page_index = GetPageIndex(*ext_it); |
+ if (page_index.IsValid() && page_index.Equal(target_page_index)) { |
+ StringOrdinal app_launch_index = GetAppLaunchIndex(*ext_it); |
+ if (app_launch_index.IsValid()) |
+ indexes_on_page->insert(app_launch_index); |
+ } |
+ } |
+} |
+ |
+StringOrdinal ExtensionPrefs::GetFirstAppPage() const { |
+ const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); |
+ if (!extensions) |
+ return StringOrdinal(); |
+ |
+ if (page_index_map_.size() == 0) |
+ return StringOrdinal::CreateValidOrdinal(); |
+ |
+ return page_index_map_.begin()->first; |
+} |
+ |
+StringOrdinal ExtensionPrefs::CreateFirstAppLaunchIndex( |
+ const StringOrdinal& page_index) const { |
+ std::set<StringOrdinal, StringOrdinal::Comparsion> apps_on_page; |
+ GetAllAppsOnPageSorted(page_index, &apps_on_page); |
- return -1; |
+ if (apps_on_page.empty()) { |
+ return StringOrdinal::CreateValidOrdinal(); |
+ } else { |
+ return apps_on_page.begin()->CreateBefore(); |
+ } |
Finnur
2011/11/17 14:59:25
nit: no braces around single-line clauses.
csharp
2011/11/17 19:51:58
Done.
|
+} |
+ |
+StringOrdinal ExtensionPrefs::GetAppLaunchIndex( |
+ const std::string& extension_id) const { |
+ std::string raw_value; |
+ ReadExtensionPrefString(extension_id, kPrefAppLaunchIndex, &raw_value); |
+ return StringOrdinal(raw_value); |
Finnur
2011/11/17 14:59:25
Is the idea here to return a blank ordinal if the
csharp
2011/11/17 19:51:58
Yes, which is an invalid ordinal which does repres
|
} |
void ExtensionPrefs::SetAppLaunchIndex(const std::string& extension_id, |
- int index) { |
+ const StringOrdinal& index) { |
UpdateExtensionPref(extension_id, kPrefAppLaunchIndex, |
- Value::CreateIntegerValue(index)); |
+ Value::CreateStringValue(index.ToString())); |
} |
-int ExtensionPrefs::GetNextAppLaunchIndex(int on_page) { |
- const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); |
- if (!extensions) |
- return 0; |
+StringOrdinal ExtensionPrefs::GetNextAppLaunchIndex(StringOrdinal on_page) |
+ const { |
+ std::set<StringOrdinal, StringOrdinal::Comparsion> apps_on_page; |
+ GetAllAppsOnPageSorted(on_page, &apps_on_page); |
- int max_value = -1; |
- for (DictionaryValue::key_iterator extension_id = extensions->begin_keys(); |
- extension_id != extensions->end_keys(); ++extension_id) { |
- int value = GetAppLaunchIndex(*extension_id); |
- int page = GetPageIndex(*extension_id); |
- if (page == on_page && value > max_value) |
- max_value = value; |
+ if (apps_on_page.empty()) { |
+ return StringOrdinal::CreateValidOrdinal(); |
+ } else { |
+ return apps_on_page.rbegin()->CreateAfter(); |
} |
- return max_value + 1; |
} |
-int ExtensionPrefs::GetNaturalAppPageIndex() { |
+StringOrdinal ExtensionPrefs::GetNaturalAppPageIndex() const { |
const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); |
if (!extensions) |
- return 0; |
+ return StringOrdinal(); |
- std::map<int, int> page_counts; |
- for (DictionaryValue::key_iterator extension_id = extensions->begin_keys(); |
- extension_id != extensions->end_keys(); ++extension_id) { |
- int page_index = GetPageIndex(*extension_id); |
- if (page_index >= 0) |
- page_counts[page_index] = page_counts[page_index] + 1; |
+ if (page_index_map_.size() == 0) { |
+ return StringOrdinal::CreateValidOrdinal(); |
} |
- for (int i = 0; ; i++) { |
- std::map<int, int>::const_iterator it = page_counts.find(i); |
- if (it == page_counts.end() || it->second < kNaturalAppPageSize) |
- return i; |
+ |
+ std::map<StringOrdinal, int>::const_iterator it = page_index_map_.begin(); |
+ for (; it != page_index_map_.end(); ++it) { |
+ if (it->second < kNaturalAppPageSize) { |
+ return it->first; |
+ } |
Finnur
2011/11/17 14:59:25
same here: no braces (also on line 1613, 1615).
csharp
2011/11/17 19:51:58
Done.
|
} |
+ |
+ // Add a new page as all existing pages are full. |
+ StringOrdinal last_element = page_index_map_.rbegin()->first; |
+ return last_element.CreateAfter(); |
} |
void ExtensionPrefs::SetAppLauncherOrder( |
- const std::vector<std::string>& extension_ids) { |
- for (size_t i = 0; i < extension_ids.size(); ++i) |
- SetAppLaunchIndex(extension_ids.at(i), i); |
+ const std::vector<std::string>& extension_ids, |
+ const std::string& moved_extension_id) { |
+ std::vector<std::string>::const_iterator it = |
+ find(extension_ids.begin(), extension_ids.end(), moved_extension_id); |
+ size_t position = std::distance(extension_ids.begin(), it); |
+ |
+ // We need at least 2 apps for the moved apps old value to be invalidated. |
+ if (extension_ids.size() >= 2) { |
+ if (position == 0U) { |
+ // The app is moving to the start of the group, so we need to get the |
+ // previous first StringOrdinal and create the new value before it. |
+ ++it; |
+ SetAppLaunchIndex(moved_extension_id, |
+ GetAppLaunchIndex(*it).CreateBefore()); |
+ } else if (position == extension_ids.size() - 1U) { |
+ // The app is moving to the end of the group, so we need to get the |
+ // previous last StringOrdinal and create the new value after it. |
+ --it; |
+ SetAppLaunchIndex(moved_extension_id, |
+ GetAppLaunchIndex(*it).CreateAfter()); |
+ } else { |
+ // The app is going into a middle position, which means there are valid |
+ // StringOrdinals before and after it. We get the new adjacent |
+ // StringOrdinals and create our new value between them. |
+ ++it; |
+ StringOrdinal value_after = GetAppLaunchIndex(*it); |
+ advance(it, -2); |
+ StringOrdinal value_before = GetAppLaunchIndex(*it); |
+ SetAppLaunchIndex(moved_extension_id, |
+ value_before.CreateBetween(value_after)); |
+ } |
+ } |
content::NotificationService::current()->Notify( |
chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, |
@@ -1502,21 +1666,84 @@ void ExtensionPrefs::SetAppLauncherOrder( |
content::NotificationService::NoDetails()); |
} |
-int ExtensionPrefs::GetPageIndex(const std::string& extension_id) { |
- int value = -1; |
- ReadExtensionPrefInteger(extension_id, kPrefPageIndex, &value); |
- return value; |
+StringOrdinal ExtensionPrefs::GetPageIndex(const std::string& extension_id) |
+ const { |
+ std::string raw_string_data; |
+ ReadExtensionPrefString(extension_id, kPrefPageIndex, &raw_string_data); |
+ return StringOrdinal(raw_string_data); |
Finnur
2011/11/17 14:59:25
Same here: Is the idea here to return a blank ordi
csharp
2011/11/17 19:51:58
Yes, and comment added to clarify.
On 2011/11/17
|
} |
-void ExtensionPrefs::SetPageIndex(const std::string& extension_id, int index) { |
+void ExtensionPrefs::SetPageIndex(const std::string& extension_id, |
+ const StringOrdinal& page_index) { |
+ UpdatePageIndexMap(GetPageIndex(extension_id), page_index); |
UpdateExtensionPref(extension_id, kPrefPageIndex, |
- Value::CreateIntegerValue(index)); |
+ Value::CreateStringValue(page_index.ToString())); |
} |
void ExtensionPrefs::ClearPageIndex(const std::string& extension_id) { |
+ UpdatePageIndexMap(GetPageIndex(extension_id), StringOrdinal()); |
UpdateExtensionPref(extension_id, kPrefPageIndex, NULL); |
} |
+void ExtensionPrefs::InitializePageIndexMap( |
+ const ExtensionIdSet& extension_ids) { |
+ for (ExtensionIdSet::const_iterator ext_it = extension_ids.begin(); |
+ ext_it != extension_ids.end(); ++ext_it) { |
+ UpdatePageIndexMap(StringOrdinal(), GetPageIndex(*ext_it)); |
Finnur
2011/11/17 14:59:25
Are there cases here where you can end up with {St
csharp
2011/11/17 19:51:58
It is possible, but the map only updates for valid
|
+ } |
+} |
+ |
+void ExtensionPrefs::UpdatePageIndexMap(const StringOrdinal& old_value, |
+ const StringOrdinal& new_value) { |
+ if (new_value.IsValid()) |
+ ++page_index_map_[new_value]; |
+ |
+ if (old_value.IsValid()) { |
+ --page_index_map_[old_value]; |
+ |
+ if (page_index_map_[old_value] == 0) |
+ page_index_map_.erase(old_value); |
+ } |
+} |
+ |
+int ExtensionPrefs::PageIndexAsInteger(const StringOrdinal& page_index) const { |
+ if (!page_index.IsValid()) |
+ return -1; |
+ |
+ std::map<StringOrdinal, int>::const_iterator it = |
+ page_index_map_.find(page_index); |
+ if (it != page_index_map_.end()) { |
+ return std::distance(page_index_map_.begin(), it); |
+ } else { |
+ return -1; |
+ } |
+} |
+ |
+StringOrdinal ExtensionPrefs::PageIndexAsStringOrdinal(size_t page_index) { |
+ const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); |
+ if (!extensions) |
+ return StringOrdinal(); |
+ |
+ if (page_index_map_.size() == 0) { |
+ return StringOrdinal::CreateValidOrdinal(); |
+ } |
Finnur
2011/11/17 14:59:25
nit: You don't need braces, your teeth look fine..
csharp
2011/11/17 19:51:58
Done and :/
Finnur
2011/11/18 09:35:15
Awww... isn't that smile lovely? :)
On 2011/11/17
|
+ |
+ if (page_index < page_index_map_.size()) { |
+ std::map<StringOrdinal, int, StringOrdinal::Comparsion>::const_iterator it = |
+ page_index_map_.begin(); |
+ advance(it, page_index); |
+ |
+ return it->first; |
+ } else { |
+ // Create new pages until we reach the desired index. |
+ while (page_index >= page_index_map_.size()) { |
+ StringOrdinal new_page = page_index_map_.rbegin()->first.CreateAfter(); |
+ page_index_map_[new_page] = 0; |
+ } |
+ return page_index_map_.rbegin()->first; |
+ } |
+} |
+ |
bool ExtensionPrefs::WasAppDraggedByUser(const std::string& extension_id) { |
return ReadExtensionPrefBoolean(extension_id, kPrefUserDraggedApp); |
} |
@@ -1661,7 +1888,9 @@ void ExtensionPrefs::InitPrefStore(bool extensions_disabled) { |
} |
FixMissingPrefs(extension_ids); |
+ InitializePageIndexMap(extension_ids); |
MigratePermissions(extension_ids); |
+ MigrateAppIndex(extension_ids); |
// Store extension controlled preference values in the |
// |extension_pref_value_map_|, which then informs the subscribers |