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.
5 #ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
6 #define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
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 "base/task/cancelable_task_tracker.h"
21 #include "chrome/browser/bookmarks/bookmark_service.h"
22 #include "components/keyed_service/core/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"
29 class BookmarkExpandedStateTracker;
31 class BookmarkLoadDetails;
33 class BookmarkModelObserver;
34 class BookmarkStorage;
35 struct BookmarkTitleMatch;
37 class ScopedGroupBookmarkActions;
40 class SequencedTaskRunner;
44 struct FaviconImageResult;
47 // BookmarkNode ---------------------------------------------------------------
49 // BookmarkNode contains information about a starred entry: title, URL, favicon,
50 // id and type. BookmarkNodes are returned from BookmarkModel.
51 class BookmarkNode : public ui::TreeNode<BookmarkNode> {
67 typedef std::map<std::string, std::string> MetaInfoMap;
69 static const int64 kInvalidSyncTransactionVersion;
71 // Creates a new node with an id of 0 and |url|.
72 explicit BookmarkNode(const GURL& url);
73 // Creates a new node with |id| and |url|.
74 BookmarkNode(int64 id, const GURL& url);
76 virtual ~BookmarkNode();
78 // Set the node's internal title. Note that this neither invokes observers
79 // nor updates any bookmark model this node may be in. For that functionality,
80 // BookmarkModel::SetTitle(..) should be used instead.
81 virtual void SetTitle(const base::string16& title) OVERRIDE;
83 // Returns an unique id for this node.
84 // For bookmark nodes that are managed by the bookmark model, the IDs are
85 // persisted across sessions.
86 int64 id() const { return id_; }
87 void set_id(int64 id) { id_ = id; }
89 const GURL& url() const { return url_; }
90 void set_url(const GURL& url) { url_ = url; }
92 // Returns the favicon's URL. Returns an empty URL if there is no favicon
93 // associated with this bookmark.
94 const GURL& icon_url() const { return icon_url_; }
96 Type type() const { return type_; }
97 void set_type(Type type) { type_ = type; }
99 // Returns the time the node was added.
100 const base::Time& date_added() const { return date_added_; }
101 void set_date_added(const base::Time& date) { date_added_ = date; }
103 // Returns the last time the folder was modified. This is only maintained
104 // for folders (including the bookmark bar and other folder).
105 const base::Time& date_folder_modified() const {
106 return date_folder_modified_;
108 void set_date_folder_modified(const base::Time& date) {
109 date_folder_modified_ = date;
112 // Convenience for testing if this node represents a folder. A folder is a
113 // node whose type is not URL.
114 bool is_folder() const { return type_ != URL; }
115 bool is_url() const { return type_ == URL; }
117 bool is_favicon_loaded() const { return favicon_state_ == LOADED_FAVICON; }
119 // Accessor method for controlling the visibility of a bookmark node/sub-tree.
120 // Note that visibility is not propagated down the tree hierarchy so if a
121 // parent node is marked as invisible, a child node may return "Visible". This
122 // function is primarily useful when traversing the model to generate a UI
123 // representation but we may want to suppress some nodes.
124 virtual bool IsVisible() const;
126 // Gets/sets/deletes value of |key| in the meta info represented by
127 // |meta_info_str_|. Return true if key is found in meta info for gets or
128 // meta info is changed indeed for sets/deletes.
129 bool GetMetaInfo(const std::string& key, std::string* value) const;
130 bool SetMetaInfo(const std::string& key, const std::string& value);
131 bool DeleteMetaInfo(const std::string& key);
132 void SetMetaInfoMap(const MetaInfoMap& meta_info_map);
133 // Returns NULL if there are no values in the map.
134 const MetaInfoMap* GetMetaInfoMap() const;
136 void set_sync_transaction_version(int64 sync_transaction_version) {
137 sync_transaction_version_ = sync_transaction_version;
139 int64 sync_transaction_version() const {
140 return sync_transaction_version_;
143 // TODO(sky): Consider adding last visit time here, it'll greatly simplify
144 // HistoryContentsProvider.
147 friend class BookmarkModel;
149 // A helper function to initialize various fields during construction.
150 void Initialize(int64 id);
152 // Called when the favicon becomes invalid.
153 void InvalidateFavicon();
155 // Sets the favicon's URL.
156 void set_icon_url(const GURL& icon_url) {
157 icon_url_ = icon_url;
160 const gfx::Image& favicon() const { return favicon_; }
161 void set_favicon(const gfx::Image& icon) { favicon_ = icon; }
163 FaviconState favicon_state() const { return favicon_state_; }
164 void set_favicon_state(FaviconState state) { favicon_state_ = state; }
166 base::CancelableTaskTracker::TaskId favicon_load_task_id() const {
167 return favicon_load_task_id_;
169 void set_favicon_load_task_id(base::CancelableTaskTracker::TaskId id) {
170 favicon_load_task_id_ = id;
173 // The unique identifier for this node.
176 // The URL of this node. BookmarkModel maintains maps off this URL, so changes
177 // to the URL must be done through the BookmarkModel.
180 // The type of this node. See enum above.
183 // Date of when this node was created.
184 base::Time date_added_;
186 // Date of the last modification. Only used for folders.
187 base::Time date_folder_modified_;
189 // The favicon of this node.
192 // The URL of the node's favicon.
195 // The loading state of the favicon.
196 FaviconState favicon_state_;
198 // If not base::CancelableTaskTracker::kBadTaskId, it indicates
200 // favicon and the task is tracked by CancelabelTaskTracker.
201 base::CancelableTaskTracker::TaskId favicon_load_task_id_;
203 // A map that stores arbitrary meta information about the node.
204 scoped_ptr<MetaInfoMap> meta_info_map_;
206 // The sync transaction version. Defaults to kInvalidSyncTransactionVersion.
207 int64 sync_transaction_version_;
209 DISALLOW_COPY_AND_ASSIGN(BookmarkNode);
212 // BookmarkPermanentNode -------------------------------------------------------
214 // Node used for the permanent folders (excluding the root).
215 class BookmarkPermanentNode : public BookmarkNode {
217 explicit BookmarkPermanentNode(int64 id);
218 virtual ~BookmarkPermanentNode();
220 // WARNING: this code is used for other projects. Contact noyau@ for details.
221 void set_visible(bool value) { visible_ = value; }
223 // BookmarkNode overrides:
224 virtual bool IsVisible() const OVERRIDE;
229 DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNode);
232 // BookmarkModel --------------------------------------------------------------
234 // BookmarkModel provides a directed acyclic graph of URLs and folders.
235 // Three graphs are provided for the three entry points: those on the 'bookmarks
236 // bar', those in the 'other bookmarks' folder and those in the 'mobile' folder.
238 // An observer may be attached to observe relevant events.
240 // You should NOT directly create a BookmarkModel, instead go through the
241 // BookmarkModelFactory.
242 class BookmarkModel : public content::NotificationObserver,
243 public BookmarkService,
244 public KeyedService {
246 explicit BookmarkModel(Profile* profile);
247 virtual ~BookmarkModel();
249 // Invoked prior to destruction to release any necessary resources.
250 virtual void Shutdown() OVERRIDE;
252 // Loads the bookmarks. This is called upon creation of the
253 // BookmarkModel. You need not invoke this directly.
254 // All load operations will be executed on |task_runner|.
255 void Load(const scoped_refptr<base::SequencedTaskRunner>& task_runner);
257 // Returns true if the model finished loading.
258 bool loaded() const { return loaded_; }
260 // Returns the root node. The 'bookmark bar' node and 'other' node are
261 // children of the root node.
262 const BookmarkNode* root_node() { return &root_; }
264 // Returns the 'bookmark bar' node. This is NULL until loaded.
265 const BookmarkNode* bookmark_bar_node() { return bookmark_bar_node_; }
267 // Returns the 'other' node. This is NULL until loaded.
268 const BookmarkNode* other_node() { return other_node_; }
270 // Returns the 'mobile' node. This is NULL until loaded.
271 const BookmarkNode* mobile_node() { return mobile_node_; }
273 bool is_root_node(const BookmarkNode* node) const { return node == &root_; }
275 // Returns whether the given |node| is one of the permanent nodes - root node,
276 // 'bookmark bar' node, 'other' node or 'mobile' node.
277 bool is_permanent_node(const BookmarkNode* node) const {
278 return node == &root_ ||
279 node == bookmark_bar_node_ ||
280 node == other_node_ ||
281 node == mobile_node_;
284 // Returns the parent the last node was added to. This never returns NULL
285 // (as long as the model is loaded).
286 const BookmarkNode* GetParentForNewNodes();
288 void AddObserver(BookmarkModelObserver* observer);
289 void RemoveObserver(BookmarkModelObserver* observer);
291 // Notifies the observers that an extensive set of changes is about to happen,
292 // such as during import or sync, so they can delay any expensive UI updates
293 // until it's finished.
294 void BeginExtensiveChanges();
295 void EndExtensiveChanges();
297 // Returns true if this bookmark model is currently in a mode where extensive
298 // changes might happen, such as for import and sync. This is helpful for
299 // observers that are created after the mode has started, and want to check
300 // state during their own initializer, such as the NTP.
301 bool IsDoingExtensiveChanges() const { return extensive_changes_ > 0; }
303 // Removes the node at the given |index| from |parent|. Removing a folder node
304 // recursively removes all nodes. Observers are notified immediately.
305 void Remove(const BookmarkNode* parent, int index);
307 // Removes all the non-permanent bookmark nodes. Observers are only notified
308 // when all nodes have been removed. There is no notification for individual
312 // Moves |node| to |new_parent| and inserts it at the given |index|.
313 void Move(const BookmarkNode* node,
314 const BookmarkNode* new_parent,
317 // Inserts a copy of |node| into |new_parent| at |index|.
318 void Copy(const BookmarkNode* node,
319 const BookmarkNode* new_parent,
322 // Returns the favicon for |node|. If the favicon has not yet been
323 // loaded it is loaded and the observer of the model notified when done.
324 const gfx::Image& GetFavicon(const BookmarkNode* node);
326 // Sets the title of |node|.
327 void SetTitle(const BookmarkNode* node, const base::string16& title);
329 // Sets the URL of |node|.
330 void SetURL(const BookmarkNode* node, const GURL& url);
332 // Sets the date added time of |node|.
333 void SetDateAdded(const BookmarkNode* node, base::Time date_added);
335 // Returns the set of nodes with the |url|.
336 void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
338 // Returns the most recently added node for the |url|. Returns NULL if |url|
339 // is not bookmarked.
340 const BookmarkNode* GetMostRecentlyAddedNodeForURL(const GURL& url);
342 // Returns true if there are bookmarks, otherwise returns false.
343 // This method is thread safe.
346 // Returns true if there is a bookmark with the |url|.
347 // This method is thread safe.
348 // See BookmarkService for more details on this.
349 virtual bool IsBookmarked(const GURL& url) OVERRIDE;
351 // Returns all the bookmarked urls and their titles.
352 // This method is thread safe.
353 // See BookmarkService for more details on this.
354 virtual void GetBookmarks(
355 std::vector<BookmarkService::URLAndTitle>* urls) OVERRIDE;
357 // Blocks until loaded; this is NOT invoked on the main thread.
358 // See BookmarkService for more details on this.
359 virtual void BlockTillLoaded() OVERRIDE;
361 // Returns the node with |id|, or NULL if there is no node with |id|.
362 const BookmarkNode* GetNodeByID(int64 id) const;
364 // Adds a new folder node at the specified position.
365 const BookmarkNode* AddFolder(const BookmarkNode* parent,
367 const base::string16& title);
369 // Adds a url at the specified position.
370 const BookmarkNode* AddURL(const BookmarkNode* parent,
372 const base::string16& title,
375 // Adds a url with a specific creation date.
376 const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
378 const base::string16& title,
380 const base::Time& creation_time);
382 // Sorts the children of |parent|, notifying observers by way of the
383 // BookmarkNodeChildrenReordered method.
384 void SortChildren(const BookmarkNode* parent);
386 // Order the children of |parent| as specified in |ordered_nodes|. This
387 // function should only be used to reorder the child nodes of |parent| and
388 // is not meant to move nodes between different parent. Notifies observers
389 // using the BookmarkNodeChildrenReordered method.
390 void ReorderChildren(const BookmarkNode* parent,
391 const std::vector<const BookmarkNode*>& ordered_nodes);
393 // Sets the date when the folder was modified.
394 void SetDateFolderModified(const BookmarkNode* node, const base::Time time);
396 // Resets the 'date modified' time of the node to 0. This is used during
397 // importing to exclude the newly created folders from showing up in the
398 // combobox of most recently modified folders.
399 void ResetDateFolderModified(const BookmarkNode* node);
401 void GetBookmarksWithTitlesMatching(
402 const base::string16& text,
404 std::vector<BookmarkTitleMatch>* matches);
406 // Sets the store to NULL, making it so the BookmarkModel does not persist
407 // any changes to disk. This is only useful during testing to speed up
411 // Returns the next node ID.
412 int64 next_node_id() const { return next_node_id_; }
414 // Returns the object responsible for tracking the set of expanded nodes in
415 // the bookmark editor.
416 BookmarkExpandedStateTracker* expanded_state_tracker() {
417 return expanded_state_tracker_.get();
420 // Sets the visibility of one of the permanent nodes. This is set by sync.
421 void SetPermanentNodeVisible(BookmarkNode::Type type, bool value);
423 // Sets/deletes meta info of |node|.
424 void SetNodeMetaInfo(const BookmarkNode* node,
425 const std::string& key,
426 const std::string& value);
427 void SetNodeMetaInfoMap(const BookmarkNode* node,
428 const BookmarkNode::MetaInfoMap& meta_info_map);
429 void DeleteNodeMetaInfo(const BookmarkNode* node,
430 const std::string& key);
432 // Sets the sync transaction version of |node|.
433 void SetNodeSyncTransactionVersion(const BookmarkNode* node,
434 int64 sync_transaction_version);
436 // Returns the profile that corresponds to this BookmarkModel.
437 Profile* profile() { return profile_; }
440 friend class BookmarkCodecTest;
441 friend class BookmarkModelTest;
442 friend class BookmarkStorage;
443 friend class ScopedGroupBookmarkActions;
445 // Used to order BookmarkNodes by URL.
446 class NodeURLComparator {
448 bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
449 return n1->url() < n2->url();
453 // Implementation of IsBookmarked. Before calling this the caller must obtain
454 // a lock on |url_lock_|.
455 bool IsBookmarkedNoLock(const GURL& url);
457 // Removes the node from internal maps and recurses through all children. If
458 // the node is a url, its url is added to removed_urls.
460 // This does NOT delete the node.
461 void RemoveNode(BookmarkNode* node, std::set<GURL>* removed_urls);
463 // Invoked when loading is finished. Sets |loaded_| and notifies observers.
464 // BookmarkModel takes ownership of |details|.
465 void DoneLoading(BookmarkLoadDetails* details);
467 // Populates |nodes_ordered_by_url_set_| from root.
468 void PopulateNodesByURL(BookmarkNode* node);
470 // Removes the node from its parent, but does not delete it. No notifications
471 // are sent. |removed_urls| is populated with the urls which no longer have
472 // any bookmarks associated with them.
473 // This method should be called after acquiring |url_lock_|.
474 void RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
475 std::set<GURL>* removed_urls);
477 // Removes the node from its parent, sends notification, and deletes it.
478 // type specifies how the node should be removed.
479 void RemoveAndDeleteNode(BookmarkNode* delete_me);
481 // Remove |node| from |nodes_ordered_by_url_set_|.
482 void RemoveNodeFromURLSet(BookmarkNode* node);
484 // Notifies the history backend about urls of removed bookmarks.
485 void NotifyHistoryAboutRemovedBookmarks(
486 const std::set<GURL>& removed_bookmark_urls) const;
488 // Adds the |node| at |parent| in the specified |index| and notifies its
490 BookmarkNode* AddNode(BookmarkNode* parent,
494 // Implementation of GetNodeByID.
495 const BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id) const;
497 // Returns true if the parent and index are valid.
498 bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end);
500 // Creates one of the possible permanent nodes (bookmark bar node, other node
501 // and mobile node) from |type|.
502 BookmarkPermanentNode* CreatePermanentNode(BookmarkNode::Type type);
504 // Notification that a favicon has finished loading. If we can decode the
505 // favicon, FaviconLoaded is invoked.
506 void OnFaviconDataAvailable(BookmarkNode* node,
507 const chrome::FaviconImageResult& image_result);
509 // Invoked from the node to load the favicon. Requests the favicon from the
511 void LoadFavicon(BookmarkNode* node);
513 // Called to notify the observers that the favicon has been loaded.
514 void FaviconLoaded(const BookmarkNode* node);
516 // If we're waiting on a favicon for node, the load request is canceled.
517 void CancelPendingFaviconLoadRequests(BookmarkNode* node);
519 // Notifies the observers that a set of changes initiated by a single user
520 // action is about to happen and has completed.
521 void BeginGroupedChanges();
522 void EndGroupedChanges();
524 // content::NotificationObserver:
525 virtual void Observe(int type,
526 const content::NotificationSource& source,
527 const content::NotificationDetails& details) OVERRIDE;
529 // Generates and returns the next node ID.
530 int64 generate_next_node_id();
532 // Sets the maximum node ID to the given value.
533 // This is used by BookmarkCodec to report the maximum ID after it's done
534 // decoding since during decoding codec assigns node IDs.
535 void set_next_node_id(int64 id) { next_node_id_ = id; }
537 // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
538 // delete the returned object.
539 BookmarkLoadDetails* CreateLoadDetails();
541 content::NotificationRegistrar registrar_;
545 // Whether the initial set of data has been loaded.
548 // The root node. This contains the bookmark bar node and the 'other' node as
552 BookmarkPermanentNode* bookmark_bar_node_;
553 BookmarkPermanentNode* other_node_;
554 BookmarkPermanentNode* mobile_node_;
556 // The maximum ID assigned to the bookmark nodes in the model.
560 ObserverList<BookmarkModelObserver> observers_;
562 // Set of nodes ordered by URL. This is not a map to avoid copying the
564 // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As
565 // such, be sure and wrap all usage of it around |url_lock_|.
566 typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet;
567 NodesOrderedByURLSet nodes_ordered_by_url_set_;
568 base::Lock url_lock_;
570 // Used for loading favicons.
571 base::CancelableTaskTracker cancelable_task_tracker_;
573 // Reads/writes bookmarks to disk.
574 scoped_refptr<BookmarkStorage> store_;
576 scoped_ptr<BookmarkIndex> index_;
578 base::WaitableEvent loaded_signal_;
580 // See description of IsDoingExtensiveChanges above.
581 int extensive_changes_;
583 scoped_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_;
585 DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
588 #endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_