root/chrome/browser/bookmarks/bookmark_model.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// Copyright (c) 2012 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_

#include <map>
#include <set>
#include <vector>

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/bookmarks/bookmark_service.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "ui/base/models/tree_node_model.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"

class BookmarkExpandedStateTracker;
class BookmarkIndex;
class BookmarkLoadDetails;
class BookmarkModel;
class BookmarkModelObserver;
class BookmarkStorage;
struct BookmarkTitleMatch;
class Profile;
class ScopedGroupBookmarkActions;

namespace base {
class SequencedTaskRunner;
}

namespace chrome {
struct FaviconImageResult;
}

// BookmarkNode ---------------------------------------------------------------

// BookmarkNode contains information about a starred entry: title, URL, favicon,
// id and type. BookmarkNodes are returned from BookmarkModel.
class BookmarkNode : public ui::TreeNode<BookmarkNode> {
 public:
  enum Type {
    URL,
    FOLDER,
    BOOKMARK_BAR,
    OTHER_NODE,
    MOBILE
  };

  enum FaviconState {
    INVALID_FAVICON,
    LOADING_FAVICON,
    LOADED_FAVICON,
  };

  typedef std::map<std::string, std::string> MetaInfoMap;

  static const int64 kInvalidSyncTransactionVersion;

  // Creates a new node with an id of 0 and |url|.
  explicit BookmarkNode(const GURL& url);
  // Creates a new node with |id| and |url|.
  BookmarkNode(int64 id, const GURL& url);

  virtual ~BookmarkNode();

  // Set the node's internal title. Note that this neither invokes observers
  // nor updates any bookmark model this node may be in. For that functionality,
  // BookmarkModel::SetTitle(..) should be used instead.
  virtual void SetTitle(const base::string16& title) OVERRIDE;

  // Returns an 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_; }
  void set_id(int64 id) { id_ = id; }

  const GURL& url() const { return url_; }
  void set_url(const GURL& url) { url_ = url; }

  // Returns the favicon's URL. Returns an empty URL if there is no favicon
  // associated with this bookmark.
  const GURL& icon_url() const { return icon_url_; }

  Type type() const { return type_; }
  void set_type(Type type) { type_ = type; }

  // Returns the time the node was added.
  const base::Time& date_added() const { return date_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 bar and other folder).
  const base::Time& date_folder_modified() const {
    return date_folder_modified_;
  }
  void set_date_folder_modified(const base::Time& date) {
    date_folder_modified_ = date;
  }

  // Convenience for testing if this node represents a folder. A folder is a
  // node whose type is not URL.
  bool is_folder() const { return type_ != URL; }
  bool is_url() const { return type_ == URL; }

  bool is_favicon_loaded() const { return favicon_state_ == LOADED_FAVICON; }

  // Accessor method for controlling the visibility of a bookmark node/sub-tree.
  // Note that visibility is not propagated down the tree hierarchy so if a
  // parent node is marked as invisible, a child node may return "Visible". This
  // function is primarily useful when traversing the model to generate a UI
  // representation but we may want to suppress some nodes.
  virtual bool IsVisible() const;

  // Gets/sets/deletes value of |key| in the meta info represented by
  // |meta_info_str_|. Return true if key is found in meta info for gets or
  // meta info is changed indeed for sets/deletes.
  bool GetMetaInfo(const std::string& key, std::string* value) const;
  bool SetMetaInfo(const std::string& key, const std::string& value);
  bool DeleteMetaInfo(const std::string& key);
  void SetMetaInfoMap(const MetaInfoMap& meta_info_map);
  // Returns NULL if there are no values in the map.
  const MetaInfoMap* GetMetaInfoMap() const;

  void set_sync_transaction_version(int64 sync_transaction_version) {
    sync_transaction_version_ = sync_transaction_version;
  }
  int64 sync_transaction_version() const {
    return sync_transaction_version_;
  }

  // TODO(sky): Consider adding last visit time here, it'll greatly simplify
  // HistoryContentsProvider.

 private:
  friend class BookmarkModel;

  // A helper function to initialize various fields during construction.
  void Initialize(int64 id);

  // Called when the favicon becomes invalid.
  void InvalidateFavicon();

  // Sets the favicon's URL.
  void set_icon_url(const GURL& icon_url) {
    icon_url_ = icon_url;
  }

  const gfx::Image& favicon() const { return favicon_; }
  void set_favicon(const gfx::Image& icon) { favicon_ = icon; }

  FaviconState favicon_state() const { return favicon_state_; }
  void set_favicon_state(FaviconState state) { favicon_state_ = state; }

  base::CancelableTaskTracker::TaskId favicon_load_task_id() const {
    return favicon_load_task_id_;
  }
  void set_favicon_load_task_id(base::CancelableTaskTracker::TaskId id) {
    favicon_load_task_id_ = id;
  }

  // The unique identifier for this node.
  int64 id_;

  // The URL of this node. BookmarkModel maintains maps off this URL, so changes
  // to the URL must be done through the BookmarkModel.
  GURL url_;

  // The type of this node. See enum above.
  Type type_;

  // Date of when this node was created.
  base::Time date_added_;

  // Date of the last modification. Only used for folders.
  base::Time date_folder_modified_;

  // The favicon of this node.
  gfx::Image favicon_;

  // The URL of the node's favicon.
  GURL icon_url_;

  // The loading state of the favicon.
  FaviconState favicon_state_;

  // If not base::CancelableTaskTracker::kBadTaskId, it indicates
  // we're loading the
  // favicon and the task is tracked by CancelabelTaskTracker.
  base::CancelableTaskTracker::TaskId favicon_load_task_id_;

  // A map that stores arbitrary meta information about the node.
  scoped_ptr<MetaInfoMap> meta_info_map_;

  // The sync transaction version. Defaults to kInvalidSyncTransactionVersion.
  int64 sync_transaction_version_;

  DISALLOW_COPY_AND_ASSIGN(BookmarkNode);
};

// BookmarkPermanentNode -------------------------------------------------------

// Node used for the permanent folders (excluding the root).
class BookmarkPermanentNode : public BookmarkNode {
 public:
  explicit BookmarkPermanentNode(int64 id);
  virtual ~BookmarkPermanentNode();

  // WARNING: this code is used for other projects. Contact noyau@ for details.
  void set_visible(bool value) { visible_ = value; }

  // BookmarkNode overrides:
  virtual bool IsVisible() const OVERRIDE;

 private:
  bool visible_;

  DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNode);
};

// 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 content::NotificationObserver,
                      public BookmarkService,
                      public KeyedService {
 public:
  explicit BookmarkModel(Profile* profile);
  virtual ~BookmarkModel();

  // Invoked prior to destruction to release any necessary resources.
  virtual void Shutdown() 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 |task_runner|.
  void Load(const scoped_refptr<base::SequencedTaskRunner>& task_runner);

  // Returns true if the model finished loading.
  bool loaded() const { return loaded_; }

  // 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* bookmark_bar_node() { return bookmark_bar_node_; }

  // Returns the 'other' node. This is NULL until loaded.
  const BookmarkNode* other_node() { return other_node_; }

  // Returns the 'mobile' node. This is NULL until loaded.
  const BookmarkNode* mobile_node() { 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.
  bool is_permanent_node(const BookmarkNode* node) const {
    return node == &root_ ||
           node == bookmark_bar_node_ ||
           node == other_node_ ||
           node == mobile_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);
  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 the node at the given |index| from |parent|. Removing a folder node
  // recursively removes all nodes. Observers are notified immediately.
  void Remove(const BookmarkNode* parent, int index);

  // Removes all the non-permanent bookmark nodes. Observers are only notified
  // when all nodes have been removed. There is no notification for individual
  // node removals.
  void RemoveAll();

  // Moves |node| to |new_parent| and inserts it at the given |index|.
  void Move(const BookmarkNode* node,
            const BookmarkNode* new_parent,
            int index);

  // Inserts a copy of |node| into |new_parent| at |index|.
  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 gfx::Image& GetFavicon(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 node for the |url|. Returns NULL if |url|
  // is not bookmarked.
  const BookmarkNode* GetMostRecentlyAddedNodeForURL(const GURL& url);

  // Returns true if there are bookmarks, otherwise returns false.
  // This method is thread safe.
  bool HasBookmarks();

  // Returns true if there is a bookmark with the |url|.
  // This method is thread safe.
  // See BookmarkService for more details on this.
  virtual bool IsBookmarked(const GURL& url) OVERRIDE;

  // Returns all the bookmarked urls and their titles.
  // This method is thread safe.
  // See BookmarkService for more details on this.
  virtual void GetBookmarks(
      std::vector<BookmarkService::URLAndTitle>* urls) OVERRIDE;

  // Blocks until loaded; this is NOT invoked on the main thread.
  // See BookmarkService for more details on this.
  virtual void BlockTillLoaded() OVERRIDE;

  // Returns the node with |id|, or NULL if there is no node with |id|.
  const BookmarkNode* GetNodeByID(int64 id) const;

  // Adds a new folder node at the specified position.
  const BookmarkNode* AddFolder(const BookmarkNode* parent,
                                int index,
                                const base::string16& title);

  // Adds a url at the specified position.
  const BookmarkNode* AddURL(const BookmarkNode* parent,
                             int index,
                             const base::string16& title,
                             const GURL& url);

  // Adds a url with a specific creation date.
  const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
                                             int index,
                                             const base::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);

  // 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);

  void GetBookmarksWithTitlesMatching(
      const base::string16& text,
      size_t max_count,
      std::vector<BookmarkTitleMatch>* 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 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. This is set by sync.
  void SetPermanentNodeVisible(BookmarkNode::Type type, bool value);

  // 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);

  // Sets the sync transaction version of |node|.
  void SetNodeSyncTransactionVersion(const BookmarkNode* node,
                                     int64 sync_transaction_version);

  // Returns the profile that corresponds to this BookmarkModel.
  Profile* profile() { return profile_; }

 private:
  friend class BookmarkCodecTest;
  friend class BookmarkModelTest;
  friend class BookmarkStorage;
  friend class ScopedGroupBookmarkActions;

  // Used to order BookmarkNodes by URL.
  class NodeURLComparator {
   public:
    bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
      return n1->url() < n2->url();
    }
  };

  // Implementation of IsBookmarked. Before calling this the caller must obtain
  // a lock on |url_lock_|.
  bool IsBookmarkedNoLock(const GURL& url);

  // 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, but does not delete it. No notifications
  // are sent. |removed_urls| is populated with the urls which no longer have
  // any bookmarks associated with them.
  // This method should be called after acquiring |url_lock_|.
  void RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
                                   std::set<GURL>* removed_urls);

  // Removes the node from its parent, sends notification, and deletes it.
  // type specifies how the node should be removed.
  void RemoveAndDeleteNode(BookmarkNode* delete_me);

  // Remove |node| from |nodes_ordered_by_url_set_|.
  void RemoveNodeFromURLSet(BookmarkNode* node);

  // Notifies the history backend about urls of removed bookmarks.
  void NotifyHistoryAboutRemovedBookmarks(
      const std::set<GURL>& removed_bookmark_urls) const;

  // Adds the |node| at |parent| in the specified |index| and notifies its
  // observers.
  BookmarkNode* AddNode(BookmarkNode* parent,
                        int index,
                        BookmarkNode* node);

  // Implementation of GetNodeByID.
  const BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id) const;

  // Returns true if the parent and index are valid.
  bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end);

  // Creates one of the possible permanent nodes (bookmark bar node, other node
  // and mobile node) from |type|.
  BookmarkPermanentNode* CreatePermanentNode(BookmarkNode::Type type);

  // Notification that a favicon has finished loading. If we can decode the
  // favicon, FaviconLoaded is invoked.
  void OnFaviconDataAvailable(BookmarkNode* node,
                              const chrome::FaviconImageResult& image_result);

  // Invoked from the node to load the favicon. Requests the favicon from the
  // favicon service.
  void LoadFavicon(BookmarkNode* node);

  // 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();

  // content::NotificationObserver:
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

  // 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; }

  // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
  // delete the returned object.
  BookmarkLoadDetails* CreateLoadDetails();

  content::NotificationRegistrar registrar_;

  Profile* profile_;

  // Whether the initial set of data has been loaded.
  bool loaded_;

  // The root node. This contains the bookmark bar node and the 'other' node as
  // children.
  BookmarkNode root_;

  BookmarkPermanentNode* bookmark_bar_node_;
  BookmarkPermanentNode* other_node_;
  BookmarkPermanentNode* mobile_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.
  base::CancelableTaskTracker cancelable_task_tracker_;

  // Reads/writes bookmarks to disk.
  scoped_refptr<BookmarkStorage> store_;

  scoped_ptr<BookmarkIndex> index_;

  base::WaitableEvent loaded_signal_;

  // See description of IsDoingExtensiveChanges above.
  int extensive_changes_;

  scoped_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_;

  DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
};

#endif  // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_

/* [<][>][^][v][top][bottom][index][help] */