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 <map> 9 #include <set> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/compiler_specific.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/observer_list.h" 17 #include "base/strings/string16.h" 18 #include "base/synchronization/lock.h" 19 #include "base/synchronization/waitable_event.h" 20 #include "components/bookmarks/browser/bookmark_client.h" 21 #include "components/bookmarks/browser/bookmark_node.h" 22 #include "components/keyed_service/core/keyed_service.h" 23 #include "ui/gfx/image/image.h" 24 #include "url/gurl.h" 25 26 class BookmarkModelObserver; 27 class PrefService; 28 29 namespace base { 30 class FilePath; 31 class SequencedTaskRunner; 32 } 33 34 namespace bookmarks { 35 class BookmarkCodecTest; 36 class BookmarkExpandedStateTracker; 37 class BookmarkIndex; 38 class BookmarkLoadDetails; 39 class BookmarkStorage; 40 class ScopedGroupBookmarkActions; 41 class TestBookmarkClient; 42 struct BookmarkMatch; 43 } 44 45 namespace favicon_base { 46 struct FaviconImageResult; 47 } 48 49 // BookmarkModel -------------------------------------------------------------- 50 51 // BookmarkModel provides a directed acyclic graph of URLs and folders. 52 // Three graphs are provided for the three entry points: those on the 'bookmarks 53 // bar', those in the 'other bookmarks' folder and those in the 'mobile' folder. 54 // 55 // An observer may be attached to observe relevant events. 56 // 57 // You should NOT directly create a BookmarkModel, instead go through the 58 // BookmarkModelFactory. 59 class BookmarkModel : public KeyedService { 60 public: 61 struct URLAndTitle { 62 GURL url; 63 base::string16 title; 64 }; 65 66 explicit BookmarkModel(bookmarks::BookmarkClient* client); 67 virtual ~BookmarkModel(); 68 69 // KeyedService: 70 virtual void Shutdown() OVERRIDE; 71 72 // Loads the bookmarks. This is called upon creation of the 73 // BookmarkModel. You need not invoke this directly. 74 // All load operations will be executed on |io_task_runner| and the completion 75 // callback will be called from |ui_task_runner|. 76 void Load(PrefService* pref_service, 77 const std::string& accept_languages, 78 const base::FilePath& profile_path, 79 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner, 80 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner); 81 82 // Returns true if the model finished loading. loaded()83 bool loaded() const { return loaded_; } 84 85 // Returns the root node. The 'bookmark bar' node and 'other' node are 86 // children of the root node. root_node()87 const BookmarkNode* root_node() const { return &root_; } 88 89 // Returns the 'bookmark bar' node. This is NULL until loaded. bookmark_bar_node()90 const BookmarkNode* bookmark_bar_node() const { return bookmark_bar_node_; } 91 92 // Returns the 'other' node. This is NULL until loaded. other_node()93 const BookmarkNode* other_node() const { return other_node_; } 94 95 // Returns the 'mobile' node. This is NULL until loaded. mobile_node()96 const BookmarkNode* mobile_node() const { return mobile_node_; } 97 is_root_node(const BookmarkNode * node)98 bool is_root_node(const BookmarkNode* node) const { return node == &root_; } 99 100 // Returns whether the given |node| is one of the permanent nodes - root node, 101 // 'bookmark bar' node, 'other' node or 'mobile' node, or one of the root 102 // nodes supplied by the |client_|. is_permanent_node(const BookmarkNode * node)103 bool is_permanent_node(const BookmarkNode* node) const { 104 return node && (node == &root_ || node->parent() == &root_); 105 } 106 107 // Returns the parent the last node was added to. This never returns NULL 108 // (as long as the model is loaded). 109 const BookmarkNode* GetParentForNewNodes(); 110 111 void AddObserver(BookmarkModelObserver* observer); 112 void RemoveObserver(BookmarkModelObserver* observer); 113 114 // Notifies the observers that an extensive set of changes is about to happen, 115 // such as during import or sync, so they can delay any expensive UI updates 116 // until it's finished. 117 void BeginExtensiveChanges(); 118 void EndExtensiveChanges(); 119 120 // Returns true if this bookmark model is currently in a mode where extensive 121 // changes might happen, such as for import and sync. This is helpful for 122 // observers that are created after the mode has started, and want to check 123 // state during their own initializer, such as the NTP. IsDoingExtensiveChanges()124 bool IsDoingExtensiveChanges() const { return extensive_changes_ > 0; } 125 126 // Removes the node at the given |index| from |parent|. Removing a folder node 127 // recursively removes all nodes. Observers are notified immediately. 128 void Remove(const BookmarkNode* parent, int index); 129 130 // Removes all the non-permanent bookmark nodes that are editable by the user. 131 // Observers are only notified when all nodes have been removed. There is no 132 // notification for individual node removals. 133 void RemoveAllUserBookmarks(); 134 135 // Moves |node| to |new_parent| and inserts it at the given |index|. 136 void Move(const BookmarkNode* node, 137 const BookmarkNode* new_parent, 138 int index); 139 140 // Inserts a copy of |node| into |new_parent| at |index|. 141 void Copy(const BookmarkNode* node, 142 const BookmarkNode* new_parent, 143 int index); 144 145 // Returns the favicon for |node|. If the favicon has not yet been 146 // loaded it is loaded and the observer of the model notified when done. 147 const gfx::Image& GetFavicon(const BookmarkNode* node); 148 149 // Returns the type of the favicon for |node|. If the favicon has not yet 150 // been loaded, it returns |favicon_base::INVALID_ICON|. 151 favicon_base::IconType GetFaviconType(const BookmarkNode* node); 152 153 // Sets the title of |node|. 154 void SetTitle(const BookmarkNode* node, const base::string16& title); 155 156 // Sets the URL of |node|. 157 void SetURL(const BookmarkNode* node, const GURL& url); 158 159 // Sets the date added time of |node|. 160 void SetDateAdded(const BookmarkNode* node, base::Time date_added); 161 162 // Returns the set of nodes with the |url|. 163 void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes); 164 165 // Returns the most recently added user node for the |url|; urls from any 166 // nodes that are not editable by the user are never returned by this call. 167 // Returns NULL if |url| is not bookmarked. 168 const BookmarkNode* GetMostRecentlyAddedUserNodeForURL(const GURL& url); 169 170 // Returns true if there are bookmarks, otherwise returns false. 171 // This method is thread safe. 172 bool HasBookmarks(); 173 174 // Returns true if the specified URL is bookmarked. 175 // 176 // If not on the main thread you *must* invoke BlockTillLoaded first. 177 bool IsBookmarked(const GURL& url); 178 179 // Returns, by reference in |bookmarks|, the set of bookmarked urls and their 180 // titles. This returns the unique set of URLs. For example, if two bookmarks 181 // reference the same URL only one entry is added not matter the titles are 182 // same or not. 183 // 184 // If not on the main thread you *must* invoke BlockTillLoaded first. 185 void GetBookmarks(std::vector<BookmarkModel::URLAndTitle>* urls); 186 187 // Blocks until loaded. This is intended for usage on a thread other than 188 // the main thread. 189 void BlockTillLoaded(); 190 191 // Adds a new folder node at the specified position. 192 const BookmarkNode* AddFolder(const BookmarkNode* parent, 193 int index, 194 const base::string16& title); 195 196 // Adds a new folder with meta info. 197 const BookmarkNode* AddFolderWithMetaInfo( 198 const BookmarkNode* parent, 199 int index, 200 const base::string16& title, 201 const BookmarkNode::MetaInfoMap* meta_info); 202 203 // Adds a url at the specified position. 204 const BookmarkNode* AddURL(const BookmarkNode* parent, 205 int index, 206 const base::string16& title, 207 const GURL& url); 208 209 // Adds a url with a specific creation date and meta info. 210 const BookmarkNode* AddURLWithCreationTimeAndMetaInfo( 211 const BookmarkNode* parent, 212 int index, 213 const base::string16& title, 214 const GURL& url, 215 const base::Time& creation_time, 216 const BookmarkNode::MetaInfoMap* meta_info); 217 218 // Sorts the children of |parent|, notifying observers by way of the 219 // BookmarkNodeChildrenReordered method. 220 void SortChildren(const BookmarkNode* parent); 221 222 // Order the children of |parent| as specified in |ordered_nodes|. This 223 // function should only be used to reorder the child nodes of |parent| and 224 // is not meant to move nodes between different parent. Notifies observers 225 // using the BookmarkNodeChildrenReordered method. 226 void ReorderChildren(const BookmarkNode* parent, 227 const std::vector<const BookmarkNode*>& ordered_nodes); 228 229 // Sets the date when the folder was modified. 230 void SetDateFolderModified(const BookmarkNode* node, const base::Time time); 231 232 // Resets the 'date modified' time of the node to 0. This is used during 233 // importing to exclude the newly created folders from showing up in the 234 // combobox of most recently modified folders. 235 void ResetDateFolderModified(const BookmarkNode* node); 236 237 // Returns up to |max_count| of bookmarks containing each term from |text| 238 // in either the title or the URL. 239 void GetBookmarksMatching(const base::string16& text, 240 size_t max_count, 241 std::vector<bookmarks::BookmarkMatch>* matches); 242 243 // Sets the store to NULL, making it so the BookmarkModel does not persist 244 // any changes to disk. This is only useful during testing to speed up 245 // testing. 246 void ClearStore(); 247 248 // Returns the next node ID. next_node_id()249 int64 next_node_id() const { return next_node_id_; } 250 251 // Returns the object responsible for tracking the set of expanded nodes in 252 // the bookmark editor. expanded_state_tracker()253 bookmarks::BookmarkExpandedStateTracker* expanded_state_tracker() { 254 return expanded_state_tracker_.get(); 255 } 256 257 // Sets the visibility of one of the permanent nodes (unless the node must 258 // always be visible, see |BookmarkClient::IsPermanentNodeVisible| for more 259 // details). This is set by sync. 260 void SetPermanentNodeVisible(BookmarkNode::Type type, bool value); 261 262 // Returns the permanent node of type |type|. 263 const BookmarkPermanentNode* PermanentNode(BookmarkNode::Type type); 264 265 // Sets/deletes meta info of |node|. 266 void SetNodeMetaInfo(const BookmarkNode* node, 267 const std::string& key, 268 const std::string& value); 269 void SetNodeMetaInfoMap(const BookmarkNode* node, 270 const BookmarkNode::MetaInfoMap& meta_info_map); 271 void DeleteNodeMetaInfo(const BookmarkNode* node, 272 const std::string& key); 273 274 // Sets the sync transaction version of |node|. 275 void SetNodeSyncTransactionVersion(const BookmarkNode* node, 276 int64 sync_transaction_version); 277 278 // Notify BookmarkModel that the favicons for |urls| have changed and have to 279 // be refetched. This notification is sent by BookmarkClient. 280 void OnFaviconChanged(const std::set<GURL>& urls); 281 282 // Returns the client used by this BookmarkModel. client()283 bookmarks::BookmarkClient* client() const { return client_; } 284 285 private: 286 friend class bookmarks::BookmarkCodecTest; 287 friend class bookmarks::BookmarkStorage; 288 friend class bookmarks::ScopedGroupBookmarkActions; 289 friend class bookmarks::TestBookmarkClient; 290 291 // Used to order BookmarkNodes by URL. 292 class NodeURLComparator { 293 public: operator()294 bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const { 295 return n1->url() < n2->url(); 296 } 297 }; 298 299 // Implementation of IsBookmarked. Before calling this the caller must obtain 300 // a lock on |url_lock_|. 301 bool IsBookmarkedNoLock(const GURL& url); 302 303 // Removes the node from internal maps and recurses through all children. If 304 // the node is a url, its url is added to removed_urls. 305 // 306 // This does NOT delete the node. 307 void RemoveNode(BookmarkNode* node, std::set<GURL>* removed_urls); 308 309 // Invoked when loading is finished. Sets |loaded_| and notifies observers. 310 // BookmarkModel takes ownership of |details|. 311 void DoneLoading(scoped_ptr<bookmarks::BookmarkLoadDetails> details); 312 313 // Populates |nodes_ordered_by_url_set_| from root. 314 void PopulateNodesByURL(BookmarkNode* node); 315 316 // Removes the node from its parent, but does not delete it. No notifications 317 // are sent. |removed_urls| is populated with the urls which no longer have 318 // any bookmarks associated with them. 319 // This method should be called after acquiring |url_lock_|. 320 void RemoveNodeAndGetRemovedUrls(BookmarkNode* node, 321 std::set<GURL>* removed_urls); 322 323 // Removes the node from its parent, sends notification, and deletes it. 324 // type specifies how the node should be removed. 325 void RemoveAndDeleteNode(BookmarkNode* delete_me); 326 327 // Remove |node| from |nodes_ordered_by_url_set_|. 328 void RemoveNodeFromURLSet(BookmarkNode* node); 329 330 // Adds the |node| at |parent| in the specified |index| and notifies its 331 // observers. 332 BookmarkNode* AddNode(BookmarkNode* parent, 333 int index, 334 BookmarkNode* node); 335 336 // Returns true if the parent and index are valid. 337 bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end); 338 339 // Creates one of the possible permanent nodes (bookmark bar node, other node 340 // and mobile node) from |type|. 341 BookmarkPermanentNode* CreatePermanentNode(BookmarkNode::Type type); 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 favicon_base::IconType icon_type, 348 const favicon_base::FaviconImageResult& image_result); 349 350 // Invoked from the node to load the favicon. Requests the favicon from the 351 // favicon service. 352 void LoadFavicon(BookmarkNode* node, favicon_base::IconType icon_type); 353 354 // Called to notify the observers that the favicon has been loaded. 355 void FaviconLoaded(const BookmarkNode* node); 356 357 // If we're waiting on a favicon for node, the load request is canceled. 358 void CancelPendingFaviconLoadRequests(BookmarkNode* node); 359 360 // Notifies the observers that a set of changes initiated by a single user 361 // action is about to happen and has completed. 362 void BeginGroupedChanges(); 363 void EndGroupedChanges(); 364 365 // Generates and returns the next node ID. 366 int64 generate_next_node_id(); 367 368 // Sets the maximum node ID to the given value. 369 // This is used by BookmarkCodec to report the maximum ID after it's done 370 // decoding since during decoding codec assigns node IDs. set_next_node_id(int64 id)371 void set_next_node_id(int64 id) { next_node_id_ = id; } 372 373 // Creates and returns a new BookmarkLoadDetails. It's up to the caller to 374 // delete the returned object. 375 scoped_ptr<bookmarks::BookmarkLoadDetails> CreateLoadDetails( 376 const std::string& accept_languages); 377 378 bookmarks::BookmarkClient* const client_; 379 380 // Whether the initial set of data has been loaded. 381 bool loaded_; 382 383 // The root node. This contains the bookmark bar node, the 'other' node and 384 // the mobile node as children. 385 BookmarkNode root_; 386 387 BookmarkPermanentNode* bookmark_bar_node_; 388 BookmarkPermanentNode* other_node_; 389 BookmarkPermanentNode* mobile_node_; 390 391 // The maximum ID assigned to the bookmark nodes in the model. 392 int64 next_node_id_; 393 394 // The observers. 395 ObserverList<BookmarkModelObserver> observers_; 396 397 // Set of nodes ordered by URL. This is not a map to avoid copying the 398 // urls. 399 // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As 400 // such, be sure and wrap all usage of it around |url_lock_|. 401 typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet; 402 NodesOrderedByURLSet nodes_ordered_by_url_set_; 403 base::Lock url_lock_; 404 405 // Used for loading favicons. 406 base::CancelableTaskTracker cancelable_task_tracker_; 407 408 // Reads/writes bookmarks to disk. 409 scoped_ptr<bookmarks::BookmarkStorage> store_; 410 411 scoped_ptr<bookmarks::BookmarkIndex> index_; 412 413 base::WaitableEvent loaded_signal_; 414 415 // See description of IsDoingExtensiveChanges above. 416 int extensive_changes_; 417 418 scoped_ptr<bookmarks::BookmarkExpandedStateTracker> expanded_state_tracker_; 419 420 DISALLOW_COPY_AND_ASSIGN(BookmarkModel); 421 }; 422 423 #endif // COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_H_ 424