| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/extensions/app_list_extension_ordering.h" |
| 6 #include "chrome/browser/extensions/extension_prefs.h" |
| 7 #include "chrome/common/chrome_notification_types.h" |
| 8 #include "content/public/browser/notification_service.h" |
| 9 |
| 10 namespace { |
| 11 const char kPrefAppListOrdinal[] = "app_list_ordinal"; |
| 12 } |
| 13 |
| 14 AppListExtensionOrdering::AppListExtensionOrdering( |
| 15 ExtensionScopedPrefs* extension_scoped_prefs) |
| 16 : ExtensionOrdering(extension_scoped_prefs) {} |
| 17 AppListExtensionOrdering::~AppListExtensionOrdering() {} |
| 18 |
| 19 // ExtensionOrdering implementation. |
| 20 void AppListExtensionOrdering::Initialize( |
| 21 const extensions::ExtensionIdList& extension_ids) { |
| 22 for (extensions::ExtensionIdList::const_iterator ext_it = |
| 23 extension_ids.begin(); ext_it != extension_ids.end(); ++ext_it) { |
| 24 syncer::StringOrdinal ordinal = GetAppListOrdinal(*ext_it); |
| 25 if (ordinal.IsValid()) { |
| 26 SetAppListOrdinal(*ext_it, ordinal); |
| 27 } |
| 28 |
| 29 // Ensure that the web store app still isn't found in this list, since |
| 30 // it is added after this loop. |
| 31 DCHECK(*ext_it != extension_misc::kWebStoreAppId); |
| 32 DCHECK(*ext_it != extension_misc::kChromeAppId); |
| 33 } |
| 34 |
| 35 // Include the Web Store App since it is displayed on the app list. |
| 36 syncer::StringOrdinal web_store_app_ordinal = |
| 37 GetAppListOrdinal(extension_misc::kWebStoreAppId); |
| 38 if (web_store_app_ordinal.IsValid()) { |
| 39 SetAppListOrdinal(extension_misc::kWebStoreAppId, web_store_app_ordinal); |
| 40 } |
| 41 // Include the Chrome App since it is displayed on the app list. |
| 42 syncer::StringOrdinal chrome_app_ordinal = |
| 43 GetAppListOrdinal(extension_misc::kChromeAppId); |
| 44 if (web_store_app_ordinal.IsValid()) { |
| 45 SetAppListOrdinal(extension_misc::kChromeAppId, chrome_app_ordinal); |
| 46 } |
| 47 } |
| 48 |
| 49 void AppListExtensionOrdering::FixSyncCollisions() { |
| 50 for (AppListOrdinalMap::iterator ordinal_map_it = app_list_ordinal_map_ |
| 51 .begin(); |
| 52 ordinal_map_it != app_list_ordinal_map_.end(); ++ordinal_map_it) { |
| 53 syncer::StringOrdinal repeated_ordinal = ordinal_map_it->first; |
| 54 ExtensionIdSet& extension_set = ordinal_map_it->second; |
| 55 if (extension_set.size() == 1) |
| 56 continue; |
| 57 AppListOrdinalMap::iterator next_it = ordinal_map_it; |
| 58 ++next_it; |
| 59 |
| 60 syncer::StringOrdinal upper_bound_ordinal = |
| 61 next_it == app_list_ordinal_map_.end() ? syncer::StringOrdinal() |
| 62 : next_it->first; |
| 63 syncer::StringOrdinal lower_bound_ordinal = repeated_ordinal; |
| 64 std::vector<std::string> conflicting_ids(extension_set.begin(), |
| 65 extension_set.end()); |
| 66 // Start at position 1 because the first extension can keep the conflicted |
| 67 // value. |
| 68 for (size_t i = 1; i < conflicting_ids.size(); ++i) { |
| 69 syncer::StringOrdinal unique_ordinal; |
| 70 if (upper_bound_ordinal.IsValid()) { |
| 71 unique_ordinal = |
| 72 lower_bound_ordinal.CreateBetween(upper_bound_ordinal); |
| 73 } else { |
| 74 unique_ordinal = lower_bound_ordinal.CreateAfter(); |
| 75 } |
| 76 Erase(conflicting_ids[i]); |
| 77 SetAppListOrdinal(conflicting_ids[i], unique_ordinal); |
| 78 lower_bound_ordinal = unique_ordinal; |
| 79 } |
| 80 } |
| 81 |
| 82 content::NotificationService::current()->Notify( |
| 83 chrome::NOTIFICATION_APP_LIST_REORDERED, |
| 84 content::Source<AppListExtensionOrdering>(this), |
| 85 content::NotificationService::NoDetails()); |
| 86 } |
| 87 |
| 88 void AppListExtensionOrdering::InsertAtFront(const std::string& extension_id) { |
| 89 syncer::StringOrdinal ordinal = syncer::StringOrdinal::CreateInitialOrdinal(); |
| 90 if (!app_list_ordinal_map_.empty()) { |
| 91 ordinal = app_list_ordinal_map_.begin()->first.CreateBefore(); |
| 92 } |
| 93 SetAppListOrdinal(extension_id, ordinal); |
| 94 } |
| 95 |
| 96 void AppListExtensionOrdering::InsertAtBack(const std::string& extension_id) { |
| 97 syncer::StringOrdinal ordinal = syncer::StringOrdinal::CreateInitialOrdinal(); |
| 98 if (!app_list_ordinal_map_.empty()) { |
| 99 ordinal = app_list_ordinal_map_.rbegin()->first.CreateAfter(); |
| 100 } |
| 101 SetAppListOrdinal(extension_id, ordinal); |
| 102 } |
| 103 |
| 104 void AppListExtensionOrdering::InsertAtNextAvailable( |
| 105 const std::string& extension_id) { |
| 106 InsertAtBack(extension_id); |
| 107 } |
| 108 |
| 109 void AppListExtensionOrdering::OnExtensionMoved( |
| 110 const std::string& moved_extension_id, |
| 111 const std::string& predecessor_extension_id, |
| 112 const std::string& successor_extension_id) { |
| 113 const syncer::StringOrdinal& predecessor_ordinal = |
| 114 predecessor_extension_id.empty() ? |
| 115 syncer::StringOrdinal() : |
| 116 GetAppListOrdinal(predecessor_extension_id); |
| 117 const syncer::StringOrdinal& successor_ordinal = |
| 118 successor_extension_id.empty() ? |
| 119 syncer::StringOrdinal() : |
| 120 GetAppListOrdinal(successor_extension_id); |
| 121 // We only need to change the StringOrdinal if there are neighbours. |
| 122 if (predecessor_ordinal.IsValid() || successor_ordinal.IsValid()) { |
| 123 if (!predecessor_ordinal.IsValid()) { |
| 124 // Only a successor. |
| 125 SetAppListOrdinal(moved_extension_id, successor_ordinal.CreateBefore()); |
| 126 } else if (!successor_ordinal.IsValid()) { |
| 127 // Only a predecessor. |
| 128 SetAppListOrdinal(moved_extension_id, predecessor_ordinal.CreateAfter()); |
| 129 } else { |
| 130 // Both a successor and predecessor |
| 131 SetAppListOrdinal(moved_extension_id, |
| 132 predecessor_ordinal.CreateBetween(successor_ordinal)); |
| 133 } |
| 134 } |
| 135 |
| 136 content::NotificationService::current()->Notify( |
| 137 chrome::NOTIFICATION_APP_LIST_REORDERED, |
| 138 content::Source<AppListExtensionOrdering>(this), |
| 139 content::Details<const std::string>(&moved_extension_id)); |
| 140 } |
| 141 |
| 142 void AppListExtensionOrdering::Erase(const std::string& extension_id) { |
| 143 AppListOrdinalMap::iterator ordinal_map_it = |
| 144 app_list_ordinal_map_.find(GetAppListOrdinal(extension_id)); |
| 145 if (ordinal_map_it != app_list_ordinal_map_.end()) { |
| 146 ordinal_map_it->second.erase(extension_id); |
| 147 if (ordinal_map_it->second.empty()) |
| 148 app_list_ordinal_map_.erase(ordinal_map_it); |
| 149 } |
| 150 UpdatePrefs(extension_id, syncer::StringOrdinal()); |
| 151 } |
| 152 |
| 153 bool AppListExtensionOrdering::ExtensionPrecedes( |
| 154 const std::string& extension1, |
| 155 const std::string& extension2) { |
| 156 if (!GetAppListOrdinal(extension1).IsValid()) |
| 157 return false; |
| 158 if (!GetAppListOrdinal(extension2).IsValid()) |
| 159 return true; |
| 160 return GetAppListOrdinal(extension1).LessThan(GetAppListOrdinal(extension2)); |
| 161 } |
| 162 |
| 163 syncer::StringOrdinal AppListExtensionOrdering::GetAppListOrdinal( |
| 164 const std::string& extension_id) { |
| 165 std::string raw_data; |
| 166 // If the preference read fails then raw_data will still be unset and we will |
| 167 // return an invalid StringOrdinal to signal that no page ordinal was found. |
| 168 extension_scoped_prefs_->ReadPrefAsString( |
| 169 extension_id, kPrefAppListOrdinal, &raw_data); |
| 170 return syncer::StringOrdinal(raw_data); |
| 171 } |
| 172 |
| 173 void AppListExtensionOrdering::SetAppListOrdinal( |
| 174 const std::string& extension_id, |
| 175 const syncer::StringOrdinal& ordinal) { |
| 176 app_list_ordinal_map_[ordinal].insert(extension_id); |
| 177 UpdatePrefs(extension_id, ordinal); |
| 178 } |
| 179 |
| 180 void AppListExtensionOrdering::UpdatePrefs( |
| 181 const std::string& extension_id, |
| 182 const syncer::StringOrdinal& ordinal) { |
| 183 if (ordinal.EqualsOrBothInvalid(GetAppListOrdinal(extension_id))) |
| 184 return; |
| 185 Value* new_value = ordinal.IsValid() ? |
| 186 Value::CreateStringValue(ordinal.ToInternalValue()) : |
| 187 NULL; |
| 188 extension_scoped_prefs_->UpdateExtensionPref( |
| 189 extension_id, |
| 190 kPrefAppListOrdinal, |
| 191 new_value); |
| 192 SyncIfNeeded(extension_id); |
| 193 } |
| OLD | NEW |