1 // Copyright 2014 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 COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_H_
6 #define COMPONENTS_BOOKMARKS_BROWSER_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 "components/bookmarks/browser/bookmark_client.h"
21 #include "components/bookmarks/browser/bookmark_node.h"
22 #include "components/keyed_service/core/keyed_service.h"
23 #include "ui/gfx/image/image.h"
26 class BookmarkModelObserver
;
31 class SequencedTaskRunner
;
35 class BookmarkCodecTest
;
36 class BookmarkExpandedStateTracker
;
38 class BookmarkLoadDetails
;
39 class BookmarkStorage
;
40 class ScopedGroupBookmarkActions
;
44 namespace favicon_base
{
45 struct FaviconImageResult
;
49 class TestBookmarkClient
;
52 // BookmarkModel --------------------------------------------------------------
54 // BookmarkModel provides a directed acyclic graph of URLs and folders.
55 // Three graphs are provided for the three entry points: those on the 'bookmarks
56 // bar', those in the 'other bookmarks' folder and those in the 'mobile' folder.
58 // An observer may be attached to observe relevant events.
60 // You should NOT directly create a BookmarkModel, instead go through the
61 // BookmarkModelFactory.
62 class BookmarkModel
: public KeyedService
{
69 explicit BookmarkModel(bookmarks::BookmarkClient
* client
);
70 virtual ~BookmarkModel();
73 virtual void Shutdown() OVERRIDE
;
75 // Loads the bookmarks. This is called upon creation of the
76 // BookmarkModel. You need not invoke this directly.
77 // All load operations will be executed on |io_task_runner| and the completion
78 // callback will be called from |ui_task_runner|.
79 void Load(PrefService
* pref_service
,
80 const std::string
& accept_languages
,
81 const base::FilePath
& profile_path
,
82 const scoped_refptr
<base::SequencedTaskRunner
>& io_task_runner
,
83 const scoped_refptr
<base::SequencedTaskRunner
>& ui_task_runner
);
85 // Returns true if the model finished loading.
86 bool loaded() const { return loaded_
; }
88 // Returns the root node. The 'bookmark bar' node and 'other' node are
89 // children of the root node.
90 const BookmarkNode
* root_node() const { return &root_
; }
92 // Returns the 'bookmark bar' node. This is NULL until loaded.
93 const BookmarkNode
* bookmark_bar_node() const { return bookmark_bar_node_
; }
95 // Returns the 'other' node. This is NULL until loaded.
96 const BookmarkNode
* other_node() const { return other_node_
; }
98 // Returns the 'mobile' node. This is NULL until loaded.
99 const BookmarkNode
* mobile_node() const { return mobile_node_
; }
101 bool is_root_node(const BookmarkNode
* node
) const { return node
== &root_
; }
103 // Returns whether the given |node| is one of the permanent nodes - root node,
104 // 'bookmark bar' node, 'other' node or 'mobile' node, or one of the root
105 // nodes supplied by the |client_|.
106 bool is_permanent_node(const BookmarkNode
* node
) const {
107 return node
&& (node
== &root_
|| node
->parent() == &root_
);
110 // Returns the parent the last node was added to. This never returns NULL
111 // (as long as the model is loaded).
112 const BookmarkNode
* GetParentForNewNodes();
114 void AddObserver(BookmarkModelObserver
* observer
);
115 void RemoveObserver(BookmarkModelObserver
* observer
);
117 // Notifies the observers that an extensive set of changes is about to happen,
118 // such as during import or sync, so they can delay any expensive UI updates
119 // until it's finished.
120 void BeginExtensiveChanges();
121 void EndExtensiveChanges();
123 // Returns true if this bookmark model is currently in a mode where extensive
124 // changes might happen, such as for import and sync. This is helpful for
125 // observers that are created after the mode has started, and want to check
126 // state during their own initializer, such as the NTP.
127 bool IsDoingExtensiveChanges() const { return extensive_changes_
> 0; }
129 // Removes the node at the given |index| from |parent|. Removing a folder node
130 // recursively removes all nodes. Observers are notified immediately.
131 void Remove(const BookmarkNode
* parent
, int index
);
133 // Removes all the non-permanent bookmark nodes that are editable by the user.
134 // Observers are only notified when all nodes have been removed. There is no
135 // notification for individual node removals.
136 void RemoveAllUserBookmarks();
138 // Moves |node| to |new_parent| and inserts it at the given |index|.
139 void Move(const BookmarkNode
* node
,
140 const BookmarkNode
* new_parent
,
143 // Inserts a copy of |node| into |new_parent| at |index|.
144 void Copy(const BookmarkNode
* node
,
145 const BookmarkNode
* new_parent
,
148 // Returns the favicon for |node|. If the favicon has not yet been
149 // loaded it is loaded and the observer of the model notified when done.
150 const gfx::Image
& GetFavicon(const BookmarkNode
* node
);
152 // Returns the type of the favicon for |node|. If the favicon has not yet
153 // been loaded, it returns |favicon_base::INVALID_ICON|.
154 favicon_base::IconType
GetFaviconType(const BookmarkNode
* node
);
156 // Sets the title of |node|.
157 void SetTitle(const BookmarkNode
* node
, const base::string16
& title
);
159 // Sets the URL of |node|.
160 void SetURL(const BookmarkNode
* node
, const GURL
& url
);
162 // Sets the date added time of |node|.
163 void SetDateAdded(const BookmarkNode
* node
, base::Time date_added
);
165 // Returns the set of nodes with the |url|.
166 void GetNodesByURL(const GURL
& url
, std::vector
<const BookmarkNode
*>* nodes
);
168 // Returns the most recently added user node for the |url|; urls from any
169 // nodes that are not editable by the user are never returned by this call.
170 // Returns NULL if |url| is not bookmarked.
171 const BookmarkNode
* GetMostRecentlyAddedUserNodeForURL(const GURL
& url
);
173 // Returns true if there are bookmarks, otherwise returns false.
174 // This method is thread safe.
177 // Returns true if the specified URL is bookmarked.
179 // If not on the main thread you *must* invoke BlockTillLoaded first.
180 bool IsBookmarked(const GURL
& url
);
182 // Returns, by reference in |bookmarks|, the set of bookmarked urls and their
183 // titles. This returns the unique set of URLs. For example, if two bookmarks
184 // reference the same URL only one entry is added not matter the titles are
187 // If not on the main thread you *must* invoke BlockTillLoaded first.
188 void GetBookmarks(std::vector
<BookmarkModel::URLAndTitle
>* urls
);
190 // Blocks until loaded. This is intended for usage on a thread other than
192 void BlockTillLoaded();
194 // Adds a new folder node at the specified position.
195 const BookmarkNode
* AddFolder(const BookmarkNode
* parent
,
197 const base::string16
& title
);
199 // Adds a new folder with meta info.
200 const BookmarkNode
* AddFolderWithMetaInfo(
201 const BookmarkNode
* parent
,
203 const base::string16
& title
,
204 const BookmarkNode::MetaInfoMap
* meta_info
);
206 // Adds a url at the specified position.
207 const BookmarkNode
* AddURL(const BookmarkNode
* parent
,
209 const base::string16
& title
,
212 // Adds a url with a specific creation date and meta info.
213 const BookmarkNode
* AddURLWithCreationTimeAndMetaInfo(
214 const BookmarkNode
* parent
,
216 const base::string16
& title
,
218 const base::Time
& creation_time
,
219 const BookmarkNode::MetaInfoMap
* meta_info
);
221 // Sorts the children of |parent|, notifying observers by way of the
222 // BookmarkNodeChildrenReordered method.
223 void SortChildren(const BookmarkNode
* parent
);
225 // Order the children of |parent| as specified in |ordered_nodes|. This
226 // function should only be used to reorder the child nodes of |parent| and
227 // is not meant to move nodes between different parent. Notifies observers
228 // using the BookmarkNodeChildrenReordered method.
229 void ReorderChildren(const BookmarkNode
* parent
,
230 const std::vector
<const BookmarkNode
*>& ordered_nodes
);
232 // Sets the date when the folder was modified.
233 void SetDateFolderModified(const BookmarkNode
* node
, const base::Time time
);
235 // Resets the 'date modified' time of the node to 0. This is used during
236 // importing to exclude the newly created folders from showing up in the
237 // combobox of most recently modified folders.
238 void ResetDateFolderModified(const BookmarkNode
* node
);
240 // Returns up to |max_count| of bookmarks containing each term from |text|
241 // in either the title or the URL.
242 void GetBookmarksMatching(const base::string16
& text
,
244 std::vector
<bookmarks::BookmarkMatch
>* matches
);
246 // Sets the store to NULL, making it so the BookmarkModel does not persist
247 // any changes to disk. This is only useful during testing to speed up
251 // Returns the next node ID.
252 int64
next_node_id() const { return next_node_id_
; }
254 // Returns the object responsible for tracking the set of expanded nodes in
255 // the bookmark editor.
256 bookmarks::BookmarkExpandedStateTracker
* expanded_state_tracker() {
257 return expanded_state_tracker_
.get();
260 // Sets the visibility of one of the permanent nodes (unless the node must
261 // always be visible, see |BookmarkClient::IsPermanentNodeVisible| for more
262 // details). This is set by sync.
263 void SetPermanentNodeVisible(BookmarkNode::Type type
, bool value
);
265 // Returns the permanent node of type |type|.
266 const BookmarkPermanentNode
* PermanentNode(BookmarkNode::Type type
);
268 // Sets/deletes meta info of |node|.
269 void SetNodeMetaInfo(const BookmarkNode
* node
,
270 const std::string
& key
,
271 const std::string
& value
);
272 void SetNodeMetaInfoMap(const BookmarkNode
* node
,
273 const BookmarkNode::MetaInfoMap
& meta_info_map
);
274 void DeleteNodeMetaInfo(const BookmarkNode
* node
,
275 const std::string
& key
);
277 // Sets the sync transaction version of |node|.
278 void SetNodeSyncTransactionVersion(const BookmarkNode
* node
,
279 int64 sync_transaction_version
);
281 // Notify BookmarkModel that the favicons for |urls| have changed and have to
282 // be refetched. This notification is sent by BookmarkClient.
283 void OnFaviconChanged(const std::set
<GURL
>& urls
);
285 // Returns the client used by this BookmarkModel.
286 bookmarks::BookmarkClient
* client() const { return client_
; }
289 friend class bookmarks::BookmarkCodecTest
;
290 friend class bookmarks::BookmarkStorage
;
291 friend class bookmarks::ScopedGroupBookmarkActions
;
292 friend class test::TestBookmarkClient
;
294 // Used to order BookmarkNodes by URL.
295 class NodeURLComparator
{
297 bool operator()(const BookmarkNode
* n1
, const BookmarkNode
* n2
) const {
298 return n1
->url() < n2
->url();
302 // Implementation of IsBookmarked. Before calling this the caller must obtain
303 // a lock on |url_lock_|.
304 bool IsBookmarkedNoLock(const GURL
& url
);
306 // Removes the node from internal maps and recurses through all children. If
307 // the node is a url, its url is added to removed_urls.
309 // This does NOT delete the node.
310 void RemoveNode(BookmarkNode
* node
, std::set
<GURL
>* removed_urls
);
312 // Invoked when loading is finished. Sets |loaded_| and notifies observers.
313 // BookmarkModel takes ownership of |details|.
314 void DoneLoading(scoped_ptr
<bookmarks::BookmarkLoadDetails
> details
);
316 // Populates |nodes_ordered_by_url_set_| from root.
317 void PopulateNodesByURL(BookmarkNode
* node
);
319 // Removes the node from its parent, but does not delete it. No notifications
320 // are sent. |removed_urls| is populated with the urls which no longer have
321 // any bookmarks associated with them.
322 // This method should be called after acquiring |url_lock_|.
323 void RemoveNodeAndGetRemovedUrls(BookmarkNode
* node
,
324 std::set
<GURL
>* removed_urls
);
326 // Removes the node from its parent, sends notification, and deletes it.
327 // type specifies how the node should be removed.
328 void RemoveAndDeleteNode(BookmarkNode
* delete_me
);
330 // Remove |node| from |nodes_ordered_by_url_set_|.
331 void RemoveNodeFromURLSet(BookmarkNode
* node
);
333 // Adds the |node| at |parent| in the specified |index| and notifies its
335 BookmarkNode
* AddNode(BookmarkNode
* parent
,
339 // Returns true if the parent and index are valid.
340 bool IsValidIndex(const BookmarkNode
* parent
, int index
, bool allow_end
);
342 // Creates one of the possible permanent nodes (bookmark bar node, other node
343 // and mobile node) from |type|.
344 BookmarkPermanentNode
* CreatePermanentNode(BookmarkNode::Type type
);
346 // Notification that a favicon has finished loading. If we can decode the
347 // favicon, FaviconLoaded is invoked.
348 void OnFaviconDataAvailable(
350 favicon_base::IconType icon_type
,
351 const favicon_base::FaviconImageResult
& image_result
);
353 // Invoked from the node to load the favicon. Requests the favicon from the
355 void LoadFavicon(BookmarkNode
* node
, favicon_base::IconType icon_type
);
357 // Called to notify the observers that the favicon has been loaded.
358 void FaviconLoaded(const BookmarkNode
* node
);
360 // If we're waiting on a favicon for node, the load request is canceled.
361 void CancelPendingFaviconLoadRequests(BookmarkNode
* node
);
363 // Notifies the observers that a set of changes initiated by a single user
364 // action is about to happen and has completed.
365 void BeginGroupedChanges();
366 void EndGroupedChanges();
368 // Generates and returns the next node ID.
369 int64
generate_next_node_id();
371 // Sets the maximum node ID to the given value.
372 // This is used by BookmarkCodec to report the maximum ID after it's done
373 // decoding since during decoding codec assigns node IDs.
374 void set_next_node_id(int64 id
) { next_node_id_
= id
; }
376 // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
377 // delete the returned object.
378 scoped_ptr
<bookmarks::BookmarkLoadDetails
> CreateLoadDetails(
379 const std::string
& accept_languages
);
381 bookmarks::BookmarkClient
* const client_
;
383 // Whether the initial set of data has been loaded.
386 // The root node. This contains the bookmark bar node, the 'other' node and
387 // the mobile node as children.
390 BookmarkPermanentNode
* bookmark_bar_node_
;
391 BookmarkPermanentNode
* other_node_
;
392 BookmarkPermanentNode
* mobile_node_
;
394 // The maximum ID assigned to the bookmark nodes in the model.
398 ObserverList
<BookmarkModelObserver
> observers_
;
400 // Set of nodes ordered by URL. This is not a map to avoid copying the
402 // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As
403 // such, be sure and wrap all usage of it around |url_lock_|.
404 typedef std::multiset
<BookmarkNode
*, NodeURLComparator
> NodesOrderedByURLSet
;
405 NodesOrderedByURLSet nodes_ordered_by_url_set_
;
406 base::Lock url_lock_
;
408 // Used for loading favicons.
409 base::CancelableTaskTracker cancelable_task_tracker_
;
411 // Reads/writes bookmarks to disk.
412 scoped_ptr
<bookmarks::BookmarkStorage
> store_
;
414 scoped_ptr
<bookmarks::BookmarkIndex
> index_
;
416 base::WaitableEvent loaded_signal_
;
418 // See description of IsDoingExtensiveChanges above.
419 int extensive_changes_
;
421 scoped_ptr
<bookmarks::BookmarkExpandedStateTracker
> expanded_state_tracker_
;
423 DISALLOW_COPY_AND_ASSIGN(BookmarkModel
);
426 #endif // COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_H_