blob: f4b6c8770e01c40992c2b6d5ee78dcbdc1429a53 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "components/bookmarks/browser/bookmark_client.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/bookmarks/browser/bookmark_undo_provider.h"
#include "components/keyed_service/core/keyed_service.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
class PrefService;
namespace base {
class FilePath;
class SequencedTaskRunner;
namespace favicon_base {
struct FaviconImageResult;
namespace query_parser {
enum class MatchingAlgorithm;
namespace bookmarks {
class BookmarkCodecTest;
class BookmarkExpandedStateTracker;
class BookmarkLoadDetails;
class BookmarkModelObserver;
class BookmarkStorage;
class BookmarkUndoDelegate;
class ModelLoader;
class ScopedGroupBookmarkActions;
class TestBookmarkClient;
class TitledUrlIndex;
class UrlIndex;
struct UrlAndTitle;
struct TitledUrlMatch;
// BookmarkModel --------------------------------------------------------------
// BookmarkModel provides a directed acyclic graph of URLs and folders.
// Three graphs are provided for the three entry points: those on the 'bookmarks
// bar', those in the 'other bookmarks' folder and those in the 'mobile' folder.
// An observer may be attached to observe relevant events.
// You should NOT directly create a BookmarkModel, instead go through the
// BookmarkModelFactory.
class BookmarkModel : public BookmarkUndoProvider,
public KeyedService {
explicit BookmarkModel(std::unique_ptr<BookmarkClient> client);
~BookmarkModel() override;
// Loads the bookmarks. This is called upon creation of the BookmarkModel. You
// need not invoke this directly. All load operations will be executed on
// |io_task_runner|. |ui_task_runner| is the task runner the model runs on.
void Load(PrefService* pref_service,
const base::FilePath& profile_path,
const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner);
// Returns true if the model finished loading.
bool loaded() const { return loaded_; }
// Returns the object responsible for tracking loading.
ModelLoader* model_loader() { return model_loader_.get(); }
// Returns the root node. The 'bookmark bar' node and 'other' node are
// children of the root node.
const BookmarkNode* root_node() const { return root_; }
// Returns the 'bookmark bar' node. This is NULL until loaded.
const BookmarkNode* bookmark_bar_node() const { return bookmark_bar_node_; }
// Returns the 'other' node. This is NULL until loaded.
const BookmarkNode* other_node() const { return other_node_; }
// Returns the 'mobile' node. This is NULL until loaded.
const BookmarkNode* mobile_node() const { return mobile_node_; }
bool is_root_node(const BookmarkNode* node) const { return node == root_; }
// Returns whether the given |node| is one of the permanent nodes - root node,
// 'bookmark bar' node, 'other' node or 'mobile' node, or one of the root
// nodes supplied by the |client_|.
bool is_permanent_node(const BookmarkNode* node) const {
return node && (node == root_ || node->parent() == root_);
void AddObserver(BookmarkModelObserver* observer);
void RemoveObserver(BookmarkModelObserver* observer);
// Notifies the observers that an extensive set of changes is about to happen,
// such as during import or sync, so they can delay any expensive UI updates
// until it's finished.
void BeginExtensiveChanges();
void EndExtensiveChanges();
// Returns true if this bookmark model is currently in a mode where extensive
// changes might happen, such as for import and sync. This is helpful for
// observers that are created after the mode has started, and want to check
// state during their own initializer, such as the NTP.
bool IsDoingExtensiveChanges() const { return extensive_changes_ > 0; }
// Removes |node| from the model and deletes it. Removing a folder node
// recursively removes all nodes. Observers are notified immediately.
void Remove(const BookmarkNode* node);
// Removes all the non-permanent bookmark nodes that are editable by the user.
// Observers are only notified when all nodes have been removed. There is no
// notification for individual node removals.
void RemoveAllUserBookmarks();
// Moves |node| to |new_parent| and inserts it at the given |index|.
void Move(const BookmarkNode* node,
const BookmarkNode* new_parent,
size_t index);
// Inserts a copy of |node| into |new_parent| at |index|.
void Copy(const BookmarkNode* node,
const BookmarkNode* new_parent,
size_t index);
// Returns the favicon for |node|. If the favicon has not yet been loaded,
// a load will be triggered and the observer of the model notified when done.
// This also means that, on return, the node's state is guaranteed to be
// either LOADED_FAVICON (if it was already loaded prior to the call) or
// LOADING_FAVICON (with the exception of folders, where the call is a no-op).
const gfx::Image& GetFavicon(const BookmarkNode* node);
// Returns the type of the favicon for |node|. If the favicon has not yet
// been loaded, it returns |favicon_base::IconType::kInvalid|.
favicon_base::IconType GetFaviconType(const BookmarkNode* node);
// Sets the title of |node|.
void SetTitle(const BookmarkNode* node, const base::string16& title);
// Sets the URL of |node|.
void SetURL(const BookmarkNode* node, const GURL& url);
// Sets the date added time of |node|.
void SetDateAdded(const BookmarkNode* node, base::Time date_added);
// Returns the set of nodes with the |url|.
void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
// Returns the most recently added user node for the |url|; urls from any
// nodes that are not editable by the user are never returned by this call.
// Returns NULL if |url| is not bookmarked.
const BookmarkNode* GetMostRecentlyAddedUserNodeForURL(const GURL& url);
// Returns true if there are bookmarks, otherwise returns false.
// This method is thread safe.
bool HasBookmarks();
// Returns true is there is no user created bookmarks or folders.
bool HasNoUserCreatedBookmarksOrFolders();
// Returns true if the specified URL is bookmarked.
// If not on the main thread you *must* invoke BlockTillLoaded first.
bool IsBookmarked(const GURL& url);
// Returns, by reference in |bookmarks|, the set of bookmarked urls and their
// titles. This returns the unique set of URLs. For example, if two bookmarks
// reference the same URL only one entry is added not matter the titles are
// same or not.
// If not on the main thread you *must* invoke BlockTillLoaded first.
void GetBookmarks(std::vector<UrlAndTitle>* urls);
// Adds a new folder node at the specified position.
const BookmarkNode* AddFolder(const BookmarkNode* parent,
size_t index,
const base::string16& title);
// Adds a new folder with meta info.
const BookmarkNode* AddFolderWithMetaInfo(
const BookmarkNode* parent,
size_t index,
const base::string16& title,
const BookmarkNode::MetaInfoMap* meta_info);
// Adds a url at the specified position.
const BookmarkNode* AddURL(const BookmarkNode* parent,
size_t index,
const base::string16& title,
const GURL& url);
// Adds a url with a specific creation date and meta info.
const BookmarkNode* AddURLWithCreationTimeAndMetaInfo(
const BookmarkNode* parent,
size_t index,
const base::string16& title,
const GURL& url,
const base::Time& creation_time,
const BookmarkNode::MetaInfoMap* meta_info);
// Sorts the children of |parent|, notifying observers by way of the
// BookmarkNodeChildrenReordered method.
void SortChildren(const BookmarkNode* parent);
// Order the children of |parent| as specified in |ordered_nodes|. This
// function should only be used to reorder the child nodes of |parent| and
// is not meant to move nodes between different parent. Notifies observers
// using the BookmarkNodeChildrenReordered method.
void ReorderChildren(const BookmarkNode* parent,
const std::vector<const BookmarkNode*>& ordered_nodes);
// Sets the date when the folder was modified.
void SetDateFolderModified(const BookmarkNode* node, const base::Time time);
// Resets the 'date modified' time of the node to 0. This is used during
// importing to exclude the newly created folders from showing up in the
// combobox of most recently modified folders.
void ResetDateFolderModified(const BookmarkNode* node);
// Returns up to |max_count| of bookmarks containing each term from |text|
// in either the title or the URL. It uses default matching algorithm.
void GetBookmarksMatching(const base::string16& text,
size_t max_count,
std::vector<TitledUrlMatch>* matches);
// Returns up to |max_count| of bookmarks containing each term from |text|
// in either the title or the URL.
void GetBookmarksMatching(const base::string16& text,
size_t max_count,
query_parser::MatchingAlgorithm matching_algorithm,
std::vector<TitledUrlMatch>* matches);
// Sets the store to NULL, making it so the BookmarkModel does not persist
// any changes to disk. This is only useful during testing to speed up
// testing.
void ClearStore();
// Returns the next node ID.
int64_t next_node_id() const { return next_node_id_; }
// Returns the object responsible for tracking the set of expanded nodes in
// the bookmark editor.
BookmarkExpandedStateTracker* expanded_state_tracker() {
return expanded_state_tracker_.get();
// Sets the visibility of one of the permanent nodes (unless the node must
// always be visible, see |BookmarkClient::IsPermanentNodeVisible| for more
// details). This is set by sync.
void SetPermanentNodeVisible(BookmarkNode::Type type, bool value);
// Returns the permanent node of type |type|.
const BookmarkPermanentNode* PermanentNode(BookmarkNode::Type type);
// Sets/deletes meta info of |node|.
void SetNodeMetaInfo(const BookmarkNode* node,
const std::string& key,
const std::string& value);
void SetNodeMetaInfoMap(const BookmarkNode* node,
const BookmarkNode::MetaInfoMap& meta_info_map);
void DeleteNodeMetaInfo(const BookmarkNode* node,
const std::string& key);
// Adds |key| to the set of meta info keys that are not copied when a node is
// cloned.
void AddNonClonedKey(const std::string& key);
// Returns the set of meta info keys that should not be copied when a node is
// cloned.
const std::set<std::string>& non_cloned_keys() const {
return non_cloned_keys_;
// Sets the sync transaction version of |node|.
void SetNodeSyncTransactionVersion(const BookmarkNode* node,
int64_t sync_transaction_version);
// Notify BookmarkModel that the favicons for the given page URLs (e.g.
// and the given icon URL (e.g.
// have changed. It is valid to call
// OnFaviconsChanged() with non-empty |page_urls| and an empty |icon_url| and
// vice versa.
void OnFaviconsChanged(const std::set<GURL>& page_urls,
const GURL& icon_url);
// Returns the client used by this BookmarkModel.
BookmarkClient* client() const { return client_.get(); }
void SetUndoDelegate(BookmarkUndoDelegate* undo_delegate);
friend class BookmarkCodecTest;
friend class BookmarkModelFaviconTest;
friend class BookmarkStorage;
friend class ScopedGroupBookmarkActions;
friend class TestBookmarkClient;
// BookmarkUndoProvider:
void RestoreRemovedNode(const BookmarkNode* parent,
size_t index,
std::unique_ptr<BookmarkNode> node) override;
// Notifies the observers for adding every descedent of |node|.
void NotifyNodeAddedForAllDescendents(const BookmarkNode* node);
// Removes the node from internal maps and recurses through all children. If
// the node is a url, its url is added to removed_urls.
// This does NOT delete the node.
void RemoveNode(BookmarkNode* node);
// Called when done loading. Updates internal state and notifies observers.
void DoneLoading(std::unique_ptr<BookmarkLoadDetails> details);
// Adds the |node| at |parent| in the specified |index| and notifies its
// observers.
BookmarkNode* AddNode(BookmarkNode* parent,
size_t index,
std::unique_ptr<BookmarkNode> node);
// Adds |node| to |index_| and recursisvely invokes this for all children.
void AddNodeToIndexRecursive(BookmarkNode* node);
// Returns true if the parent and index are valid.
bool IsValidIndex(const BookmarkNode* parent, size_t index, bool allow_end);
// Notification that a favicon has finished loading. If we can decode the
// favicon, FaviconLoaded is invoked.
void OnFaviconDataAvailable(
BookmarkNode* node,
favicon_base::IconType icon_type,
const favicon_base::FaviconImageResult& image_result);
// Invoked from the node to load the favicon. Requests the favicon from the
// favicon service.
void LoadFavicon(BookmarkNode* node, favicon_base::IconType icon_type);
// Called to notify the observers that the favicon has been loaded.
void FaviconLoaded(const BookmarkNode* node);
// If we're waiting on a favicon for node, the load request is canceled.
void CancelPendingFaviconLoadRequests(BookmarkNode* node);
// Notifies the observers that a set of changes initiated by a single user
// action is about to happen and has completed.
void BeginGroupedChanges();
void EndGroupedChanges();
// Generates and returns the next node ID.
int64_t generate_next_node_id();
// Sets the maximum node ID to the given value.
// This is used by BookmarkCodec to report the maximum ID after it's done
// decoding since during decoding codec assigns node IDs.
void set_next_node_id(int64_t id) { next_node_id_ = id; }
BookmarkUndoDelegate* undo_delegate() const;
std::unique_ptr<BookmarkClient> client_;
// Whether the initial set of data has been loaded.
bool loaded_ = false;
// See |root_| for details.
std::unique_ptr<BookmarkNode> owned_root_;
// The root node. This contains the bookmark bar node, the 'other' node and
// the mobile node as children. The value of |root_| is initially that of
// |owned_root_|. Once loading has completed, |owned_root_| is destroyed and
// this is set to url_index_->root(). |owned_root_| is done as lots of
// existing code assumes the root is non-null while loading.
BookmarkNode* root_ = nullptr;
BookmarkPermanentNode* bookmark_bar_node_ = nullptr;
BookmarkPermanentNode* other_node_ = nullptr;
BookmarkPermanentNode* mobile_node_ = nullptr;
// The maximum ID assigned to the bookmark nodes in the model.
int64_t next_node_id_ = 1;
// The observers.
base::ObserverList<BookmarkModelObserver>::Unchecked observers_;
// Used for loading favicons.
base::CancelableTaskTracker cancelable_task_tracker_;
// Reads/writes bookmarks to disk.
std::unique_ptr<BookmarkStorage> store_;
std::unique_ptr<TitledUrlIndex> index_;
// Owned by |model_loader_|.
// WARNING: in some tests this does *not* refer to
// |ModelLoader::history_bookmark_model_|. This is because some tests
// directly call DoneLoading().
// TODO: this is confusing, fix tests not to circumvent ModelLoader.
scoped_refptr<UrlIndex> url_index_;
// See description of IsDoingExtensiveChanges above.
int extensive_changes_ = 0;
std::unique_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_;
std::set<std::string> non_cloned_keys_;
BookmarkUndoDelegate* undo_delegate_ = nullptr;
std::unique_ptr<BookmarkUndoDelegate> empty_undo_delegate_;
scoped_refptr<ModelLoader> model_loader_;
base::WeakPtrFactory<BookmarkModel> weak_factory_{this};
} // namespace bookmarks