Home | History | Annotate | Download | only in bookmarks
      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_BOOKMARKS_BOOKMARK_MODEL_H_
      6 #define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/compiler_specific.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/observer_list.h"
     17 #include "base/strings/string16.h"
     18 #include "base/synchronization/lock.h"
     19 #include "base/synchronization/waitable_event.h"
     20 #include "chrome/browser/bookmarks/bookmark_service.h"
     21 #include "chrome/common/cancelable_task_tracker.h"
     22 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
     23 #include "content/public/browser/notification_observer.h"
     24 #include "content/public/browser/notification_registrar.h"
     25 #include "ui/base/models/tree_node_model.h"
     26 #include "ui/gfx/image/image.h"
     27 #include "url/gurl.h"
     28 
     29 class BookmarkExpandedStateTracker;
     30 class BookmarkIndex;
     31 class BookmarkLoadDetails;
     32 class BookmarkModel;
     33 class BookmarkModelObserver;
     34 class BookmarkStorage;
     35 struct BookmarkTitleMatch;
     36 class Profile;
     37 
     38 namespace base {
     39 class SequencedTaskRunner;
     40 }
     41 
     42 namespace chrome {
     43 struct FaviconImageResult;
     44 }
     45 
     46 // BookmarkNode ---------------------------------------------------------------
     47 
     48 // BookmarkNode contains information about a starred entry: title, URL, favicon,
     49 // id and type. BookmarkNodes are returned from BookmarkModel.
     50 class BookmarkNode : public ui::TreeNode<BookmarkNode> {
     51  public:
     52   enum Type {
     53     URL,
     54     FOLDER,
     55     BOOKMARK_BAR,
     56     OTHER_NODE,
     57     MOBILE
     58   };
     59 
     60   enum FaviconState {
     61     INVALID_FAVICON,
     62     LOADING_FAVICON,
     63     LOADED_FAVICON,
     64   };
     65 
     66   typedef std::map<std::string, std::string> MetaInfoMap;
     67 
     68   static const int64 kInvalidSyncTransactionVersion;
     69 
     70   // Creates a new node with an id of 0 and |url|.
     71   explicit BookmarkNode(const GURL& url);
     72   // Creates a new node with |id| and |url|.
     73   BookmarkNode(int64 id, const GURL& url);
     74 
     75   virtual ~BookmarkNode();
     76 
     77   // Set the node's internal title. Note that this neither invokes observers
     78   // nor updates any bookmark model this node may be in. For that functionality,
     79   // BookmarkModel::SetTitle(..) should be used instead.
     80   virtual void SetTitle(const base::string16& title) OVERRIDE;
     81 
     82   // Returns an unique id for this node.
     83   // For bookmark nodes that are managed by the bookmark model, the IDs are
     84   // persisted across sessions.
     85   int64 id() const { return id_; }
     86   void set_id(int64 id) { id_ = id; }
     87 
     88   const GURL& url() const { return url_; }
     89   void set_url(const GURL& url) { url_ = url; }
     90 
     91   // Returns the favicon's URL. Returns an empty URL if there is no favicon
     92   // associated with this bookmark.
     93   const GURL& icon_url() const { return icon_url_; }
     94 
     95   Type type() const { return type_; }
     96   void set_type(Type type) { type_ = type; }
     97 
     98   // Returns the time the node was added.
     99   const base::Time& date_added() const { return date_added_; }
    100   void set_date_added(const base::Time& date) { date_added_ = date; }
    101 
    102   // Returns the last time the folder was modified. This is only maintained
    103   // for folders (including the bookmark bar and other folder).
    104   const base::Time& date_folder_modified() const {
    105     return date_folder_modified_;
    106   }
    107   void set_date_folder_modified(const base::Time& date) {
    108     date_folder_modified_ = date;
    109   }
    110 
    111   // Convenience for testing if this node represents a folder. A folder is a
    112   // node whose type is not URL.
    113   bool is_folder() const { return type_ != URL; }
    114   bool is_url() const { return type_ == URL; }
    115 
    116   bool is_favicon_loaded() const { return favicon_state_ == LOADED_FAVICON; }
    117 
    118   // Accessor method for controlling the visibility of a bookmark node/sub-tree.
    119   // Note that visibility is not propagated down the tree hierarchy so if a
    120   // parent node is marked as invisible, a child node may return "Visible". This
    121   // function is primarily useful when traversing the model to generate a UI
    122   // representation but we may want to suppress some nodes.
    123   virtual bool IsVisible() const;
    124 
    125   // Gets/sets/deletes value of |key| in the meta info represented by
    126   // |meta_info_str_|. Return true if key is found in meta info for gets or
    127   // meta info is changed indeed for sets/deletes.
    128   bool GetMetaInfo(const std::string& key, std::string* value) const;
    129   bool SetMetaInfo(const std::string& key, const std::string& value);
    130   bool DeleteMetaInfo(const std::string& key);
    131   void SetMetaInfoMap(const MetaInfoMap& meta_info_map);
    132   // Returns NULL if there are no values in the map.
    133   const MetaInfoMap* GetMetaInfoMap() const;
    134 
    135   void set_sync_transaction_version(int64 sync_transaction_version) {
    136     sync_transaction_version_ = sync_transaction_version;
    137   }
    138   int64 sync_transaction_version() const {
    139     return sync_transaction_version_;
    140   }
    141 
    142   // TODO(sky): Consider adding last visit time here, it'll greatly simplify
    143   // HistoryContentsProvider.
    144 
    145  private:
    146   friend class BookmarkModel;
    147 
    148   // A helper function to initialize various fields during construction.
    149   void Initialize(int64 id);
    150 
    151   // Called when the favicon becomes invalid.
    152   void InvalidateFavicon();
    153 
    154   // Sets the favicon's URL.
    155   void set_icon_url(const GURL& icon_url) {
    156     icon_url_ = icon_url;
    157   }
    158 
    159   const gfx::Image& favicon() const { return favicon_; }
    160   void set_favicon(const gfx::Image& icon) { favicon_ = icon; }
    161 
    162   FaviconState favicon_state() const { return favicon_state_; }
    163   void set_favicon_state(FaviconState state) { favicon_state_ = state; }
    164 
    165   CancelableTaskTracker::TaskId favicon_load_task_id() const {
    166     return favicon_load_task_id_;
    167   }
    168   void set_favicon_load_task_id(CancelableTaskTracker::TaskId id) {
    169     favicon_load_task_id_ = id;
    170   }
    171 
    172   // The unique identifier for this node.
    173   int64 id_;
    174 
    175   // The URL of this node. BookmarkModel maintains maps off this URL, so changes
    176   // to the URL must be done through the BookmarkModel.
    177   GURL url_;
    178 
    179   // The type of this node. See enum above.
    180   Type type_;
    181 
    182   // Date of when this node was created.
    183   base::Time date_added_;
    184 
    185   // Date of the last modification. Only used for folders.
    186   base::Time date_folder_modified_;
    187 
    188   // The favicon of this node.
    189   gfx::Image favicon_;
    190 
    191   // The URL of the node's favicon.
    192   GURL icon_url_;
    193 
    194   // The loading state of the favicon.
    195   FaviconState favicon_state_;
    196 
    197   // If not CancelableTaskTracker::kBadTaskId, it indicates we're loading the
    198   // favicon and the task is tracked by CancelabelTaskTracker.
    199   CancelableTaskTracker::TaskId favicon_load_task_id_;
    200 
    201   // A map that stores arbitrary meta information about the node.
    202   scoped_ptr<MetaInfoMap> meta_info_map_;
    203 
    204   // The sync transaction version. Defaults to kInvalidSyncTransactionVersion.
    205   int64 sync_transaction_version_;
    206 
    207   DISALLOW_COPY_AND_ASSIGN(BookmarkNode);
    208 };
    209 
    210 // BookmarkPermanentNode -------------------------------------------------------
    211 
    212 // Node used for the permanent folders (excluding the root).
    213 class BookmarkPermanentNode : public BookmarkNode {
    214  public:
    215   explicit BookmarkPermanentNode(int64 id);
    216   virtual ~BookmarkPermanentNode();
    217 
    218   // WARNING: this code is used for other projects. Contact noyau@ for details.
    219   void set_visible(bool value) { visible_ = value; }
    220 
    221   // BookmarkNode overrides:
    222   virtual bool IsVisible() const OVERRIDE;
    223 
    224  private:
    225   bool visible_;
    226 
    227   DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNode);
    228 };
    229 
    230 // BookmarkModel --------------------------------------------------------------
    231 
    232 // BookmarkModel provides a directed acyclic graph of URLs and folders.
    233 // Three graphs are provided for the three entry points: those on the 'bookmarks
    234 // bar', those in the 'other bookmarks' folder and those in the 'mobile' folder.
    235 //
    236 // An observer may be attached to observe relevant events.
    237 //
    238 // You should NOT directly create a BookmarkModel, instead go through the
    239 // BookmarkModelFactory.
    240 class BookmarkModel : public content::NotificationObserver,
    241                       public BookmarkService,
    242                       public BrowserContextKeyedService {
    243  public:
    244   explicit BookmarkModel(Profile* profile);
    245   virtual ~BookmarkModel();
    246 
    247   // Invoked prior to destruction to release any necessary resources.
    248   virtual void Shutdown() OVERRIDE;
    249 
    250   // Loads the bookmarks. This is called upon creation of the
    251   // BookmarkModel. You need not invoke this directly.
    252   // All load operations will be executed on |task_runner|.
    253   void Load(const scoped_refptr<base::SequencedTaskRunner>& task_runner);
    254 
    255   // Returns true if the model finished loading.
    256   bool loaded() const { return loaded_; }
    257 
    258   // Returns the root node. The 'bookmark bar' node and 'other' node are
    259   // children of the root node.
    260   const BookmarkNode* root_node() { return &root_; }
    261 
    262   // Returns the 'bookmark bar' node. This is NULL until loaded.
    263   const BookmarkNode* bookmark_bar_node() { return bookmark_bar_node_; }
    264 
    265   // Returns the 'other' node. This is NULL until loaded.
    266   const BookmarkNode* other_node() { return other_node_; }
    267 
    268   // Returns the 'mobile' node. This is NULL until loaded.
    269   const BookmarkNode* mobile_node() { return mobile_node_; }
    270 
    271   bool is_root_node(const BookmarkNode* node) const { return node == &root_; }
    272 
    273   // Returns whether the given |node| is one of the permanent nodes - root node,
    274   // 'bookmark bar' node, 'other' node or 'mobile' node.
    275   bool is_permanent_node(const BookmarkNode* node) const {
    276     return node == &root_ ||
    277            node == bookmark_bar_node_ ||
    278            node == other_node_ ||
    279            node == mobile_node_;
    280   }
    281 
    282   // Returns the parent the last node was added to. This never returns NULL
    283   // (as long as the model is loaded).
    284   const BookmarkNode* GetParentForNewNodes();
    285 
    286   void AddObserver(BookmarkModelObserver* observer);
    287   void RemoveObserver(BookmarkModelObserver* observer);
    288 
    289   // Notifies the observers that an extensive set of changes is about to happen,
    290   // such as during import or sync, so they can delay any expensive UI updates
    291   // until it's finished.
    292   void BeginExtensiveChanges();
    293   void EndExtensiveChanges();
    294 
    295   // Returns true if this bookmark model is currently in a mode where extensive
    296   // changes might happen, such as for import and sync. This is helpful for
    297   // observers that are created after the mode has started, and want to check
    298   // state during their own initializer, such as the NTP.
    299   bool IsDoingExtensiveChanges() const { return extensive_changes_ > 0; }
    300 
    301   // Removes the node at the given |index| from |parent|. Removing a folder node
    302   // recursively removes all nodes. Observers are notified immediately.
    303   void Remove(const BookmarkNode* parent, int index);
    304 
    305   // Removes all the non-permanent bookmark nodes. Observers are only notified
    306   // when all nodes have been removed. There is no notification for individual
    307   // node removals.
    308   void RemoveAll();
    309 
    310   // Moves |node| to |new_parent| and inserts it at the given |index|.
    311   void Move(const BookmarkNode* node,
    312             const BookmarkNode* new_parent,
    313             int index);
    314 
    315   // Inserts a copy of |node| into |new_parent| at |index|.
    316   void Copy(const BookmarkNode* node,
    317             const BookmarkNode* new_parent,
    318             int index);
    319 
    320   // Returns the favicon for |node|. If the favicon has not yet been
    321   // loaded it is loaded and the observer of the model notified when done.
    322   const gfx::Image& GetFavicon(const BookmarkNode* node);
    323 
    324   // Sets the title of |node|.
    325   void SetTitle(const BookmarkNode* node, const base::string16& title);
    326 
    327   // Sets the URL of |node|.
    328   void SetURL(const BookmarkNode* node, const GURL& url);
    329 
    330   // Sets the date added time of |node|.
    331   void SetDateAdded(const BookmarkNode* node, base::Time date_added);
    332 
    333   // Returns the set of nodes with the |url|.
    334   void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
    335 
    336   // Returns the most recently added node for the |url|. Returns NULL if |url|
    337   // is not bookmarked.
    338   const BookmarkNode* GetMostRecentlyAddedNodeForURL(const GURL& url);
    339 
    340   // Returns true if there are bookmarks, otherwise returns false.
    341   // This method is thread safe.
    342   bool HasBookmarks();
    343 
    344   // Returns true if there is a bookmark with the |url|.
    345   // This method is thread safe.
    346   // See BookmarkService for more details on this.
    347   virtual bool IsBookmarked(const GURL& url) OVERRIDE;
    348 
    349   // Returns all the bookmarked urls and their titles.
    350   // This method is thread safe.
    351   // See BookmarkService for more details on this.
    352   virtual void GetBookmarks(
    353       std::vector<BookmarkService::URLAndTitle>* urls) OVERRIDE;
    354 
    355   // Blocks until loaded; this is NOT invoked on the main thread.
    356   // See BookmarkService for more details on this.
    357   virtual void BlockTillLoaded() OVERRIDE;
    358 
    359   // Returns the node with |id|, or NULL if there is no node with |id|.
    360   const BookmarkNode* GetNodeByID(int64 id) const;
    361 
    362   // Adds a new folder node at the specified position.
    363   const BookmarkNode* AddFolder(const BookmarkNode* parent,
    364                                 int index,
    365                                 const base::string16& title);
    366 
    367   // Adds a url at the specified position.
    368   const BookmarkNode* AddURL(const BookmarkNode* parent,
    369                              int index,
    370                              const base::string16& title,
    371                              const GURL& url);
    372 
    373   // Adds a url with a specific creation date.
    374   const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
    375                                              int index,
    376                                              const base::string16& title,
    377                                              const GURL& url,
    378                                              const base::Time& creation_time);
    379 
    380   // Sorts the children of |parent|, notifying observers by way of the
    381   // BookmarkNodeChildrenReordered method.
    382   void SortChildren(const BookmarkNode* parent);
    383 
    384   // Order the children of |parent| as specified in |ordered_nodes|.  This
    385   // function should only be used to reorder the child nodes of |parent| and
    386   // is not meant to move nodes between different parent. Notifies observers
    387   // using the BookmarkNodeChildrenReordered method.
    388   void ReorderChildren(const BookmarkNode* parent,
    389                        const std::vector<const BookmarkNode*>& ordered_nodes);
    390 
    391   // Sets the date when the folder was modified.
    392   void SetDateFolderModified(const BookmarkNode* node, const base::Time time);
    393 
    394   // Resets the 'date modified' time of the node to 0. This is used during
    395   // importing to exclude the newly created folders from showing up in the
    396   // combobox of most recently modified folders.
    397   void ResetDateFolderModified(const BookmarkNode* node);
    398 
    399   void GetBookmarksWithTitlesMatching(
    400       const base::string16& text,
    401       size_t max_count,
    402       std::vector<BookmarkTitleMatch>* matches);
    403 
    404   // Sets the store to NULL, making it so the BookmarkModel does not persist
    405   // any changes to disk. This is only useful during testing to speed up
    406   // testing.
    407   void ClearStore();
    408 
    409   // Returns the next node ID.
    410   int64 next_node_id() const { return next_node_id_; }
    411 
    412   // Returns the object responsible for tracking the set of expanded nodes in
    413   // the bookmark editor.
    414   BookmarkExpandedStateTracker* expanded_state_tracker() {
    415     return expanded_state_tracker_.get();
    416   }
    417 
    418   // Sets the visibility of one of the permanent nodes. This is set by sync.
    419   void SetPermanentNodeVisible(BookmarkNode::Type type, bool value);
    420 
    421   // Sets/deletes meta info of |node|.
    422   void SetNodeMetaInfo(const BookmarkNode* node,
    423                        const std::string& key,
    424                        const std::string& value);
    425   void SetNodeMetaInfoMap(const BookmarkNode* node,
    426                           const BookmarkNode::MetaInfoMap& meta_info_map);
    427   void DeleteNodeMetaInfo(const BookmarkNode* node,
    428                           const std::string& key);
    429 
    430   // Sets the sync transaction version of |node|.
    431   void SetNodeSyncTransactionVersion(const BookmarkNode* node,
    432                                      int64 sync_transaction_version);
    433 
    434  private:
    435   friend class BookmarkCodecTest;
    436   friend class BookmarkModelTest;
    437   friend class BookmarkStorage;
    438 
    439   // Used to order BookmarkNodes by URL.
    440   class NodeURLComparator {
    441    public:
    442     bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
    443       return n1->url() < n2->url();
    444     }
    445   };
    446 
    447   // Implementation of IsBookmarked. Before calling this the caller must obtain
    448   // a lock on |url_lock_|.
    449   bool IsBookmarkedNoLock(const GURL& url);
    450 
    451   // Removes the node from internal maps and recurses through all children. If
    452   // the node is a url, its url is added to removed_urls.
    453   //
    454   // This does NOT delete the node.
    455   void RemoveNode(BookmarkNode* node, std::set<GURL>* removed_urls);
    456 
    457   // Invoked when loading is finished. Sets |loaded_| and notifies observers.
    458   // BookmarkModel takes ownership of |details|.
    459   void DoneLoading(BookmarkLoadDetails* details);
    460 
    461   // Populates |nodes_ordered_by_url_set_| from root.
    462   void PopulateNodesByURL(BookmarkNode* node);
    463 
    464   // Removes the node from its parent, but does not delete it. No notifications
    465   // are sent. |removed_urls| is populated with the urls which no longer have
    466   // any bookmarks associated with them.
    467   // This method should be called after acquiring |url_lock_|.
    468   void RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
    469                                    std::set<GURL>* removed_urls);
    470 
    471   // Removes the node from its parent, sends notification, and deletes it.
    472   // type specifies how the node should be removed.
    473   void RemoveAndDeleteNode(BookmarkNode* delete_me);
    474 
    475   // Notifies the history backend about urls of removed bookmarks.
    476   void NotifyHistoryAboutRemovedBookmarks(
    477       const std::set<GURL>& removed_bookmark_urls) const;
    478 
    479   // Adds the |node| at |parent| in the specified |index| and notifies its
    480   // observers.
    481   BookmarkNode* AddNode(BookmarkNode* parent,
    482                         int index,
    483                         BookmarkNode* node);
    484 
    485   // Implementation of GetNodeByID.
    486   const BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id) const;
    487 
    488   // Returns true if the parent and index are valid.
    489   bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end);
    490 
    491   // Creates one of the possible permanent nodes (bookmark bar node, other node
    492   // and mobile node) from |type|.
    493   BookmarkPermanentNode* CreatePermanentNode(BookmarkNode::Type type);
    494 
    495   // Notification that a favicon has finished loading. If we can decode the
    496   // favicon, FaviconLoaded is invoked.
    497   void OnFaviconDataAvailable(BookmarkNode* node,
    498                               const chrome::FaviconImageResult& image_result);
    499 
    500   // Invoked from the node to load the favicon. Requests the favicon from the
    501   // favicon service.
    502   void LoadFavicon(BookmarkNode* node);
    503 
    504   // Called to notify the observers that the favicon has been loaded.
    505   void FaviconLoaded(const BookmarkNode* node);
    506 
    507   // If we're waiting on a favicon for node, the load request is canceled.
    508   void CancelPendingFaviconLoadRequests(BookmarkNode* node);
    509 
    510   // content::NotificationObserver:
    511   virtual void Observe(int type,
    512                        const content::NotificationSource& source,
    513                        const content::NotificationDetails& details) OVERRIDE;
    514 
    515   // Generates and returns the next node ID.
    516   int64 generate_next_node_id();
    517 
    518   // Sets the maximum node ID to the given value.
    519   // This is used by BookmarkCodec to report the maximum ID after it's done
    520   // decoding since during decoding codec assigns node IDs.
    521   void set_next_node_id(int64 id) { next_node_id_ = id; }
    522 
    523   // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
    524   // delete the returned object.
    525   BookmarkLoadDetails* CreateLoadDetails();
    526 
    527   content::NotificationRegistrar registrar_;
    528 
    529   Profile* profile_;
    530 
    531   // Whether the initial set of data has been loaded.
    532   bool loaded_;
    533 
    534   // The root node. This contains the bookmark bar node and the 'other' node as
    535   // children.
    536   BookmarkNode root_;
    537 
    538   BookmarkPermanentNode* bookmark_bar_node_;
    539   BookmarkPermanentNode* other_node_;
    540   BookmarkPermanentNode* mobile_node_;
    541 
    542   // The maximum ID assigned to the bookmark nodes in the model.
    543   int64 next_node_id_;
    544 
    545   // The observers.
    546   ObserverList<BookmarkModelObserver> observers_;
    547 
    548   // Set of nodes ordered by URL. This is not a map to avoid copying the
    549   // urls.
    550   // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As
    551   // such, be sure and wrap all usage of it around |url_lock_|.
    552   typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet;
    553   NodesOrderedByURLSet nodes_ordered_by_url_set_;
    554   base::Lock url_lock_;
    555 
    556   // Used for loading favicons.
    557   CancelableTaskTracker cancelable_task_tracker_;
    558 
    559   // Reads/writes bookmarks to disk.
    560   scoped_refptr<BookmarkStorage> store_;
    561 
    562   scoped_ptr<BookmarkIndex> index_;
    563 
    564   base::WaitableEvent loaded_signal_;
    565 
    566   // See description of IsDoingExtensiveChanges above.
    567   int extensive_changes_;
    568 
    569   scoped_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_;
    570 
    571   DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
    572 };
    573 
    574 #endif  // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
    575