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_TOOLBAR_MODEL_H_
      6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
      7 
      8 #include "base/compiler_specific.h"
      9 #include "base/observer_list.h"
     10 #include "base/prefs/pref_change_registrar.h"
     11 #include "base/scoped_observer.h"
     12 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
     13 #include "chrome/browser/extensions/extension_action.h"
     14 #include "components/keyed_service/core/keyed_service.h"
     15 #include "content/public/browser/notification_observer.h"
     16 #include "content/public/browser/notification_registrar.h"
     17 #include "extensions/browser/extension_prefs.h"
     18 #include "extensions/browser/extension_registry_observer.h"
     19 #include "extensions/common/extension.h"
     20 
     21 class Browser;
     22 class PrefService;
     23 class Profile;
     24 
     25 namespace extensions {
     26 class ExtensionRegistry;
     27 class ExtensionSet;
     28 
     29 // Model for the browser actions toolbar.
     30 class ExtensionToolbarModel : public content::NotificationObserver,
     31                               public ExtensionActionAPI::Observer,
     32                               public ExtensionRegistryObserver,
     33                               public KeyedService {
     34  public:
     35   ExtensionToolbarModel(Profile* profile, ExtensionPrefs* extension_prefs);
     36   virtual ~ExtensionToolbarModel();
     37 
     38   // A class which is informed of changes to the model; represents the view of
     39   // MVC. Also used for signaling view changes such as showing extension popups.
     40   // TODO(devlin): Should this really be an observer? It acts more like a
     41   // delegate.
     42   class Observer {
     43    public:
     44     // An extension has been added to the toolbar and should go at |index|.
     45     virtual void ToolbarExtensionAdded(const Extension* extension,
     46                                        int index) = 0;
     47 
     48     // The given |extension| should be removed from the toolbar.
     49     virtual void ToolbarExtensionRemoved(const Extension* extension) = 0;
     50 
     51     // The given |extension| has been moved to |index|. |index| is the desired
     52     // *final* index of the extension (that is, in the adjusted order, extension
     53     // should be at |index|).
     54     virtual void ToolbarExtensionMoved(const Extension* extension,
     55                                        int index) = 0;
     56 
     57     // Signals that the browser action for the given |extension| has been
     58     // updated.
     59     virtual void ToolbarExtensionUpdated(const Extension* extension) = 0;
     60 
     61     // Signal the |extension| to show the popup now in the active window.
     62     // If |grant_active_tab| is true, then active tab permissions should be
     63     // given to the extension (only do this if this is through a user action).
     64     // Returns true if a popup was slated to be shown.
     65     virtual bool ShowExtensionActionPopup(const Extension* extension,
     66                                           bool grant_active_tab) = 0;
     67 
     68     // Signal when the container needs to be redrawn because of a size change,
     69     // and when the model has finished loading.
     70     virtual void ToolbarVisibleCountChanged() = 0;
     71 
     72     // Signal that the model has entered or exited highlighting mode, or that
     73     // the extensions being highlighted have (probably*) changed. Highlighting
     74     // mode indicates that only a subset of the extensions are actively
     75     // displayed, and those extensions should be highlighted for extra emphasis.
     76     // * probably, because if we are in highlight mode and receive a call to
     77     //   highlight a new set of extensions, we do not compare the current set
     78     //   with the new set (and just assume the new set is different).
     79     virtual void ToolbarHighlightModeChanged(bool is_highlighting) = 0;
     80 
     81     // Returns the browser associated with the Observer.
     82     virtual Browser* GetBrowser() = 0;
     83 
     84    protected:
     85     virtual ~Observer() {}
     86   };
     87 
     88   // Convenience function to get the ExtensionToolbarModel for a Profile.
     89   static ExtensionToolbarModel* Get(Profile* profile);
     90 
     91   // Add or remove an observer.
     92   void AddObserver(Observer* observer);
     93   void RemoveObserver(Observer* observer);
     94 
     95   // Moves the given |extension|'s icon to the given |index|.
     96   void MoveExtensionIcon(const Extension* extension, int index);
     97 
     98   // Sets the number of extension icons that should be visible.
     99   // If count == size(), this will set the visible icon count to -1, meaning
    100   // "show all actions".
    101   void SetVisibleIconCount(int count);
    102 
    103   // As above, a return value of -1 represents "show all actions".
    104   int GetVisibleIconCount() const { return visible_icon_count_; }
    105 
    106   bool extensions_initialized() const { return extensions_initialized_; }
    107 
    108   const ExtensionList& toolbar_items() const {
    109     return is_highlighting_ ? highlighted_items_ : toolbar_items_;
    110   }
    111 
    112   bool is_highlighting() const { return is_highlighting_; }
    113 
    114   // Utility functions for converting between an index into the list of
    115   // incognito-enabled browser actions, and the list of all browser actions.
    116   int IncognitoIndexToOriginal(int incognito_index);
    117   int OriginalIndexToIncognito(int original_index);
    118 
    119   void OnExtensionToolbarPrefChange();
    120 
    121   // Finds the Observer associated with |browser| and tells it to display a
    122   // popup for the given |extension|. If |grant_active_tab| is true, this
    123   // grants active tab permissions to the |extension|; only do this because of
    124   // a direct user action.
    125   bool ShowExtensionActionPopup(const Extension* extension,
    126                                 Browser* browser,
    127                                 bool grant_active_tab);
    128 
    129   // Ensures that the extensions in the |extension_ids| list are visible on the
    130   // toolbar. This might mean they need to be moved to the front (if they are in
    131   // the overflow bucket).
    132   void EnsureVisibility(const ExtensionIdList& extension_ids);
    133 
    134   // Highlight the extensions specified by |extension_ids|. This will cause
    135   // the ToolbarModel to only display those extensions.
    136   // Highlighting mode is only entered if there is at least one extension to
    137   // be shown.
    138   // Returns true if highlighting mode is entered, false otherwise.
    139   bool HighlightExtensions(const ExtensionIdList& extension_ids);
    140 
    141   // Stop highlighting extensions. All extensions can be shown again, and the
    142   // number of visible icons will be reset to what it was before highlighting.
    143   void StopHighlighting();
    144 
    145   // Sets the number of visible icons and notifies all observers of the change.
    146   void SetVisibleIconCountForTest(size_t visible_icons);
    147 
    148  private:
    149   // content::NotificationObserver:
    150   virtual void Observe(int type,
    151                        const content::NotificationSource& source,
    152                        const content::NotificationDetails& details) OVERRIDE;
    153 
    154   // Callback when extensions are ready.
    155   void OnReady();
    156 
    157   // ExtensionRegistryObserver:
    158   virtual void OnExtensionLoaded(content::BrowserContext* browser_context,
    159                                  const Extension* extension) OVERRIDE;
    160   virtual void OnExtensionUnloaded(
    161       content::BrowserContext* browser_context,
    162       const Extension* extension,
    163       UnloadedExtensionInfo::Reason reason) OVERRIDE;
    164   virtual void OnExtensionUninstalled(
    165       content::BrowserContext* browser_context,
    166       const Extension* extension,
    167       extensions::UninstallReason reason) OVERRIDE;
    168 
    169   // ExtensionActionAPI::Observer:
    170   virtual void OnExtensionActionUpdated(
    171       ExtensionAction* extension_action,
    172       content::WebContents* web_contents,
    173       content::BrowserContext* browser_context) OVERRIDE;
    174 
    175   // To be called after the extension service is ready; gets loaded extensions
    176   // from the extension service and their saved order from the pref service
    177   // and constructs |toolbar_items_| from these data.
    178   void InitializeExtensionList(const ExtensionSet& extensions);
    179   void Populate(const ExtensionIdList& positions,
    180                 const ExtensionSet& extensions);
    181 
    182   // Save the model to prefs.
    183   void UpdatePrefs();
    184 
    185   // Updates |extension|'s browser action visibility pref if the browser action
    186   // is in the overflow menu and should be considered hidden.
    187   void MaybeUpdateVisibilityPref(const Extension* extension, int index);
    188 
    189   // Calls MaybeUpdateVisibilityPref() for each extension in |toolbar_items|.
    190   void MaybeUpdateVisibilityPrefs();
    191 
    192   // Finds the last known visible position of the icon for an |extension|. The
    193   // value returned is a zero-based index into the vector of visible items.
    194   size_t FindNewPositionFromLastKnownGood(const Extension* extension);
    195 
    196   // Returns true if the given |extension| should be added to the toolbar.
    197   bool ShouldAddExtension(const Extension* extension);
    198 
    199   // Adds or removes the given |extension| from the toolbar model.
    200   void AddExtension(const Extension* extension);
    201   void RemoveExtension(const Extension* extension);
    202 
    203   // Our observers.
    204   ObserverList<Observer> observers_;
    205 
    206   // The Profile this toolbar model is for.
    207   Profile* profile_;
    208 
    209   ExtensionPrefs* extension_prefs_;
    210   PrefService* prefs_;
    211 
    212   // True if we've handled the initial EXTENSIONS_READY notification.
    213   bool extensions_initialized_;
    214 
    215   // If true, we include all extensions in the toolbar model. If false, we only
    216   // include browser actions.
    217   bool include_all_extensions_;
    218 
    219   // Ordered list of browser action buttons.
    220   ExtensionList toolbar_items_;
    221 
    222   // List of browser action buttons which should be highlighted.
    223   ExtensionList highlighted_items_;
    224 
    225   // Indication whether or not we are currently in highlight mode; typically,
    226   // this is equivalent to !highlighted_items_.empty(), but can be different
    227   // if we are exiting highlight mode due to no longer having highlighted items.
    228   bool is_highlighting_;
    229 
    230   // The number of icons which were visible before highlighting a subset, in
    231   // order to restore the count when finished.
    232   int old_visible_icon_count_;
    233 
    234   ExtensionIdList last_known_positions_;
    235 
    236   // The number of icons visible (the rest should be hidden in the overflow
    237   // chevron).
    238   int visible_icon_count_;
    239 
    240   content::NotificationRegistrar registrar_;
    241 
    242   ScopedObserver<ExtensionActionAPI, ExtensionActionAPI::Observer>
    243       extension_action_observer_;
    244 
    245   // Listen to extension load, unloaded notifications.
    246   ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
    247       extension_registry_observer_;
    248 
    249   // For observing change of toolbar order preference by external entity (sync).
    250   PrefChangeRegistrar pref_change_registrar_;
    251   base::Closure pref_change_callback_;
    252 
    253   base::WeakPtrFactory<ExtensionToolbarModel> weak_ptr_factory_;
    254 
    255   DISALLOW_COPY_AND_ASSIGN(ExtensionToolbarModel);
    256 };
    257 
    258 }  // namespace extensions
    259 
    260 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
    261