Home | History | Annotate | Download | only in bookmarks
      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_BOOKMARKS_BOOKMARK_MODEL_H_
      6 #define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
      7 #pragma once
      8 
      9 #include "build/build_config.h"
     10 
     11 #include <set>
     12 #include <vector>
     13 
     14 #include "base/observer_list.h"
     15 #include "base/string16.h"
     16 #include "base/synchronization/lock.h"
     17 #include "base/synchronization/waitable_event.h"
     18 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
     19 #include "chrome/browser/bookmarks/bookmark_service.h"
     20 #include "chrome/browser/favicon_service.h"
     21 #include "chrome/browser/history/history.h"
     22 #include "chrome/browser/history/history_types.h"
     23 #include "content/browser/cancelable_request.h"
     24 #include "content/common/notification_registrar.h"
     25 #include "googleurl/src/gurl.h"
     26 #include "testing/gtest/include/gtest/gtest_prod.h"
     27 #include "third_party/skia/include/core/SkBitmap.h"
     28 #include "ui/base/models/tree_node_model.h"
     29 
     30 class BookmarkIndex;
     31 class BookmarkLoadDetails;
     32 class BookmarkModel;
     33 class BookmarkStorage;
     34 class Profile;
     35 
     36 namespace bookmark_utils {
     37 struct TitleMatch;
     38 }
     39 
     40 // BookmarkNode ---------------------------------------------------------------
     41 
     42 // BookmarkNode contains information about a starred entry: title, URL, favicon,
     43 // star id and type. BookmarkNodes are returned from a BookmarkModel.
     44 //
     45 class BookmarkNode : public ui::TreeNode<BookmarkNode> {
     46   friend class BookmarkModel;
     47 
     48  public:
     49   enum Type {
     50     URL,
     51     FOLDER,
     52     BOOKMARK_BAR,
     53     OTHER_NODE
     54   };
     55   // Creates a new node with the specified url and id of 0
     56   explicit BookmarkNode(const GURL& url);
     57   // Creates a new node with the specified url and id.
     58   BookmarkNode(int64 id, const GURL& url);
     59   virtual ~BookmarkNode();
     60 
     61   // Returns the URL.
     62   const GURL& GetURL() const { return url_; }
     63   // Sets the URL to the given value.
     64   void SetURL(const GURL& url) { url_ = url; }
     65 
     66   // Returns a unique id for this node.
     67   // For bookmark nodes that are managed by the bookmark model, the IDs are
     68   // persisted across sessions.
     69   int64 id() const { return id_; }
     70   // Sets the id to the given value.
     71   void set_id(int64 id) { id_ = id; }
     72 
     73   // Returns the type of this node.
     74   BookmarkNode::Type type() const { return type_; }
     75   void set_type(BookmarkNode::Type type) { type_ = type; }
     76 
     77   // Returns the time the bookmark/folder was added.
     78   const base::Time& date_added() const { return date_added_; }
     79   // Sets the time the bookmark/folder was added.
     80   void set_date_added(const base::Time& date) { date_added_ = date; }
     81 
     82   // Returns the last time the folder was modified. This is only maintained
     83   // for folders (including the bookmark and other folder).
     84   const base::Time& date_folder_modified() const {
     85     return date_folder_modified_;
     86   }
     87   // Sets the last time the folder was modified.
     88   void set_date_folder_modified(const base::Time& date) {
     89     date_folder_modified_ = date;
     90   }
     91 
     92   // Convenience for testing if this nodes represents a folder. A folder is a
     93   // node whose type is not URL.
     94   bool is_folder() const { return type_ != URL; }
     95 
     96   // Is this a URL?
     97   bool is_url() const { return type_ == URL; }
     98 
     99   // Returns the favicon. In nearly all cases you should use the method
    100   // BookmarkModel::GetFavicon rather than this. BookmarkModel::GetFavicon
    101   // takes care of loading the favicon if it isn't already loaded, where as
    102   // this does not.
    103   const SkBitmap& favicon() const { return favicon_; }
    104   void set_favicon(const SkBitmap& icon) { favicon_ = icon; }
    105 
    106   // The following methods are used by the bookmark model, and are not
    107   // really useful outside of it.
    108 
    109   bool is_favicon_loaded() const { return loaded_favicon_; }
    110   void set_favicon_loaded(bool value) { loaded_favicon_ = value; }
    111 
    112   HistoryService::Handle favicon_load_handle() const {
    113     return favicon_load_handle_;
    114   }
    115   void set_favicon_load_handle(HistoryService::Handle handle) {
    116     favicon_load_handle_ = handle;
    117   }
    118 
    119   // Called when the favicon becomes invalid.
    120   void InvalidateFavicon();
    121 
    122   // Resets the properties of the node from the supplied entry.
    123   // This is used by the bookmark model and not really useful outside of it.
    124   void Reset(const history::StarredEntry& entry);
    125 
    126   // TODO(sky): Consider adding last visit time here, it'll greatly simplify
    127   // HistoryContentsProvider.
    128 
    129  private:
    130   // helper to initialize various fields during construction.
    131   void Initialize(int64 id);
    132 
    133   // Unique identifier for this node.
    134   int64 id_;
    135 
    136   // Whether the favicon has been loaded.
    137   bool loaded_favicon_;
    138 
    139   // The favicon.
    140   SkBitmap favicon_;
    141 
    142   // If non-zero, it indicates we're loading the favicon and this is the handle
    143   // from the HistoryService.
    144   HistoryService::Handle favicon_load_handle_;
    145 
    146   // The URL. BookmarkModel maintains maps off this URL, it is important that
    147   // changes to the URL is done through the bookmark model.
    148   GURL url_;
    149 
    150   // Type of node.
    151   BookmarkNode::Type type_;
    152 
    153   // Date we were created.
    154   base::Time date_added_;
    155 
    156   // Time last modified. Only used for folders.
    157   base::Time date_folder_modified_;
    158 
    159   DISALLOW_COPY_AND_ASSIGN(BookmarkNode);
    160 };
    161 
    162 // BookmarkModel --------------------------------------------------------------
    163 
    164 // BookmarkModel provides a directed acyclic graph of the starred entries
    165 // and folders. Two graphs are provided for the two entry points: those on
    166 // the bookmark bar, and those in the other folder.
    167 //
    168 // An observer may be attached to observer relevant events.
    169 //
    170 // You should NOT directly create a BookmarkModel, instead go through the
    171 // Profile.
    172 
    173 class BookmarkModel : public NotificationObserver, public BookmarkService {
    174   friend class BookmarkCodecTest;
    175   friend class BookmarkModelTest;
    176   friend class BookmarkStorage;
    177 
    178  public:
    179   explicit BookmarkModel(Profile* profile);
    180   virtual ~BookmarkModel();
    181 
    182   // Loads the bookmarks. This is called by Profile upon creation of the
    183   // BookmarkModel. You need not invoke this directly.
    184   void Load();
    185 
    186   // Returns the root node. The bookmark bar node and other node are children of
    187   // the root node.
    188   const BookmarkNode* root_node() { return &root_; }
    189 
    190   // Returns the bookmark bar node. This is NULL until loaded.
    191   const BookmarkNode* GetBookmarkBarNode() { return bookmark_bar_node_; }
    192 
    193   // Returns the 'other' node. This is NULL until loaded.
    194   const BookmarkNode* other_node() { return other_node_; }
    195 
    196   // Returns the parent the last node was added to. This never returns NULL
    197   // (as long as the model is loaded).
    198   const BookmarkNode* GetParentForNewNodes();
    199 
    200   void AddObserver(BookmarkModelObserver* observer) {
    201     observers_.AddObserver(observer);
    202   }
    203 
    204   void RemoveObserver(BookmarkModelObserver* observer) {
    205     observers_.RemoveObserver(observer);
    206   }
    207 
    208   // Notify the observes that an import is about to happen, so they can
    209   // delay any expensive UI updates until it is finished.
    210   void BeginImportMode();
    211   void EndImportMode();
    212 
    213   // Unstars or deletes the specified entry. Removing a folder entry recursively
    214   // unstars all nodes. Observers are notified immediately.
    215   void Remove(const BookmarkNode* parent, int index);
    216 
    217   // Moves the specified entry to a new location.
    218   void Move(const BookmarkNode* node,
    219             const BookmarkNode* new_parent,
    220             int index);
    221 
    222   // Duplicates a bookmark node and inserts it at a new location.
    223   void Copy(const BookmarkNode* node,
    224             const BookmarkNode* new_parent,
    225             int index);
    226 
    227   // Returns the favicon for |node|. If the favicon has not yet been
    228   // loaded it is loaded and the observer of the model notified when done.
    229   const SkBitmap& GetFavicon(const BookmarkNode* node);
    230 
    231   // Sets the title of the specified node.
    232   void SetTitle(const BookmarkNode* node, const string16& title);
    233 
    234   // Sets the URL of the specified bookmark node.
    235   void SetURL(const BookmarkNode* node, const GURL& url);
    236 
    237   // Returns true if the model finished loading.
    238   virtual bool IsLoaded();
    239 
    240   // Returns the set of nodes with the specified URL.
    241   void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
    242 
    243   // Returns the most recently added node for the url. Returns NULL if url is
    244   // not bookmarked.
    245   const BookmarkNode* GetMostRecentlyAddedNodeForURL(const GURL& url);
    246 
    247   // Returns all the bookmarked urls. This method is thread safe.
    248   virtual void GetBookmarks(std::vector<GURL>* urls);
    249 
    250   // Returns true if there are bookmarks, otherwise returns false. This method
    251   // is thread safe.
    252   bool HasBookmarks();
    253 
    254   // Returns true if there is a bookmark for the specified URL. This method is
    255   // thread safe. See BookmarkService for more details on this.
    256   virtual bool IsBookmarked(const GURL& url);
    257 
    258   // Blocks until loaded; this is NOT invoked on the main thread. See
    259   // BookmarkService for more details on this.
    260   virtual void BlockTillLoaded();
    261 
    262   // Returns the node with the specified id, or NULL if there is no node with
    263   // the specified id.
    264   const BookmarkNode* GetNodeByID(int64 id);
    265 
    266   // Adds a new folder node at the specified position.
    267   const BookmarkNode* AddFolder(const BookmarkNode* parent,
    268                                 int index,
    269                                 const string16& title);
    270 
    271   // Adds a url at the specified position.
    272   const BookmarkNode* AddURL(const BookmarkNode* parent,
    273                              int index,
    274                              const string16& title,
    275                              const GURL& url);
    276 
    277   // Adds a url with a specific creation date.
    278   const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
    279                                              int index,
    280                                              const string16& title,
    281                                              const GURL& url,
    282                                              const base::Time& creation_time);
    283 
    284   // Sorts the children of |parent|, notifying observers by way of the
    285   // BookmarkNodeChildrenReordered method.
    286   void SortChildren(const BookmarkNode* parent);
    287 
    288   // This is the convenience that makes sure the url is starred or not starred.
    289   // If is_starred is false, all bookmarks for URL are removed. If is_starred is
    290   // true and there are no bookmarks for url, a bookmark is created.
    291   void SetURLStarred(const GURL& url,
    292                      const string16& title,
    293                      bool is_starred);
    294 
    295   // Sets the date modified time of the specified node.
    296   void SetDateFolderModified(const BookmarkNode* parent, const base::Time time);
    297 
    298   // Resets the 'date modified' time of the node to 0. This is used during
    299   // importing to exclude the newly created folders from showing up in the
    300   // combobox of most recently modified folders.
    301   void ResetDateFolderModified(const BookmarkNode* node);
    302 
    303   void GetBookmarksWithTitlesMatching(
    304       const string16& text,
    305       size_t max_count,
    306       std::vector<bookmark_utils::TitleMatch>* matches);
    307 
    308   Profile* profile() const { return profile_; }
    309 
    310   bool is_root(const BookmarkNode* node) const { return node == &root_; }
    311   bool is_bookmark_bar_node(const BookmarkNode* node) const {
    312     return node == bookmark_bar_node_;
    313   }
    314   bool is_other_bookmarks_node(const BookmarkNode* node) const {
    315     return node == other_node_;
    316   }
    317   // Returns whether the given node is one of the permanent nodes - root node,
    318   // bookmark bar node or other bookmarks node.
    319   bool is_permanent_node(const BookmarkNode* node) const {
    320     return is_root(node) ||
    321            is_bookmark_bar_node(node) ||
    322            is_other_bookmarks_node(node);
    323   }
    324 
    325   // Sets the store to NULL, making it so the BookmarkModel does not persist
    326   // any changes to disk. This is only useful during testing to speed up
    327   // testing.
    328   void ClearStore();
    329 
    330   // Returns whether the bookmarks file changed externally.
    331   bool file_changed() const { return file_changed_; }
    332 
    333   // Returns the next node ID.
    334   int64 next_node_id() const { return next_node_id_; }
    335 
    336  private:
    337   // Used to order BookmarkNodes by URL.
    338   class NodeURLComparator {
    339    public:
    340     bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
    341       return n1->GetURL() < n2->GetURL();
    342     }
    343   };
    344 
    345   // Implementation of IsBookmarked. Before calling this the caller must
    346   // obtain a lock on url_lock_.
    347   bool IsBookmarkedNoLock(const GURL& url);
    348 
    349   // Overriden to notify the observer the favicon has been loaded.
    350   void FaviconLoaded(const BookmarkNode* node);
    351 
    352   // Removes the node from internal maps and recurses through all children. If
    353   // the node is a url, its url is added to removed_urls.
    354   //
    355   // This does NOT delete the node.
    356   void RemoveNode(BookmarkNode* node, std::set<GURL>* removed_urls);
    357 
    358   // Invoked when loading is finished. Sets loaded_ and notifies observers.
    359   // BookmarkModel takes ownership of |details|.
    360   void DoneLoading(BookmarkLoadDetails* details);
    361 
    362   // Populates nodes_ordered_by_url_set_ from root.
    363   void PopulateNodesByURL(BookmarkNode* node);
    364 
    365   // Removes the node from its parent, sends notification, and deletes it.
    366   // type specifies how the node should be removed.
    367   void RemoveAndDeleteNode(BookmarkNode* delete_me);
    368 
    369   // Adds the node at the specified position and sends notification. If
    370   // was_bookmarked is true, it indicates a bookmark already existed for the
    371   // URL.
    372   BookmarkNode* AddNode(BookmarkNode* parent,
    373                         int index,
    374                         BookmarkNode* node,
    375                         bool was_bookmarked);
    376 
    377   // Implementation of GetNodeByID.
    378   const BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id);
    379 
    380   // Returns true if the parent and index are valid.
    381   bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end);
    382 
    383   // Creates the bookmark bar/other nodes. These call into
    384   // CreateRootNodeFromStarredEntry.
    385   BookmarkNode* CreateBookmarkNode();
    386   BookmarkNode* CreateOtherBookmarksNode();
    387 
    388   // Creates a root node (either the bookmark bar node or other node) from the
    389   // specified starred entry.
    390   BookmarkNode* CreateRootNodeFromStarredEntry(
    391       const history::StarredEntry& entry);
    392 
    393   // Notification that a favicon has finished loading. If we can decode the
    394   // favicon, FaviconLoaded is invoked.
    395   void OnFaviconDataAvailable(FaviconService::Handle handle,
    396                               history::FaviconData favicon);
    397 
    398   // Invoked from the node to load the favicon. Requests the favicon from the
    399   // favicon service.
    400   void LoadFavicon(BookmarkNode* node);
    401 
    402   // If we're waiting on a favicon for node, the load request is canceled.
    403   void CancelPendingFaviconLoadRequests(BookmarkNode* node);
    404 
    405   // NotificationObserver.
    406   virtual void Observe(NotificationType type,
    407                        const NotificationSource& source,
    408                        const NotificationDetails& details);
    409 
    410   // Generates and returns the next node ID.
    411   int64 generate_next_node_id();
    412 
    413   // Sets the maximum node ID to the given value.
    414   // This is used by BookmarkCodec to report the maximum ID after it's done
    415   // decoding since during decoding codec assigns node IDs.
    416   void set_next_node_id(int64 id) { next_node_id_ = id; }
    417 
    418   // Records that the bookmarks file was changed externally.
    419   void SetFileChanged();
    420 
    421   // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
    422   // delete the returned object.
    423   BookmarkLoadDetails* CreateLoadDetails();
    424 
    425   NotificationRegistrar registrar_;
    426 
    427   Profile* profile_;
    428 
    429   // Whether the initial set of data has been loaded.
    430   bool loaded_;
    431 
    432   // Whether the bookmarks file was changed externally. This is set after
    433   // loading is complete and once set the value never changes.
    434   bool file_changed_;
    435 
    436   // The root node. This contains the bookmark bar node and the 'other' node as
    437   // children.
    438   BookmarkNode root_;
    439 
    440   BookmarkNode* bookmark_bar_node_;
    441   BookmarkNode* other_node_;
    442 
    443   // The maximum ID assigned to the bookmark nodes in the model.
    444   int64 next_node_id_;
    445 
    446   // The observers.
    447   ObserverList<BookmarkModelObserver> observers_;
    448 
    449   // Set of nodes ordered by URL. This is not a map to avoid copying the
    450   // urls.
    451   // WARNING: nodes_ordered_by_url_set_ is accessed on multiple threads. As
    452   // such, be sure and wrap all usage of it around url_lock_.
    453   typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet;
    454   NodesOrderedByURLSet nodes_ordered_by_url_set_;
    455   base::Lock url_lock_;
    456 
    457   // Used for loading favicons and the empty history request.
    458   CancelableRequestConsumerTSimple<BookmarkNode*> load_consumer_;
    459 
    460   // Reads/writes bookmarks to disk.
    461   scoped_refptr<BookmarkStorage> store_;
    462 
    463   scoped_ptr<BookmarkIndex> index_;
    464 
    465   base::WaitableEvent loaded_signal_;
    466 
    467   DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
    468 };
    469 
    470 #endif  // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
    471