// Copyright (c) 2011 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.
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
#pragma once
#include "build/build_config.h"
#include <set>
#include <vector>
#include "base/observer_list.h"
#include "base/string16.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
#include "chrome/browser/bookmarks/bookmark_service.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_types.h"
#include "content/browser/cancelable_request.h"
#include "content/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/models/tree_node_model.h"
class BookmarkIndex;
class BookmarkLoadDetails;
class BookmarkModel;
class BookmarkStorage;
class Profile;
namespace bookmark_utils {
struct TitleMatch;
}
// BookmarkNode ---------------------------------------------------------------
// BookmarkNode contains information about a starred entry: title, URL, favicon,
// star id and type. BookmarkNodes are returned from a BookmarkModel.
//
class BookmarkNode : public ui::TreeNode<BookmarkNode> {
friend class BookmarkModel;
public:
enum Type {
URL,
FOLDER,
BOOKMARK_BAR,
OTHER_NODE
};
// Creates a new node with the specified url and id of 0
explicit BookmarkNode(const GURL& url);
// Creates a new node with the specified url and id.
BookmarkNode(int64 id, const GURL& url);
virtual ~BookmarkNode();
// Returns the URL.
const GURL& GetURL() const { return url_; }
// Sets the URL to the given value.
void SetURL(const GURL& url) { url_ = url; }
// Returns a unique id for this node.
// For bookmark nodes that are managed by the bookmark model, the IDs are
// persisted across sessions.
int64 id() const { return id_; }
// Sets the id to the given value.
void set_id(int64 id) { id_ = id; }
// Returns the type of this node.
BookmarkNode::Type type() const { return type_; }
void set_type(BookmarkNode::Type type) { type_ = type; }
// Returns the time the bookmark/folder was added.
const base::Time& date_added() const { return date_added_; }
// Sets the time the bookmark/folder was added.
void set_date_added(const base::Time& date) { date_added_ = date; }
// Returns the last time the folder was modified. This is only maintained
// for folders (including the bookmark and other folder).
const base::Time& date_folder_modified() const {
return date_folder_modified_;
}
// Sets the last time the folder was modified.
void set_date_folder_modified(const base::Time& date) {
date_folder_modified_ = date;
}
// Convenience for testing if this nodes represents a folder. A folder is a
// node whose type is not URL.
bool is_folder() const { return type_ != URL; }
// Is this a URL?
bool is_url() const { return type_ == URL; }
// Returns the favicon. In nearly all cases you should use the method
// BookmarkModel::GetFavicon rather than this. BookmarkModel::GetFavicon
// takes care of loading the favicon if it isn't already loaded, where as
// this does not.
const SkBitmap& favicon() const { return favicon_; }
void set_favicon(const SkBitmap& icon) { favicon_ = icon; }
// The following methods are used by the bookmark model, and are not
// really useful outside of it.
bool is_favicon_loaded() const { return loaded_favicon_; }
void set_favicon_loaded(bool value) { loaded_favicon_ = value; }
HistoryService::Handle favicon_load_handle() const {
return favicon_load_handle_;
}
void set_favicon_load_handle(HistoryService::Handle handle) {
favicon_load_handle_ = handle;
}
// Called when the favicon becomes invalid.
void InvalidateFavicon();
// Resets the properties of the node from the supplied entry.
// This is used by the bookmark model and not really useful outside of it.
void Reset(const history::StarredEntry& entry);
// TODO(sky): Consider adding last visit time here, it'll greatly simplify
// HistoryContentsProvider.
private:
// helper to initialize various fields during construction.
void Initialize(int64 id);
// Unique identifier for this node.
int64 id_;
// Whether the favicon has been loaded.
bool loaded_favicon_;
// The favicon.
SkBitmap favicon_;
// If non-zero, it indicates we're loading the favicon and this is the handle
// from the HistoryService.
HistoryService::Handle favicon_load_handle_;
// The URL. BookmarkModel maintains maps off this URL, it is important that
// changes to the URL is done through the bookmark model.
GURL url_;
// Type of node.
BookmarkNode::Type type_;
// Date we were created.
base::Time date_added_;
// Time last modified. Only used for folders.
base::Time date_folder_modified_;
DISALLOW_COPY_AND_ASSIGN(BookmarkNode);
};
// BookmarkModel --------------------------------------------------------------
// BookmarkModel provides a directed acyclic graph of the starred entries
// and folders. Two graphs are provided for the two entry points: those on
// the bookmark bar, and those in the other folder.
//
// An observer may be attached to observer relevant events.
//
// You should NOT directly create a BookmarkModel, instead go through the
// Profile.
class BookmarkModel : public NotificationObserver, public BookmarkService {
friend class BookmarkCodecTest;
friend class BookmarkModelTest;
friend class BookmarkStorage;
public:
explicit BookmarkModel(Profile* profile);
virtual ~BookmarkModel();
// Loads the bookmarks. This is called by Profile upon creation of the
// BookmarkModel. You need not invoke this directly.
void Load();
// Returns the root node. The bookmark bar node and other node are children of
// the root node.
const BookmarkNode* root_node() { return &root_; }
// Returns the bookmark bar node. This is NULL until loaded.
const BookmarkNode* GetBookmarkBarNode() { return bookmark_bar_node_; }
// Returns the 'other' node. This is NULL until loaded.
const BookmarkNode* other_node() { return other_node_; }
// Returns the parent the last node was added to. This never returns NULL
// (as long as the model is loaded).
const BookmarkNode* GetParentForNewNodes();
void AddObserver(BookmarkModelObserver* observer) {
observers_.AddObserver(observer);
}
void RemoveObserver(BookmarkModelObserver* observer) {
observers_.RemoveObserver(observer);
}
// Notify the observes that an import is about to happen, so they can
// delay any expensive UI updates until it is finished.
void BeginImportMode();
void EndImportMode();
// Unstars or deletes the specified entry. Removing a folder entry recursively
// unstars all nodes. Observers are notified immediately.
void Remove(const BookmarkNode* parent, int index);
// Moves the specified entry to a new location.
void Move(const BookmarkNode* node,
const BookmarkNode* new_parent,
int index);
// Duplicates a bookmark node and inserts it at a new location.
void Copy(const BookmarkNode* node,
const BookmarkNode* new_parent,
int index);
// Returns the favicon for |node|. If the favicon has not yet been
// loaded it is loaded and the observer of the model notified when done.
const SkBitmap& GetFavicon(const BookmarkNode* node);
// Sets the title of the specified node.
void SetTitle(const BookmarkNode* node, const string16& title);
// Sets the URL of the specified bookmark node.
void SetURL(const BookmarkNode* node, const GURL& url);
// Returns true if the model finished loading.
virtual bool IsLoaded();
// Returns the set of nodes with the specified URL.
void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
// Returns the most recently added node for the url. Returns NULL if url is
// not bookmarked.
const BookmarkNode* GetMostRecentlyAddedNodeForURL(const GURL& url);
// Returns all the bookmarked urls. This method is thread safe.
virtual void GetBookmarks(std::vector<GURL>* urls);
// Returns true if there are bookmarks, otherwise returns false. This method
// is thread safe.
bool HasBookmarks();
// Returns true if there is a bookmark for the specified URL. This method is
// thread safe. See BookmarkService for more details on this.
virtual bool IsBookmarked(const GURL& url);
// Blocks until loaded; this is NOT invoked on the main thread. See
// BookmarkService for more details on this.
virtual void BlockTillLoaded();
// Returns the node with the specified id, or NULL if there is no node with
// the specified id.
const BookmarkNode* GetNodeByID(int64 id);
// Adds a new folder node at the specified position.
const BookmarkNode* AddFolder(const BookmarkNode* parent,
int index,
const string16& title);
// Adds a url at the specified position.
const BookmarkNode* AddURL(const BookmarkNode* parent,
int index,
const string16& title,
const GURL& url);
// Adds a url with a specific creation date.
const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
int index,
const string16& title,
const GURL& url,
const base::Time& creation_time);
// Sorts the children of |parent|, notifying observers by way of the
// BookmarkNodeChildrenReordered method.
void SortChildren(const BookmarkNode* parent);
// This is the convenience that makes sure the url is starred or not starred.
// If is_starred is false, all bookmarks for URL are removed. If is_starred is
// true and there are no bookmarks for url, a bookmark is created.
void SetURLStarred(const GURL& url,
const string16& title,
bool is_starred);
// Sets the date modified time of the specified node.
void SetDateFolderModified(const BookmarkNode* parent, 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);
void GetBookmarksWithTitlesMatching(
const string16& text,
size_t max_count,
std::vector<bookmark_utils::TitleMatch>* matches);
Profile* profile() const { return profile_; }
bool is_root(const BookmarkNode* node) const { return node == &root_; }
bool is_bookmark_bar_node(const BookmarkNode* node) const {
return node == bookmark_bar_node_;
}
bool is_other_bookmarks_node(const BookmarkNode* node) const {
return node == other_node_;
}
// Returns whether the given node is one of the permanent nodes - root node,
// bookmark bar node or other bookmarks node.
bool is_permanent_node(const BookmarkNode* node) const {
return is_root(node) ||
is_bookmark_bar_node(node) ||
is_other_bookmarks_node(node);
}
// 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 whether the bookmarks file changed externally.
bool file_changed() const { return file_changed_; }
// Returns the next node ID.
int64 next_node_id() const { return next_node_id_; }
private:
// Used to order BookmarkNodes by URL.
class NodeURLComparator {
public:
bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
return n1->GetURL() < n2->GetURL();
}
};
// Implementation of IsBookmarked. Before calling this the caller must
// obtain a lock on url_lock_.
bool IsBookmarkedNoLock(const GURL& url);
// Overriden to notify the observer the favicon has been loaded.
void FaviconLoaded(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, std::set<GURL>* removed_urls);
// Invoked when loading is finished. Sets loaded_ and notifies observers.
// BookmarkModel takes ownership of |details|.
void DoneLoading(BookmarkLoadDetails* details);
// Populates nodes_ordered_by_url_set_ from root.
void PopulateNodesByURL(BookmarkNode* node);
// Removes the node from its parent, sends notification, and deletes it.
// type specifies how the node should be removed.
void RemoveAndDeleteNode(BookmarkNode* delete_me);
// Adds the node at the specified position and sends notification. If
// was_bookmarked is true, it indicates a bookmark already existed for the
// URL.
BookmarkNode* AddNode(BookmarkNode* parent,
int index,
BookmarkNode* node,
bool was_bookmarked);
// Implementation of GetNodeByID.
const BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id);
// Returns true if the parent and index are valid.
bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end);
// Creates the bookmark bar/other nodes. These call into
// CreateRootNodeFromStarredEntry.
BookmarkNode* CreateBookmarkNode();
BookmarkNode* CreateOtherBookmarksNode();
// Creates a root node (either the bookmark bar node or other node) from the
// specified starred entry.
BookmarkNode* CreateRootNodeFromStarredEntry(
const history::StarredEntry& entry);
// Notification that a favicon has finished loading. If we can decode the
// favicon, FaviconLoaded is invoked.
void OnFaviconDataAvailable(FaviconService::Handle handle,
history::FaviconData favicon);
// Invoked from the node to load the favicon. Requests the favicon from the
// favicon service.
void LoadFavicon(BookmarkNode* node);
// If we're waiting on a favicon for node, the load request is canceled.
void CancelPendingFaviconLoadRequests(BookmarkNode* node);
// NotificationObserver.
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
// Generates and returns the next node ID.
int64 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 id) { next_node_id_ = id; }
// Records that the bookmarks file was changed externally.
void SetFileChanged();
// Creates and returns a new BookmarkLoadDetails. It's up to the caller to
// delete the returned object.
BookmarkLoadDetails* CreateLoadDetails();
NotificationRegistrar registrar_;
Profile* profile_;
// Whether the initial set of data has been loaded.
bool loaded_;
// Whether the bookmarks file was changed externally. This is set after
// loading is complete and once set the value never changes.
bool file_changed_;
// The root node. This contains the bookmark bar node and the 'other' node as
// children.
BookmarkNode root_;
BookmarkNode* bookmark_bar_node_;
BookmarkNode* other_node_;
// The maximum ID assigned to the bookmark nodes in the model.
int64 next_node_id_;
// The observers.
ObserverList<BookmarkModelObserver> observers_;
// Set of nodes ordered by URL. This is not a map to avoid copying the
// urls.
// WARNING: nodes_ordered_by_url_set_ is accessed on multiple threads. As
// such, be sure and wrap all usage of it around url_lock_.
typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet;
NodesOrderedByURLSet nodes_ordered_by_url_set_;
base::Lock url_lock_;
// Used for loading favicons and the empty history request.
CancelableRequestConsumerTSimple<BookmarkNode*> load_consumer_;
// Reads/writes bookmarks to disk.
scoped_refptr<BookmarkStorage> store_;
scoped_ptr<BookmarkIndex> index_;
base::WaitableEvent loaded_signal_;
DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
};
#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_