• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetURL()62   const GURL& GetURL() const { return url_; }
63   // Sets the URL to the given value.
SetURL(const GURL & url)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.
id()69   int64 id() const { return id_; }
70   // Sets the id to the given value.
set_id(int64 id)71   void set_id(int64 id) { id_ = id; }
72 
73   // Returns the type of this node.
type()74   BookmarkNode::Type type() const { return type_; }
set_type(BookmarkNode::Type type)75   void set_type(BookmarkNode::Type type) { type_ = type; }
76 
77   // Returns the time the bookmark/folder was added.
date_added()78   const base::Time& date_added() const { return date_added_; }
79   // Sets the time the bookmark/folder was added.
set_date_added(const base::Time & date)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).
date_folder_modified()84   const base::Time& date_folder_modified() const {
85     return date_folder_modified_;
86   }
87   // Sets the last time the folder was modified.
set_date_folder_modified(const base::Time & date)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.
is_folder()94   bool is_folder() const { return type_ != URL; }
95 
96   // Is this a URL?
is_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.
favicon()103   const SkBitmap& favicon() const { return favicon_; }
set_favicon(const SkBitmap & icon)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 
is_favicon_loaded()109   bool is_favicon_loaded() const { return loaded_favicon_; }
set_favicon_loaded(bool value)110   void set_favicon_loaded(bool value) { loaded_favicon_ = value; }
111 
favicon_load_handle()112   HistoryService::Handle favicon_load_handle() const {
113     return favicon_load_handle_;
114   }
set_favicon_load_handle(HistoryService::Handle handle)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.
root_node()188   const BookmarkNode* root_node() { return &root_; }
189 
190   // Returns the bookmark bar node. This is NULL until loaded.
GetBookmarkBarNode()191   const BookmarkNode* GetBookmarkBarNode() { return bookmark_bar_node_; }
192 
193   // Returns the 'other' node. This is NULL until loaded.
other_node()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 
AddObserver(BookmarkModelObserver * observer)200   void AddObserver(BookmarkModelObserver* observer) {
201     observers_.AddObserver(observer);
202   }
203 
RemoveObserver(BookmarkModelObserver * observer)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 
profile()308   Profile* profile() const { return profile_; }
309 
is_root(const BookmarkNode * node)310   bool is_root(const BookmarkNode* node) const { return node == &root_; }
is_bookmark_bar_node(const BookmarkNode * node)311   bool is_bookmark_bar_node(const BookmarkNode* node) const {
312     return node == bookmark_bar_node_;
313   }
is_other_bookmarks_node(const BookmarkNode * node)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.
is_permanent_node(const BookmarkNode * 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.
file_changed()331   bool file_changed() const { return file_changed_; }
332 
333   // Returns the next node ID.
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:
operator()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.
set_next_node_id(int64 id)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