1 // Copyright (c) 2012 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 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SORTING_H_ 6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_SORTING_H_ 7 8 #include <map> 9 #include <set> 10 #include <string> 11 12 #include "base/basictypes.h" 13 #include "chrome/browser/extensions/extension_prefs.h" 14 #include "chrome/common/extensions/extension.h" 15 #include "sync/api/string_ordinal.h" 16 17 class ExtensionScopedPrefs; 18 class ExtensionServiceInterface; 19 class PrefService; 20 21 class ExtensionSorting { 22 public: 23 explicit ExtensionSorting(ExtensionScopedPrefs* extension_scoped_prefs); 24 ~ExtensionSorting(); 25 26 // Set up the ExtensionService to inform of changes that require syncing. 27 void SetExtensionService(ExtensionServiceInterface* extension_service); 28 29 // Properly initialize ExtensionSorting internal values that require 30 // |extension_ids|. 31 void Initialize( 32 const extensions::ExtensionIdList& extension_ids); 33 34 // Resolves any conflicts the might be created as a result of syncing that 35 // results in two icons having the same page and app launch ordinal. After 36 // this is called it is guaranteed that there are no collisions of NTP icons. 37 void FixNTPOrdinalCollisions(); 38 39 // This ensures that the extension has valid ordinals, and if it doesn't then 40 // properly initialize them. |suggested_page| will be used if it is valid and 41 // the extension has no valid user-set page ordinal. 42 void EnsureValidOrdinals(const std::string& extension_id, 43 const syncer::StringOrdinal& suggested_page); 44 45 // Updates the app launcher value for the moved extension so that it is now 46 // located after the given predecessor and before the successor. 47 // Empty strings are used to indicate no successor or predecessor. 48 void OnExtensionMoved(const std::string& moved_extension_id, 49 const std::string& predecessor_extension_id, 50 const std::string& successor_extension_id); 51 52 // Get the application launch ordinal for an app with |extension_id|. This 53 // determines the order in which the app appears on the page it's on in the 54 // New Tab Page (Note that you can compare app launch ordinals only if the 55 // apps are on the same page). A string value close to |a*| generally 56 // indicates top left. If the extension has no launch ordinal, an invalid 57 // StringOrdinal is returned. 58 syncer::StringOrdinal GetAppLaunchOrdinal( 59 const std::string& extension_id) const; 60 61 // Sets a specific launch ordinal for an app with |extension_id|. 62 void SetAppLaunchOrdinal(const std::string& extension_id, 63 const syncer::StringOrdinal& new_app_launch_ordinal); 64 65 // Returns a StringOrdinal that is lower than any app launch ordinal for the 66 // given page. 67 syncer::StringOrdinal CreateFirstAppLaunchOrdinal( 68 const syncer::StringOrdinal& page_ordinal) const; 69 70 // Returns a StringOrdinal that is higher than any app launch ordinal for the 71 // given page. 72 syncer::StringOrdinal CreateNextAppLaunchOrdinal( 73 const syncer::StringOrdinal& page_ordinal) const; 74 75 // Returns a StringOrdinal that is lower than any existing page ordinal. 76 syncer::StringOrdinal CreateFirstAppPageOrdinal() const; 77 78 // Gets the page a new app should install to, which is the earliest non-full 79 // page. The returned ordinal may correspond to a page that doesn't yet exist 80 // if all pages are full. 81 syncer::StringOrdinal GetNaturalAppPageOrdinal() const; 82 83 // Get the page ordinal for an app with |extension_id|. This determines 84 // which page an app will appear on in page-based NTPs. If the app has no 85 // page specified, an invalid StringOrdinal is returned. 86 syncer::StringOrdinal GetPageOrdinal(const std::string& extension_id) const; 87 88 // Sets a specific page ordinal for an app with |extension_id|. 89 void SetPageOrdinal(const std::string& extension_id, 90 const syncer::StringOrdinal& new_page_ordinal); 91 92 // Removes the ordinal values for an app. 93 void ClearOrdinals(const std::string& extension_id); 94 95 // Convert the page StringOrdinal value to its integer equivalent. This takes 96 // O(# of apps) worst-case. 97 int PageStringOrdinalAsInteger( 98 const syncer::StringOrdinal& page_ordinal) const; 99 100 // Converts the page index integer to its StringOrdinal equivalent. This takes 101 // O(# of apps) worst-case. 102 syncer::StringOrdinal PageIntegerAsStringOrdinal(size_t page_index); 103 104 // Hidden extensions don't appear in the new tab page. 105 void MarkExtensionAsHidden(const std::string& extension_id); 106 107 private: 108 // The StringOrdinal is the app launch ordinal and the string is the extension 109 // id. 110 typedef std::multimap< 111 syncer::StringOrdinal, std::string, 112 syncer::StringOrdinal::LessThanFn> AppLaunchOrdinalMap; 113 // The StringOrdinal is the page ordinal and the AppLaunchOrdinalMap is the 114 // contents of that page. 115 typedef std::map< 116 syncer::StringOrdinal, AppLaunchOrdinalMap, 117 syncer::StringOrdinal::LessThanFn> PageOrdinalMap; 118 119 // Unit tests. 120 friend class ExtensionSortingDefaultOrdinalsBase; 121 friend class ExtensionSortingGetMinOrMaxAppLaunchOrdinalsOnPage; 122 friend class ExtensionSortingInitializeWithNoApps; 123 friend class ExtensionSortingPageOrdinalMapping; 124 125 // An enum used by GetMinOrMaxAppLaunchOrdinalsOnPage to specify which 126 // value should be returned. 127 enum AppLaunchOrdinalReturn {MIN_ORDINAL, MAX_ORDINAL}; 128 129 // Maps an app id to its ordinals. 130 struct AppOrdinals { 131 AppOrdinals(); 132 ~AppOrdinals(); 133 134 syncer::StringOrdinal page_ordinal; 135 syncer::StringOrdinal app_launch_ordinal; 136 }; 137 typedef std::map<std::string, AppOrdinals> AppOrdinalsMap; 138 139 // This function returns the lowest ordinal on |page_ordinal| if 140 // |return_value| == AppLaunchOrdinalReturn::MIN_ORDINAL, otherwise it returns 141 // the largest ordinal on |page_ordinal|. If there are no apps on the page 142 // then an invalid StringOrdinal is returned. It is an error to call this 143 // function with an invalid |page_ordinal|. 144 syncer::StringOrdinal GetMinOrMaxAppLaunchOrdinalsOnPage( 145 const syncer::StringOrdinal& page_ordinal, 146 AppLaunchOrdinalReturn return_type) const; 147 148 // Initialize the |page_ordinal_map_| with the page ordinals used by the 149 // given extensions. 150 void InitializePageOrdinalMap( 151 const extensions::ExtensionIdList& extension_ids); 152 153 // Migrates the app launcher and page index values. 154 void MigrateAppIndex( 155 const extensions::ExtensionIdList& extension_ids); 156 157 // Called to add a new mapping value for |extension_id| with a page ordinal 158 // of |page_ordinal| and a app launch ordinal of |app_launch_ordinal|. This 159 // works with valid and invalid StringOrdinals. 160 void AddOrdinalMapping(const std::string& extension_id, 161 const syncer::StringOrdinal& page_ordinal, 162 const syncer::StringOrdinal& app_launch_ordinal); 163 164 // Ensures |ntp_ordinal_map_| is of |minimum_size| number of entries. 165 void CreateOrdinalsIfNecessary(size_t minimum_size); 166 167 // Removes the mapping for |extension_id| with a page ordinal of 168 // |page_ordinal| and a app launch ordinal of |app_launch_ordinal|. If there 169 // is not matching map, nothing happens. This works with valid and invalid 170 // StringOrdinals. 171 void RemoveOrdinalMapping(const std::string& extension_id, 172 const syncer::StringOrdinal& page_ordinal, 173 const syncer::StringOrdinal& app_launch_ordinal); 174 175 // Syncs the extension if needed. It is an error to call this if the 176 // extension is not an application. 177 void SyncIfNeeded(const std::string& extension_id); 178 179 // Creates the default ordinals. 180 void CreateDefaultOrdinals(); 181 182 // Gets the default ordinals for |extension_id|. Returns false if no default 183 // ordinals for |extension_id| is defined. Otherwise, returns true and 184 // ordinals is updated with corresponding ordinals. 185 bool GetDefaultOrdinals(const std::string& extension_id, 186 syncer::StringOrdinal* page_ordinal, 187 syncer::StringOrdinal* app_launch_ordinal); 188 189 // Returns |app_launch_ordinal| if it has no collision in the page specified 190 // by |page_ordinal|. Otherwise, returns an ordinal after |app_launch_ordinal| 191 // that has no conflict. 192 syncer::StringOrdinal ResolveCollision( 193 const syncer::StringOrdinal& page_ordinal, 194 const syncer::StringOrdinal& app_launch_ordinal) const; 195 196 // Returns the number of items in |m| visible on the new tab page. 197 size_t CountItemsVisibleOnNtp(const AppLaunchOrdinalMap& m) const; 198 199 ExtensionScopedPrefs* extension_scoped_prefs_; // Weak, owns this instance. 200 ExtensionServiceInterface* extension_service_; // Weak. 201 202 // A map of all the StringOrdinal page ordinals mapping to the collections of 203 // app launch ordinals that exist on that page. This is used for mapping 204 // StringOrdinals to their Integer equivalent as well as quick lookup of the 205 // any collision of on the NTP (icons with the same page and same app launch 206 // ordinals). The possiblity of collisions means that a multimap must be used 207 // (although the collisions must all be resolved once all the syncing is 208 // done). 209 PageOrdinalMap ntp_ordinal_map_; 210 211 // Defines the default ordinals. 212 AppOrdinalsMap default_ordinals_; 213 214 // Used to construct the default ordinals once when needed instead of on 215 // construction when the app order may not have been determined. 216 bool default_ordinals_created_; 217 218 // The set of extensions that don't appear in the new tab page. 219 std::set<std::string> ntp_hidden_extensions_; 220 221 DISALLOW_COPY_AND_ASSIGN(ExtensionSorting); 222 }; 223 224 #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SORTING_H_ 225