• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
id()85   int64 id() const { return id_; }
set_id(int64 id)86   void set_id(int64 id) { id_ = id; }
87 
url()88   const GURL& url() const { return url_; }
set_url(const GURL & 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.
icon_url()93   const GURL& icon_url() const { return icon_url_; }
94 
type()95   Type type() const { return type_; }
set_type(Type type)96   void set_type(Type type) { type_ = type; }
97 
98   // Returns the time the node was added.
date_added()99   const base::Time& date_added() const { return date_added_; }
set_date_added(const base::Time & date)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).
date_folder_modified()104   const base::Time& date_folder_modified() const {
105     return date_folder_modified_;
106   }
set_date_folder_modified(const base::Time & date)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.
is_folder()113   bool is_folder() const { return type_ != URL; }
is_url()114   bool is_url() const { return type_ == URL; }
115 
is_favicon_loaded()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 
set_sync_transaction_version(int64 sync_transaction_version)135   void set_sync_transaction_version(int64 sync_transaction_version) {
136     sync_transaction_version_ = sync_transaction_version;
137   }
sync_transaction_version()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.
set_icon_url(const GURL & icon_url)155   void set_icon_url(const GURL& icon_url) {
156     icon_url_ = icon_url;
157   }
158 
favicon()159   const gfx::Image& favicon() const { return favicon_; }
set_favicon(const gfx::Image & icon)160   void set_favicon(const gfx::Image& icon) { favicon_ = icon; }
161 
favicon_state()162   FaviconState favicon_state() const { return favicon_state_; }
set_favicon_state(FaviconState state)163   void set_favicon_state(FaviconState state) { favicon_state_ = state; }
164 
favicon_load_task_id()165   CancelableTaskTracker::TaskId favicon_load_task_id() const {
166     return favicon_load_task_id_;
167   }
set_favicon_load_task_id(CancelableTaskTracker::TaskId id)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.
set_visible(bool value)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.
loaded()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.
root_node()260   const BookmarkNode* root_node() { return &root_; }
261 
262   // Returns the 'bookmark bar' node. This is NULL until loaded.
bookmark_bar_node()263   const BookmarkNode* bookmark_bar_node() { return bookmark_bar_node_; }
264 
265   // Returns the 'other' node. This is NULL until loaded.
other_node()266   const BookmarkNode* other_node() { return other_node_; }
267 
268   // Returns the 'mobile' node. This is NULL until loaded.
mobile_node()269   const BookmarkNode* mobile_node() { return mobile_node_; }
270 
is_root_node(const BookmarkNode * node)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.
is_permanent_node(const BookmarkNode * 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.
IsDoingExtensiveChanges()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.
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.
expanded_state_tracker()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:
operator()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.
set_next_node_id(int64 id)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