Home | History | Annotate | Download | only in extensions
      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