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 <stddef.h>
9 #include <stdint.h>
10 
11 #include <map>
12 #include <memory>
13 #include <set>
14 #include <string>
15 #include <vector>
16 
17 #include "base/check_op.h"
18 #include "base/compiler_specific.h"
19 #include "base/macros.h"
20 #include "base/memory/scoped_refptr.h"
21 #include "base/memory/weak_ptr.h"
22 #include "base/observer_list.h"
23 #include "base/sequence_checker.h"
24 #include "base/strings/string16.h"
25 #include "components/bookmarks/browser/bookmark_client.h"
26 #include "components/bookmarks/browser/bookmark_node.h"
27 #include "components/bookmarks/browser/bookmark_undo_provider.h"
28 #include "components/keyed_service/core/keyed_service.h"
29 #include "ui/gfx/image/image.h"
30 #include "url/gurl.h"
31 
32 class PrefService;
33 
34 namespace base {
35 class FilePath;
36 }
37 
38 namespace favicon_base {
39 struct FaviconImageResult;
40 }
41 
42 namespace query_parser {
43 enum class MatchingAlgorithm;
44 }
45 
46 namespace bookmarks {
47 
48 class BookmarkCodecTest;
49 class BookmarkExpandedStateTracker;
50 class BookmarkLoadDetails;
51 class BookmarkModelObserver;
52 class BookmarkStorage;
53 class BookmarkUndoDelegate;
54 class ModelLoader;
55 class ScopedGroupBookmarkActions;
56 class TestBookmarkClient;
57 class TitledUrlIndex;
58 class UrlIndex;
59 
60 struct UrlAndTitle;
61 struct TitledUrlMatch;
62 
63 // BookmarkModel --------------------------------------------------------------
64 
65 // BookmarkModel provides a directed acyclic graph of URLs and folders.
66 // Three graphs are provided for the three entry points: those on the 'bookmarks
67 // bar', those in the 'other bookmarks' folder and those in the 'mobile' folder.
68 //
69 // An observer may be attached to observe relevant events.
70 //
71 // You should NOT directly create a BookmarkModel, instead go through the
72 // BookmarkModelFactory.
73 class BookmarkModel : public BookmarkUndoProvider,
74                       public KeyedService {
75  public:
76   explicit BookmarkModel(std::unique_ptr<BookmarkClient> client);
77   ~BookmarkModel() override;
78 
79   // Triggers the loading of bookmarks, which is an asynchronous operation with
80   // most heavy-lifting taking place in a background sequence. Upon completion,
81   // loaded() will return true and observers will be notified via
82   // BookmarkModelLoaded().
83   void Load(PrefService* pref_service, const base::FilePath& profile_path);
84 
85   // Returns true if the model finished loading.
loaded()86   bool loaded() const {
87     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
88     return loaded_;
89   }
90 
91   // Returns the object responsible for tracking loading.
92   scoped_refptr<ModelLoader> model_loader();
93 
94   // Returns the root node. The 'bookmark bar' node and 'other' node are
95   // children of the root node.
root_node()96   const BookmarkNode* root_node() const {
97     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
98     return root_;
99   }
100 
101   // Returns the 'bookmark bar' node. This is NULL until loaded.
bookmark_bar_node()102   const BookmarkNode* bookmark_bar_node() const {
103     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
104     return bookmark_bar_node_;
105   }
106 
107   // Returns the 'other' node. This is NULL until loaded.
other_node()108   const BookmarkNode* other_node() const {
109     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
110     return other_node_;
111   }
112 
113   // Returns the 'mobile' node. This is NULL until loaded.
mobile_node()114   const BookmarkNode* mobile_node() const {
115     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116     return mobile_node_;
117   }
118 
is_root_node(const BookmarkNode * node)119   bool is_root_node(const BookmarkNode* node) const {
120     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
121     return node == root_;
122   }
123 
124   // Returns whether the given |node| is one of the permanent nodes - root node,
125   // 'bookmark bar' node, 'other' node or 'mobile' node, or one of the root
126   // nodes supplied by the |client_|.
is_permanent_node(const BookmarkNode * node)127   bool is_permanent_node(const BookmarkNode* node) const {
128     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
129     return node && (node == root_ || node->parent() == root_);
130   }
131 
132   void AddObserver(BookmarkModelObserver* observer);
133   void RemoveObserver(BookmarkModelObserver* observer);
134 
135   // Notifies the observers that an extensive set of changes is about to happen,
136   // such as during import or sync, so they can delay any expensive UI updates
137   // until it's finished.
138   void BeginExtensiveChanges();
139   void EndExtensiveChanges();
140 
141   // Returns true if this bookmark model is currently in a mode where extensive
142   // changes might happen, such as for import and sync. This is helpful for
143   // observers that are created after the mode has started, and want to check
144   // state during their own initializer, such as the NTP.
IsDoingExtensiveChanges()145   bool IsDoingExtensiveChanges() const { return extensive_changes_ > 0; }
146 
147   // Removes |node| from the model and deletes it. Removing a folder node
148   // recursively removes all nodes. Observers are notified immediately. |node|
149   // must not be a permanent node.
150   void Remove(const BookmarkNode* node);
151 
152   // Removes all the non-permanent bookmark nodes that are editable by the user.
153   // Observers are only notified when all nodes have been removed. There is no
154   // notification for individual node removals.
155   void RemoveAllUserBookmarks();
156 
157   // Moves |node| to |new_parent| and inserts it at the given |index|.
158   void Move(const BookmarkNode* node,
159             const BookmarkNode* new_parent,
160             size_t index);
161 
162   // Inserts a copy of |node| into |new_parent| at |index|.
163   void Copy(const BookmarkNode* node,
164             const BookmarkNode* new_parent,
165             size_t index);
166 
167   // Returns the favicon for |node|. If the favicon has not yet been loaded,
168   // a load will be triggered and the observer of the model notified when done.
169   // This also means that, on return, the node's state is guaranteed to be
170   // either LOADED_FAVICON (if it was already loaded prior to the call) or
171   // LOADING_FAVICON (with the exception of folders, where the call is a no-op).
172   const gfx::Image& GetFavicon(const BookmarkNode* node);
173 
174   // Sets the title of |node|.
175   void SetTitle(const BookmarkNode* node, const base::string16& title);
176 
177   // Sets the URL of |node|.
178   void SetURL(const BookmarkNode* node, const GURL& url);
179 
180   // Sets the date added time of |node|.
181   void SetDateAdded(const BookmarkNode* node, base::Time date_added);
182 
183   // Returns the set of nodes with the |url|.
184   void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
185 
186   // Returns the most recently added user node for the |url|; urls from any
187   // nodes that are not editable by the user are never returned by this call.
188   // Returns NULL if |url| is not bookmarked.
189   const BookmarkNode* GetMostRecentlyAddedUserNodeForURL(const GURL& url);
190 
191   // Returns true if there are bookmarks, otherwise returns false.
192   bool HasBookmarks();
193 
194   // Returns true is there is no user created bookmarks or folders.
195   bool HasNoUserCreatedBookmarksOrFolders();
196 
197   // Returns true if the specified URL is bookmarked.
198   bool IsBookmarked(const GURL& url);
199 
200   // Returns, by reference in |bookmarks|, the set of bookmarked urls and their
201   // titles. This returns the unique set of URLs. For example, if two bookmarks
202   // reference the same URL only one entry is added not matter the titles are
203   // same or not.
204   void GetBookmarks(std::vector<UrlAndTitle>* urls);
205 
206   // Adds a new folder node at the specified position with the given |guid| and
207   // |meta_info|. If a GUID is provided, it must be a valid version 4 GUID,
208   // otherwise a new one is generated to replace it.
209   const BookmarkNode* AddFolder(
210       const BookmarkNode* parent,
211       size_t index,
212       const base::string16& title,
213       const BookmarkNode::MetaInfoMap* meta_info = nullptr,
214       base::Optional<std::string> guid = base::nullopt);
215 
216   // Adds a url at the specified position with the given |creation_time|,
217   // |meta_info| and |guid|. If a GUID is provided, it must be a valid version 4
218   // GUID, otherwise a new one is generated to replace it.
219   const BookmarkNode* AddURL(
220       const BookmarkNode* parent,
221       size_t index,
222       const base::string16& title,
223       const GURL& url,
224       const BookmarkNode::MetaInfoMap* meta_info = nullptr,
225       base::Optional<base::Time> creation_time = base::nullopt,
226       base::Optional<std::string> guid = base::nullopt);
227 
228   // Sorts the children of |parent|, notifying observers by way of the
229   // BookmarkNodeChildrenReordered method.
230   void SortChildren(const BookmarkNode* parent);
231 
232   // Order the children of |parent| as specified in |ordered_nodes|.  This
233   // function should only be used to reorder the child nodes of |parent| and
234   // is not meant to move nodes between different parent. Notifies observers
235   // using the BookmarkNodeChildrenReordered method.
236   void ReorderChildren(const BookmarkNode* parent,
237                        const std::vector<const BookmarkNode*>& ordered_nodes);
238 
239   // Sets the date when the folder was modified.
240   void SetDateFolderModified(const BookmarkNode* node, const base::Time time);
241 
242   // Resets the 'date modified' time of the node to 0. This is used during
243   // importing to exclude the newly created folders from showing up in the
244   // combobox of most recently modified folders.
245   void ResetDateFolderModified(const BookmarkNode* node);
246 
247   // Returns up to |max_count| bookmarks containing each term from |query| in
248   // either the title, URL, or, if |match_ancestor_titles| is true, the titles
249   // of ancestors. |matching_algorithm| determines the algorithm used by
250   // QueryParser internally to parse |query|.
251   std::vector<TitledUrlMatch> GetBookmarksMatching(
252       const base::string16& query,
253       size_t max_count,
254       query_parser::MatchingAlgorithm matching_algorithm,
255       bool match_ancestor_titles = false);
256 
257   // Sets the store to NULL, making it so the BookmarkModel does not persist
258   // any changes to disk. This is only useful during testing to speed up
259   // testing.
260   void ClearStore();
261 
262   // Returns the next node ID.
next_node_id()263   int64_t next_node_id() const { return next_node_id_; }
264 
265   // Returns the object responsible for tracking the set of expanded nodes in
266   // the bookmark editor.
expanded_state_tracker()267   BookmarkExpandedStateTracker* expanded_state_tracker() {
268     return expanded_state_tracker_.get();
269   }
270 
271   // Sets/deletes meta info of |node|.
272   void SetNodeMetaInfo(const BookmarkNode* node,
273                        const std::string& key,
274                        const std::string& value);
275   void SetNodeMetaInfoMap(const BookmarkNode* node,
276                           const BookmarkNode::MetaInfoMap& meta_info_map);
277   void DeleteNodeMetaInfo(const BookmarkNode* node,
278                           const std::string& key);
279 
280   // Adds |key| to the set of meta info keys that are not copied when a node is
281   // cloned.
282   void AddNonClonedKey(const std::string& key);
283 
284   // Returns the set of meta info keys that should not be copied when a node is
285   // cloned.
non_cloned_keys()286   const std::set<std::string>& non_cloned_keys() const {
287     return non_cloned_keys_;
288   }
289 
290   // Notify BookmarkModel that the favicons for the given page URLs (e.g.
291   // http://www.google.com) and the given icon URL (e.g.
292   // http://www.google.com/favicon.ico) have changed. It is valid to call
293   // OnFaviconsChanged() with non-empty |page_urls| and an empty |icon_url| and
294   // vice versa.
295   void OnFaviconsChanged(const std::set<GURL>& page_urls,
296                          const GURL& icon_url);
297 
298   // Returns the client used by this BookmarkModel.
client()299   BookmarkClient* client() const { return client_.get(); }
300 
301   void SetUndoDelegate(BookmarkUndoDelegate* undo_delegate);
302 
AsWeakPtr()303   base::WeakPtr<BookmarkModel> AsWeakPtr() {
304     return weak_factory_.GetWeakPtr();
305   }
306 
307  private:
308   friend class BookmarkCodecTest;
309   friend class BookmarkModelFaviconTest;
310   friend class BookmarkStorage;
311   friend class ScopedGroupBookmarkActions;
312   friend class TestBookmarkClient;
313 
314   // BookmarkUndoProvider:
315   void RestoreRemovedNode(const BookmarkNode* parent,
316                           size_t index,
317                           std::unique_ptr<BookmarkNode> node) override;
318 
319   // Notifies the observers for adding every descendant of |node|.
320   void NotifyNodeAddedForAllDescendants(const BookmarkNode* node);
321 
322   // Removes the node from internal maps and recurses through all children. If
323   // the node is a url, its url is added to removed_urls.
324   //
325   // This does NOT delete the node.
326   void RemoveNodeFromIndexRecursive(BookmarkNode* node);
327 
328   // Called when done loading. Updates internal state and notifies observers.
329   void DoneLoading(std::unique_ptr<BookmarkLoadDetails> details);
330 
331   // Adds the |node| at |parent| in the specified |index| and notifies its
332   // observers.
333   BookmarkNode* AddNode(BookmarkNode* parent,
334                         size_t index,
335                         std::unique_ptr<BookmarkNode> node);
336 
337   // Adds |node| to |index_| and recursively invokes this for all children.
338   void AddNodeToIndexRecursive(const BookmarkNode* node);
339 
340   // Returns true if the parent and index are valid.
341   bool IsValidIndex(const BookmarkNode* parent, size_t index, bool allow_end);
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       const favicon_base::FaviconImageResult& image_result);
348 
349   // Invoked from the node to load the favicon. Requests the favicon from the
350   // favicon service.
351   void LoadFavicon(BookmarkNode* node);
352 
353   // Called to notify the observers that the favicon has been loaded.
354   void FaviconLoaded(const BookmarkNode* node);
355 
356   // If we're waiting on a favicon for node, the load request is canceled.
357   void CancelPendingFaviconLoadRequests(BookmarkNode* node);
358 
359   // Notifies the observers that a set of changes initiated by a single user
360   // action is about to happen and has completed.
361   void BeginGroupedChanges();
362   void EndGroupedChanges();
363 
364   // Generates and returns the next node ID.
365   int64_t generate_next_node_id();
366 
367   // Sets the maximum node ID to the given value.
368   // This is used by BookmarkCodec to report the maximum ID after it's done
369   // decoding since during decoding codec assigns node IDs.
set_next_node_id(int64_t id)370   void set_next_node_id(int64_t id) { next_node_id_ = id; }
371 
372   BookmarkUndoDelegate* undo_delegate() const;
373 
374   std::unique_ptr<BookmarkClient> client_;
375 
376   // Whether the initial set of data has been loaded.
377   bool loaded_ = false;
378 
379   // See |root_| for details.
380   std::unique_ptr<BookmarkNode> owned_root_;
381 
382   // The root node. This contains the bookmark bar node, the 'other' node and
383   // the mobile node as children. The value of |root_| is initially that of
384   // |owned_root_|. Once loading has completed, |owned_root_| is destroyed and
385   // this is set to url_index_->root(). |owned_root_| is done as lots of
386   // existing code assumes the root is non-null while loading.
387   BookmarkNode* root_ = nullptr;
388 
389   BookmarkPermanentNode* bookmark_bar_node_ = nullptr;
390   BookmarkPermanentNode* other_node_ = nullptr;
391   BookmarkPermanentNode* mobile_node_ = nullptr;
392 
393   // The maximum ID assigned to the bookmark nodes in the model.
394   int64_t next_node_id_ = 1;
395 
396   // The observers.
397   base::ObserverList<BookmarkModelObserver>::Unchecked observers_;
398 
399   // Used for loading favicons.
400   base::CancelableTaskTracker cancelable_task_tracker_;
401 
402   // Writes bookmarks to disk.
403   std::unique_ptr<BookmarkStorage> store_;
404 
405   std::unique_ptr<TitledUrlIndex> titled_url_index_;
406 
407   // Owned by |model_loader_|.
408   // WARNING: in some tests this does *not* refer to
409   // |ModelLoader::history_bookmark_model_|. This is because some tests
410   // directly call DoneLoading().
411   // TODO: this is confusing, fix tests not to circumvent ModelLoader.
412   scoped_refptr<UrlIndex> url_index_;
413 
414   // See description of IsDoingExtensiveChanges above.
415   int extensive_changes_ = 0;
416 
417   std::unique_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_;
418 
419   std::set<std::string> non_cloned_keys_;
420 
421   BookmarkUndoDelegate* undo_delegate_ = nullptr;
422   std::unique_ptr<BookmarkUndoDelegate> empty_undo_delegate_;
423 
424   scoped_refptr<ModelLoader> model_loader_;
425 
426   SEQUENCE_CHECKER(sequence_checker_);
427 
428   base::WeakPtrFactory<BookmarkModel> weak_factory_{this};
429 
430   DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
431 };
432 
433 }  // namespace bookmarks
434 
435 #endif  // COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_H_
436