Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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_MENU_MANAGER_H_
      6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_MENU_MANAGER_H_
      7 #pragma once
      8 
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <vector>
     13 
     14 #include "base/basictypes.h"
     15 #include "base/gtest_prod_util.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/string16.h"
     18 #include "chrome/browser/extensions/extension_icon_manager.h"
     19 #include "chrome/common/extensions/extension_extent.h"
     20 #include "content/common/notification_observer.h"
     21 #include "content/common/notification_registrar.h"
     22 
     23 struct ContextMenuParams;
     24 
     25 class Extension;
     26 class Profile;
     27 class SkBitmap;
     28 class TabContents;
     29 
     30 // Represents a menu item added by an extension.
     31 class ExtensionMenuItem {
     32  public:
     33   // A list of ExtensionMenuItem's.
     34   typedef std::vector<ExtensionMenuItem*> List;
     35 
     36   // An Id uniquely identifies a context menu item registered by an extension.
     37   struct Id {
     38     Id();
     39     Id(Profile* profile, const std::string& extension_id, int uid);
     40     ~Id();
     41 
     42     bool operator==(const Id& other) const;
     43     bool operator!=(const Id& other) const;
     44     bool operator<(const Id& other) const;
     45 
     46     Profile* profile;
     47     std::string extension_id;
     48     int uid;
     49   };
     50 
     51   // For context menus, these are the contexts where an item can appear.
     52   enum Context {
     53     ALL = 1,
     54     PAGE = 2,
     55     SELECTION = 4,
     56     LINK = 8,
     57     EDITABLE = 16,
     58     IMAGE = 32,
     59     VIDEO = 64,
     60     AUDIO = 128,
     61     FRAME = 256,
     62   };
     63 
     64   // An item can be only one of these types.
     65   enum Type {
     66     NORMAL,
     67     CHECKBOX,
     68     RADIO,
     69     SEPARATOR
     70   };
     71 
     72   // A list of Contexts for an item.
     73   class ContextList {
     74    public:
     75     ContextList() : value_(0) {}
     76     explicit ContextList(Context context) : value_(context) {}
     77     ContextList(const ContextList& other) : value_(other.value_) {}
     78 
     79     void operator=(const ContextList& other) {
     80       value_ = other.value_;
     81     }
     82 
     83     bool operator==(const ContextList& other) const {
     84       return value_ == other.value_;
     85     }
     86 
     87     bool operator!=(const ContextList& other) const {
     88       return !(*this == other);
     89     }
     90 
     91     bool Contains(Context context) const {
     92       return (value_ & context) > 0;
     93     }
     94 
     95     void Add(Context context) {
     96       value_ |= context;
     97     }
     98 
     99    private:
    100     uint32 value_;  // A bitmask of Context values.
    101   };
    102 
    103   ExtensionMenuItem(const Id& id,
    104                     const std::string& title,
    105                     bool checked,
    106                     Type type,
    107                     const ContextList& contexts);
    108   virtual ~ExtensionMenuItem();
    109 
    110   // Simple accessor methods.
    111   const std::string& extension_id() const { return id_.extension_id; }
    112   const std::string& title() const { return title_; }
    113   const List& children() { return children_; }
    114   const Id& id() const { return id_; }
    115   Id* parent_id() const { return parent_id_.get(); }
    116   int child_count() const { return children_.size(); }
    117   ContextList contexts() const { return contexts_; }
    118   Type type() const { return type_; }
    119   bool checked() const { return checked_; }
    120   const ExtensionExtent& document_url_patterns() const {
    121     return document_url_patterns_;
    122   }
    123   const ExtensionExtent& target_url_patterns() const {
    124     return target_url_patterns_;
    125   }
    126 
    127   // Simple mutator methods.
    128   void set_title(const std::string& new_title) { title_ = new_title; }
    129   void set_contexts(ContextList contexts) { contexts_ = contexts; }
    130   void set_type(Type type) { type_ = type; }
    131   void set_document_url_patterns(const ExtensionExtent& patterns) {
    132     document_url_patterns_ = patterns;
    133   }
    134   void set_target_url_patterns(const ExtensionExtent& patterns) {
    135     target_url_patterns_ = patterns;
    136   }
    137 
    138   // Returns the title with any instances of %s replaced by |selection|. The
    139   // result will be no longer than |max_length|.
    140   string16 TitleWithReplacement(const string16& selection,
    141                                 size_t max_length) const;
    142 
    143   // Set the checked state to |checked|. Returns true if successful.
    144   bool SetChecked(bool checked);
    145 
    146  protected:
    147   friend class ExtensionMenuManager;
    148 
    149   // Takes ownership of |item| and sets its parent_id_.
    150   void AddChild(ExtensionMenuItem* item);
    151 
    152   // Takes the child item from this parent. The item is returned and the caller
    153   // then owns the pointer.
    154   ExtensionMenuItem* ReleaseChild(const Id& child_id, bool recursive);
    155 
    156   // Recursively removes all descendant items (children, grandchildren, etc.),
    157   // returning the ids of the removed items.
    158   std::set<Id> RemoveAllDescendants();
    159 
    160  private:
    161   // The unique id for this item.
    162   Id id_;
    163 
    164   // What gets shown in the menu for this item.
    165   std::string title_;
    166 
    167   Type type_;
    168 
    169   // This should only be true for items of type CHECKBOX or RADIO.
    170   bool checked_;
    171 
    172   // In what contexts should the item be shown?
    173   ContextList contexts_;
    174 
    175   // If this item is a child of another item, the unique id of its parent. If
    176   // this is a top-level item with no parent, this will be NULL.
    177   scoped_ptr<Id> parent_id_;
    178 
    179   // Patterns for restricting what documents this item will appear for. This
    180   // applies to the frame where the click took place.
    181   ExtensionExtent document_url_patterns_;
    182 
    183   // Patterns for restricting where items appear based on the src/href
    184   // attribute of IMAGE/AUDIO/VIDEO/LINK tags.
    185   ExtensionExtent target_url_patterns_;
    186 
    187   // Any children this item may have.
    188   List children_;
    189 
    190   DISALLOW_COPY_AND_ASSIGN(ExtensionMenuItem);
    191 };
    192 
    193 // This class keeps track of menu items added by extensions.
    194 class ExtensionMenuManager : public NotificationObserver {
    195  public:
    196   // A bitmask of values from URLPattern::SchemeMasks indicating the schemes
    197   // of pages where we'll show extension menu items.
    198   static const int kAllowedSchemes;
    199 
    200   ExtensionMenuManager();
    201   virtual ~ExtensionMenuManager();
    202 
    203   // Returns the ids of extensions which have menu items registered.
    204   std::set<std::string> ExtensionIds();
    205 
    206   // Returns a list of all the *top-level* menu items (added via AddContextItem)
    207   // for the given extension id, *not* including child items (added via
    208   // AddChildItem); although those can be reached via the top-level items'
    209   // children. A view can then decide how to display these, including whether to
    210   // put them into a submenu if there are more than 1.
    211   const ExtensionMenuItem::List* MenuItems(const std::string& extension_id);
    212 
    213   // Adds a top-level menu item for an extension, requiring the |extension|
    214   // pointer so it can load the icon for the extension. Takes ownership of
    215   // |item|. Returns a boolean indicating success or failure.
    216   bool AddContextItem(const Extension* extension, ExtensionMenuItem* item);
    217 
    218   // Add an item as a child of another item which has been previously added, and
    219   // takes ownership of |item|. Returns a boolean indicating success or failure.
    220   bool AddChildItem(const ExtensionMenuItem::Id& parent_id,
    221                     ExtensionMenuItem* child);
    222 
    223   // Makes existing item with |child_id| a child of the item with |parent_id|.
    224   // If the child item was already a child of another parent, this will remove
    225   // it from that parent first. It is an error to try and move an item to be a
    226   // child of one of its own descendants. It is legal to pass NULL for
    227   // |parent_id|, which means the item should be moved to the top-level.
    228   bool ChangeParent(const ExtensionMenuItem::Id& child_id,
    229                     const ExtensionMenuItem::Id* parent_id);
    230 
    231   // Removes a context menu item with the given id (whether it is a top-level
    232   // item or a child of some other item), returning true if the item was found
    233   // and removed or false otherwise.
    234   bool RemoveContextMenuItem(const ExtensionMenuItem::Id& id);
    235 
    236   // Removes all items for the given extension id.
    237   void RemoveAllContextItems(const std::string& extension_id);
    238 
    239   // Returns the item with the given |id| or NULL.
    240   ExtensionMenuItem* GetItemById(const ExtensionMenuItem::Id& id) const;
    241 
    242   // Called when a menu item is clicked on by the user.
    243   void ExecuteCommand(Profile* profile, TabContents* tab_contents,
    244                       const ContextMenuParams& params,
    245                       const ExtensionMenuItem::Id& menuItemId);
    246 
    247   // This returns a bitmap of width/height kFaviconSize, loaded either from an
    248   // entry specified in the extension's 'icon' section of the manifest, or a
    249   // default extension icon.
    250   const SkBitmap& GetIconForExtension(const std::string& extension_id);
    251 
    252   // Implements the NotificationObserver interface.
    253   virtual void Observe(NotificationType type, const NotificationSource& source,
    254                        const NotificationDetails& details);
    255 
    256   // Returns true if |url| has an allowed scheme for extension context menu
    257   // items. This checks against kAllowedSchemes.
    258   static bool HasAllowedScheme(const GURL& url);
    259 
    260  private:
    261   FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, DeleteParent);
    262   FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, RemoveOneByOne);
    263 
    264   // This is a helper function which takes care of de-selecting any other radio
    265   // items in the same group (i.e. that are adjacent in the list).
    266   void RadioItemSelected(ExtensionMenuItem* item);
    267 
    268   // Returns true if item is a descendant of an item with id |ancestor_id|.
    269   bool DescendantOf(ExtensionMenuItem* item,
    270                     const ExtensionMenuItem::Id& ancestor_id);
    271 
    272   // We keep items organized by mapping an extension id to a list of items.
    273   typedef std::map<std::string, ExtensionMenuItem::List> MenuItemMap;
    274   MenuItemMap context_items_;
    275 
    276   // This lets us make lookup by id fast. It maps id to ExtensionMenuItem* for
    277   // all items the menu manager knows about, including all children of top-level
    278   // items.
    279   std::map<ExtensionMenuItem::Id, ExtensionMenuItem*> items_by_id_;
    280 
    281   NotificationRegistrar registrar_;
    282 
    283   ExtensionIconManager icon_manager_;
    284 
    285   DISALLOW_COPY_AND_ASSIGN(ExtensionMenuManager);
    286 };
    287 
    288 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_MENU_MANAGER_H_
    289