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 "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"
29 class BookmarkExpandedStateTracker
;
31 class BookmarkLoadDetails
;
33 class BookmarkModelObserver
;
34 class BookmarkStorage
;
35 struct BookmarkTitleMatch
;
39 class SequencedTaskRunner
;
43 struct FaviconImageResult
;
46 // BookmarkNode ---------------------------------------------------------------
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
> {
66 typedef std::map
<std::string
, std::string
> MetaInfoMap
;
68 static const int64 kInvalidSyncTransactionVersion
;
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
);
75 virtual ~BookmarkNode();
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
;
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.
85 int64
id() const { return id_
; }
86 void set_id(int64 id
) { id_
= id
; }
88 const GURL
& url() const { return url_
; }
89 void set_url(const GURL
& url
) { url_
= url
; }
91 // Returns the favicon's URL. Returns an empty URL if there is no favicon
92 // associated with this bookmark.
93 const GURL
& icon_url() const { return icon_url_
; }
95 Type
type() const { return type_
; }
96 void set_type(Type type
) { type_
= type
; }
98 // Returns the time the node was added.
99 const base::Time
& date_added() const { return date_added_
; }
100 void set_date_added(const base::Time
& date
) { date_added_
= date
; }
102 // Returns the last time the folder was modified. This is only maintained
103 // for folders (including the bookmark bar and other folder).
104 const base::Time
& date_folder_modified() const {
105 return date_folder_modified_
;
107 void set_date_folder_modified(const base::Time
& date
) {
108 date_folder_modified_
= date
;
111 // Convenience for testing if this node represents a folder. A folder is a
112 // node whose type is not URL.
113 bool is_folder() const { return type_
!= URL
; }
114 bool is_url() const { return type_
== URL
; }
116 bool is_favicon_loaded() const { return favicon_state_
== LOADED_FAVICON
; }
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;
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;
135 void set_sync_transaction_version(int64 sync_transaction_version
) {
136 sync_transaction_version_
= sync_transaction_version
;
138 int64
sync_transaction_version() const {
139 return sync_transaction_version_
;
142 // TODO(sky): Consider adding last visit time here, it'll greatly simplify
143 // HistoryContentsProvider.
146 friend class BookmarkModel
;
148 // A helper function to initialize various fields during construction.
149 void Initialize(int64 id
);
151 // Called when the favicon becomes invalid.
152 void InvalidateFavicon();
154 // Sets the favicon's URL.
155 void set_icon_url(const GURL
& icon_url
) {
156 icon_url_
= icon_url
;
159 const gfx::Image
& favicon() const { return favicon_
; }
160 void set_favicon(const gfx::Image
& icon
) { favicon_
= icon
; }
162 FaviconState
favicon_state() const { return favicon_state_
; }
163 void set_favicon_state(FaviconState state
) { favicon_state_
= state
; }
165 CancelableTaskTracker::TaskId
favicon_load_task_id() const {
166 return favicon_load_task_id_
;
168 void set_favicon_load_task_id(CancelableTaskTracker::TaskId id
) {
169 favicon_load_task_id_
= id
;
172 // The unique identifier for this node.
175 // The URL of this node. BookmarkModel maintains maps off this URL, so changes
176 // to the URL must be done through the BookmarkModel.
179 // The type of this node. See enum above.
182 // Date of when this node was created.
183 base::Time date_added_
;
185 // Date of the last modification. Only used for folders.
186 base::Time date_folder_modified_
;
188 // The favicon of this node.
191 // The URL of the node's favicon.
194 // The loading state of the favicon.
195 FaviconState favicon_state_
;
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_
;
201 // A map that stores arbitrary meta information about the node.
202 scoped_ptr
<MetaInfoMap
> meta_info_map_
;
204 // The sync transaction version. Defaults to kInvalidSyncTransactionVersion.
205 int64 sync_transaction_version_
;
207 DISALLOW_COPY_AND_ASSIGN(BookmarkNode
);
210 // BookmarkPermanentNode -------------------------------------------------------
212 // Node used for the permanent folders (excluding the root).
213 class BookmarkPermanentNode
: public BookmarkNode
{
215 explicit BookmarkPermanentNode(int64 id
);
216 virtual ~BookmarkPermanentNode();
218 // WARNING: this code is used for other projects. Contact noyau@ for details.
219 void set_visible(bool value
) { visible_
= value
; }
221 // BookmarkNode overrides:
222 virtual bool IsVisible() const OVERRIDE
;
227 DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNode
);
230 // BookmarkModel --------------------------------------------------------------
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.
236 // An observer may be attached to observe relevant events.
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
{
244 explicit BookmarkModel(Profile
* profile
);
245 virtual ~BookmarkModel();
247 // Invoked prior to destruction to release any necessary resources.
248 virtual void Shutdown() OVERRIDE
;
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
);
255 // Returns true if the model finished loading.
256 bool loaded() const { return loaded_
; }
258 // Returns the root node. The 'bookmark bar' node and 'other' node are
259 // children of the root node.
260 const BookmarkNode
* root_node() { return &root_
; }
262 // Returns the 'bookmark bar' node. This is NULL until loaded.
263 const BookmarkNode
* bookmark_bar_node() { return bookmark_bar_node_
; }
265 // Returns the 'other' node. This is NULL until loaded.
266 const BookmarkNode
* other_node() { return other_node_
; }
268 // Returns the 'mobile' node. This is NULL until loaded.
269 const BookmarkNode
* mobile_node() { return mobile_node_
; }
271 bool is_root_node(const BookmarkNode
* node
) const { return node
== &root_
; }
273 // Returns whether the given |node| is one of the permanent nodes - root node,
274 // 'bookmark bar' node, 'other' node or 'mobile' 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_
;
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();
286 void AddObserver(BookmarkModelObserver
* observer
);
287 void RemoveObserver(BookmarkModelObserver
* observer
);
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();
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.
299 bool IsDoingExtensiveChanges() const { return extensive_changes_
> 0; }
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
);
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
310 // Moves |node| to |new_parent| and inserts it at the given |index|.
311 void Move(const BookmarkNode
* node
,
312 const BookmarkNode
* new_parent
,
315 // Inserts a copy of |node| into |new_parent| at |index|.
316 void Copy(const BookmarkNode
* node
,
317 const BookmarkNode
* new_parent
,
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
);
324 // Sets the title of |node|.
325 void SetTitle(const BookmarkNode
* node
, const base::string16
& title
);
327 // Sets the URL of |node|.
328 void SetURL(const BookmarkNode
* node
, const GURL
& url
);
330 // Sets the date added time of |node|.
331 void SetDateAdded(const BookmarkNode
* node
, base::Time date_added
);
333 // Returns the set of nodes with the |url|.
334 void GetNodesByURL(const GURL
& url
, std::vector
<const BookmarkNode
*>* nodes
);
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
);
340 // Returns true if there are bookmarks, otherwise returns false.
341 // This method is thread safe.
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
;
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
;
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
;
359 // Returns the node with |id|, or NULL if there is no node with |id|.
360 const BookmarkNode
* GetNodeByID(int64 id
) const;
362 // Adds a new folder node at the specified position.
363 const BookmarkNode
* AddFolder(const BookmarkNode
* parent
,
365 const base::string16
& title
);
367 // Adds a url at the specified position.
368 const BookmarkNode
* AddURL(const BookmarkNode
* parent
,
370 const base::string16
& title
,
373 // Adds a url with a specific creation date.
374 const BookmarkNode
* AddURLWithCreationTime(const BookmarkNode
* parent
,
376 const base::string16
& title
,
378 const base::Time
& creation_time
);
380 // Sorts the children of |parent|, notifying observers by way of the
381 // BookmarkNodeChildrenReordered method.
382 void SortChildren(const BookmarkNode
* parent
);
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
);
391 // Sets the date when the folder was modified.
392 void SetDateFolderModified(const BookmarkNode
* node
, const base::Time time
);
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
);
399 void GetBookmarksWithTitlesMatching(
400 const base::string16
& text
,
402 std::vector
<BookmarkTitleMatch
>* matches
);
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
409 // Returns the next node ID.
410 int64
next_node_id() const { return next_node_id_
; }
412 // Returns the object responsible for tracking the set of expanded nodes in
413 // the bookmark editor.
414 BookmarkExpandedStateTracker
* expanded_state_tracker() {
415 return expanded_state_tracker_
.get();
418 // Sets the visibility of one of the permanent nodes. This is set by sync.
419 void SetPermanentNodeVisible(BookmarkNode::Type type
, bool value
);
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
);
430 // Sets the sync transaction version of |node|.
431 void SetNodeSyncTransactionVersion(const BookmarkNode
* node
,
432 int64 sync_transaction_version
);
434 // Returns the profile that corresponds to this BookmarkModel.
435 Profile
* profile() { return profile_
; }
438 friend class BookmarkCodecTest
;
439 friend class BookmarkModelTest
;
440 friend class BookmarkStorage
;
442 // Used to order BookmarkNodes by URL.
443 class NodeURLComparator
{
445 bool operator()(const BookmarkNode
* n1
, const BookmarkNode
* n2
) const {
446 return n1
->url() < n2
->url();
450 // Implementation of IsBookmarked. Before calling this the caller must obtain
451 // a lock on |url_lock_|.
452 bool IsBookmarkedNoLock(const GURL
& url
);
454 // Removes the node from internal maps and recurses through all children. If
455 // the node is a url, its url is added to removed_urls.
457 // This does NOT delete the node.
458 void RemoveNode(BookmarkNode
* node
, std::set
<GURL
>* removed_urls
);
460 // Invoked when loading is finished. Sets |loaded_| and notifies observers.
461 // BookmarkModel takes ownership of |details|.
462 void DoneLoading(BookmarkLoadDetails
* details
);
464 // Populates |nodes_ordered_by_url_set_| from root.
465 void PopulateNodesByURL(BookmarkNode
* node
);
467 // Removes the node from its parent, but does not delete it. No notifications
468 // are sent. |removed_urls| is populated with the urls which no longer have
469 // any bookmarks associated with them.
470 // This method should be called after acquiring |url_lock_|.
471 void RemoveNodeAndGetRemovedUrls(BookmarkNode
* node
,
472 std::set
<GURL
>* removed_urls
);
474 // Removes the node from its parent, sends notification, and deletes it.
475 // type specifies how the node should be removed.
476 void RemoveAndDeleteNode(BookmarkNode
* delete_me
);
478 // Remove |node| from |nodes_ordered_by_url_set_|.
479 void RemoveNodeFromURLSet(BookmarkNode
* node
);
481 // Notifies the history backend about urls of removed bookmarks.
482 void NotifyHistoryAboutRemovedBookmarks(
483 const std::set
<GURL
>& removed_bookmark_urls
) const;
485 // Adds the |node| at |parent| in the specified |index| and notifies its
487 BookmarkNode
* AddNode(BookmarkNode
* parent
,
491 // Implementation of GetNodeByID.
492 const BookmarkNode
* GetNodeByID(const BookmarkNode
* node
, int64 id
) const;
494 // Returns true if the parent and index are valid.
495 bool IsValidIndex(const BookmarkNode
* parent
, int index
, bool allow_end
);
497 // Creates one of the possible permanent nodes (bookmark bar node, other node
498 // and mobile node) from |type|.
499 BookmarkPermanentNode
* CreatePermanentNode(BookmarkNode::Type type
);
501 // Notification that a favicon has finished loading. If we can decode the
502 // favicon, FaviconLoaded is invoked.
503 void OnFaviconDataAvailable(BookmarkNode
* node
,
504 const chrome::FaviconImageResult
& image_result
);
506 // Invoked from the node to load the favicon. Requests the favicon from the
508 void LoadFavicon(BookmarkNode
* node
);
510 // Called to notify the observers that the favicon has been loaded.
511 void FaviconLoaded(const BookmarkNode
* node
);
513 // If we're waiting on a favicon for node, the load request is canceled.
514 void CancelPendingFaviconLoadRequests(BookmarkNode
* node
);
516 // content::NotificationObserver:
517 virtual void Observe(int type
,
518 const content::NotificationSource
& source
,
519 const content::NotificationDetails
& details
) OVERRIDE
;
521 // Generates and returns the next node ID.
522 int64
generate_next_node_id();
524 // Sets the maximum node ID to the given value.
525 // This is used by BookmarkCodec to report the maximum ID after it's done
526 // decoding since during decoding codec assigns node IDs.
527 void set_next_node_id(int64 id
) { next_node_id_
= id
; }
529 // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
530 // delete the returned object.
531 BookmarkLoadDetails
* CreateLoadDetails();
533 content::NotificationRegistrar registrar_
;
537 // Whether the initial set of data has been loaded.
540 // The root node. This contains the bookmark bar node and the 'other' node as
544 BookmarkPermanentNode
* bookmark_bar_node_
;
545 BookmarkPermanentNode
* other_node_
;
546 BookmarkPermanentNode
* mobile_node_
;
548 // The maximum ID assigned to the bookmark nodes in the model.
552 ObserverList
<BookmarkModelObserver
> observers_
;
554 // Set of nodes ordered by URL. This is not a map to avoid copying the
556 // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As
557 // such, be sure and wrap all usage of it around |url_lock_|.
558 typedef std::multiset
<BookmarkNode
*, NodeURLComparator
> NodesOrderedByURLSet
;
559 NodesOrderedByURLSet nodes_ordered_by_url_set_
;
560 base::Lock url_lock_
;
562 // Used for loading favicons.
563 CancelableTaskTracker cancelable_task_tracker_
;
565 // Reads/writes bookmarks to disk.
566 scoped_refptr
<BookmarkStorage
> store_
;
568 scoped_ptr
<BookmarkIndex
> index_
;
570 base::WaitableEvent loaded_signal_
;
572 // See description of IsDoingExtensiveChanges above.
573 int extensive_changes_
;
575 scoped_ptr
<BookmarkExpandedStateTracker
> expanded_state_tracker_
;
577 DISALLOW_COPY_AND_ASSIGN(BookmarkModel
);
580 #endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_