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