// 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_