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