1 // Copyright (c) 2012 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 CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_ 6 #define CHROME_BROWSER_BOOKMARKS_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 "chrome/browser/bookmarks/bookmark_service.h" 21 #include "chrome/common/cancelable_task_tracker.h" 22 #include "components/browser_context_keyed_service/browser_context_keyed_service.h" 23 #include "content/public/browser/notification_observer.h" 24 #include "content/public/browser/notification_registrar.h" 25 #include "ui/base/models/tree_node_model.h" 26 #include "ui/gfx/image/image.h" 27 #include "url/gurl.h" 28 29 class BookmarkExpandedStateTracker; 30 class BookmarkIndex; 31 class BookmarkLoadDetails; 32 class BookmarkModel; 33 class BookmarkModelObserver; 34 class BookmarkStorage; 35 struct BookmarkTitleMatch; 36 class Profile; 37 38 namespace base { 39 class SequencedTaskRunner; 40 } 41 42 namespace chrome { 43 struct FaviconImageResult; 44 } 45 46 // BookmarkNode --------------------------------------------------------------- 47 48 // BookmarkNode contains information about a starred entry: title, URL, favicon, 49 // id and type. BookmarkNodes are returned from BookmarkModel. 50 class BookmarkNode : public ui::TreeNode<BookmarkNode> { 51 public: 52 enum Type { 53 URL, 54 FOLDER, 55 BOOKMARK_BAR, 56 OTHER_NODE, 57 MOBILE 58 }; 59 60 enum FaviconState { 61 INVALID_FAVICON, 62 LOADING_FAVICON, 63 LOADED_FAVICON, 64 }; 65 66 typedef std::map<std::string, std::string> MetaInfoMap; 67 68 static const int64 kInvalidSyncTransactionVersion; 69 70 // Creates a new node with an id of 0 and |url|. 71 explicit BookmarkNode(const GURL& url); 72 // Creates a new node with |id| and |url|. 73 BookmarkNode(int64 id, const GURL& url); 74 75 virtual ~BookmarkNode(); 76 77 // Set the node's internal title. Note that this neither invokes observers 78 // nor updates any bookmark model this node may be in. For that functionality, 79 // BookmarkModel::SetTitle(..) should be used instead. 80 virtual void SetTitle(const base::string16& title) OVERRIDE; 81 82 // Returns an unique id for this node. 83 // For bookmark nodes that are managed by the bookmark model, the IDs are 84 // persisted across sessions. 85 int64 id() const { return id_; } 86 void set_id(int64 id) { id_ = id; } 87 88 const GURL& url() const { return url_; } 89 void set_url(const GURL& url) { url_ = url; } 90 91 // Returns the favicon's URL. Returns an empty URL if there is no favicon 92 // associated with this bookmark. 93 const GURL& icon_url() const { return icon_url_; } 94 95 Type type() const { return type_; } 96 void set_type(Type type) { type_ = type; } 97 98 // Returns the time the node was added. 99 const base::Time& date_added() const { return date_added_; } 100 void set_date_added(const base::Time& date) { date_added_ = date; } 101 102 // Returns the last time the folder was modified. This is only maintained 103 // for folders (including the bookmark bar and other folder). 104 const base::Time& date_folder_modified() const { 105 return date_folder_modified_; 106 } 107 void set_date_folder_modified(const base::Time& date) { 108 date_folder_modified_ = date; 109 } 110 111 // Convenience for testing if this node represents a folder. A folder is a 112 // node whose type is not URL. 113 bool is_folder() const { return type_ != URL; } 114 bool is_url() const { return type_ == URL; } 115 116 bool is_favicon_loaded() const { return favicon_state_ == LOADED_FAVICON; } 117 118 // Accessor method for controlling the visibility of a bookmark node/sub-tree. 119 // Note that visibility is not propagated down the tree hierarchy so if a 120 // parent node is marked as invisible, a child node may return "Visible". This 121 // function is primarily useful when traversing the model to generate a UI 122 // representation but we may want to suppress some nodes. 123 virtual bool IsVisible() const; 124 125 // Gets/sets/deletes value of |key| in the meta info represented by 126 // |meta_info_str_|. Return true if key is found in meta info for gets or 127 // meta info is changed indeed for sets/deletes. 128 bool GetMetaInfo(const std::string& key, std::string* value) const; 129 bool SetMetaInfo(const std::string& key, const std::string& value); 130 bool DeleteMetaInfo(const std::string& key); 131 void SetMetaInfoMap(const MetaInfoMap& meta_info_map); 132 // Returns NULL if there are no values in the map. 133 const MetaInfoMap* GetMetaInfoMap() const; 134 135 void set_sync_transaction_version(int64 sync_transaction_version) { 136 sync_transaction_version_ = sync_transaction_version; 137 } 138 int64 sync_transaction_version() const { 139 return sync_transaction_version_; 140 } 141 142 // TODO(sky): Consider adding last visit time here, it'll greatly simplify 143 // HistoryContentsProvider. 144 145 private: 146 friend class BookmarkModel; 147 148 // A helper function to initialize various fields during construction. 149 void Initialize(int64 id); 150 151 // Called when the favicon becomes invalid. 152 void InvalidateFavicon(); 153 154 // Sets the favicon's URL. 155 void set_icon_url(const GURL& icon_url) { 156 icon_url_ = icon_url; 157 } 158 159 const gfx::Image& favicon() const { return favicon_; } 160 void set_favicon(const gfx::Image& icon) { favicon_ = icon; } 161 162 FaviconState favicon_state() const { return favicon_state_; } 163 void set_favicon_state(FaviconState state) { favicon_state_ = state; } 164 165 CancelableTaskTracker::TaskId favicon_load_task_id() const { 166 return favicon_load_task_id_; 167 } 168 void set_favicon_load_task_id(CancelableTaskTracker::TaskId id) { 169 favicon_load_task_id_ = id; 170 } 171 172 // The unique identifier for this node. 173 int64 id_; 174 175 // The URL of this node. BookmarkModel maintains maps off this URL, so changes 176 // to the URL must be done through the BookmarkModel. 177 GURL url_; 178 179 // The type of this node. See enum above. 180 Type type_; 181 182 // Date of when this node was created. 183 base::Time date_added_; 184 185 // Date of the last modification. Only used for folders. 186 base::Time date_folder_modified_; 187 188 // The favicon of this node. 189 gfx::Image favicon_; 190 191 // The URL of the node's favicon. 192 GURL icon_url_; 193 194 // The loading state of the favicon. 195 FaviconState favicon_state_; 196 197 // If not CancelableTaskTracker::kBadTaskId, it indicates we're loading the 198 // favicon and the task is tracked by CancelabelTaskTracker. 199 CancelableTaskTracker::TaskId favicon_load_task_id_; 200 201 // A map that stores arbitrary meta information about the node. 202 scoped_ptr<MetaInfoMap> meta_info_map_; 203 204 // The sync transaction version. Defaults to kInvalidSyncTransactionVersion. 205 int64 sync_transaction_version_; 206 207 DISALLOW_COPY_AND_ASSIGN(BookmarkNode); 208 }; 209 210 // BookmarkPermanentNode ------------------------------------------------------- 211 212 // Node used for the permanent folders (excluding the root). 213 class BookmarkPermanentNode : public BookmarkNode { 214 public: 215 explicit BookmarkPermanentNode(int64 id); 216 virtual ~BookmarkPermanentNode(); 217 218 // WARNING: this code is used for other projects. Contact noyau@ for details. 219 void set_visible(bool value) { visible_ = value; } 220 221 // BookmarkNode overrides: 222 virtual bool IsVisible() const OVERRIDE; 223 224 private: 225 bool visible_; 226 227 DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNode); 228 }; 229 230 // BookmarkModel -------------------------------------------------------------- 231 232 // BookmarkModel provides a directed acyclic graph of URLs and folders. 233 // Three graphs are provided for the three entry points: those on the 'bookmarks 234 // bar', those in the 'other bookmarks' folder and those in the 'mobile' folder. 235 // 236 // An observer may be attached to observe relevant events. 237 // 238 // You should NOT directly create a BookmarkModel, instead go through the 239 // BookmarkModelFactory. 240 class BookmarkModel : public content::NotificationObserver, 241 public BookmarkService, 242 public BrowserContextKeyedService { 243 public: 244 explicit BookmarkModel(Profile* profile); 245 virtual ~BookmarkModel(); 246 247 // Invoked prior to destruction to release any necessary resources. 248 virtual void Shutdown() OVERRIDE; 249 250 // Loads the bookmarks. This is called upon creation of the 251 // BookmarkModel. You need not invoke this directly. 252 // All load operations will be executed on |task_runner|. 253 void Load(const scoped_refptr<base::SequencedTaskRunner>& task_runner); 254 255 // Returns true if the model finished loading. 256 bool loaded() const { return loaded_; } 257 258 // Returns the root node. The 'bookmark bar' node and 'other' node are 259 // children of the root node. 260 const BookmarkNode* root_node() { return &root_; } 261 262 // Returns the 'bookmark bar' node. This is NULL until loaded. 263 const BookmarkNode* bookmark_bar_node() { return bookmark_bar_node_; } 264 265 // Returns the 'other' node. This is NULL until loaded. 266 const BookmarkNode* other_node() { return other_node_; } 267 268 // Returns the 'mobile' node. This is NULL until loaded. 269 const BookmarkNode* mobile_node() { return mobile_node_; } 270 271 bool is_root_node(const BookmarkNode* node) const { return node == &root_; } 272 273 // Returns whether the given |node| is one of the permanent nodes - root node, 274 // 'bookmark bar' node, 'other' node or 'mobile' node. 275 bool is_permanent_node(const BookmarkNode* node) const { 276 return node == &root_ || 277 node == bookmark_bar_node_ || 278 node == other_node_ || 279 node == mobile_node_; 280 } 281 282 // Returns the parent the last node was added to. This never returns NULL 283 // (as long as the model is loaded). 284 const BookmarkNode* GetParentForNewNodes(); 285 286 void AddObserver(BookmarkModelObserver* observer); 287 void RemoveObserver(BookmarkModelObserver* observer); 288 289 // Notifies the observers that an extensive set of changes is about to happen, 290 // such as during import or sync, so they can delay any expensive UI updates 291 // until it's finished. 292 void BeginExtensiveChanges(); 293 void EndExtensiveChanges(); 294 295 // Returns true if this bookmark model is currently in a mode where extensive 296 // changes might happen, such as for import and sync. This is helpful for 297 // observers that are created after the mode has started, and want to check 298 // state during their own initializer, such as the NTP. 299 bool IsDoingExtensiveChanges() const { return extensive_changes_ > 0; } 300 301 // Removes the node at the given |index| from |parent|. Removing a folder node 302 // recursively removes all nodes. Observers are notified immediately. 303 void Remove(const BookmarkNode* parent, int index); 304 305 // Removes all the non-permanent bookmark nodes. Observers are only notified 306 // when all nodes have been removed. There is no notification for individual 307 // node removals. 308 void RemoveAll(); 309 310 // Moves |node| to |new_parent| and inserts it at the given |index|. 311 void Move(const BookmarkNode* node, 312 const BookmarkNode* new_parent, 313 int index); 314 315 // Inserts a copy of |node| into |new_parent| at |index|. 316 void Copy(const BookmarkNode* node, 317 const BookmarkNode* new_parent, 318 int index); 319 320 // Returns the favicon for |node|. If the favicon has not yet been 321 // loaded it is loaded and the observer of the model notified when done. 322 const gfx::Image& GetFavicon(const BookmarkNode* node); 323 324 // Sets the title of |node|. 325 void SetTitle(const BookmarkNode* node, const base::string16& title); 326 327 // Sets the URL of |node|. 328 void SetURL(const BookmarkNode* node, const GURL& url); 329 330 // Sets the date added time of |node|. 331 void SetDateAdded(const BookmarkNode* node, base::Time date_added); 332 333 // Returns the set of nodes with the |url|. 334 void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes); 335 336 // Returns the most recently added node for the |url|. Returns NULL if |url| 337 // is not bookmarked. 338 const BookmarkNode* GetMostRecentlyAddedNodeForURL(const GURL& url); 339 340 // Returns true if there are bookmarks, otherwise returns false. 341 // This method is thread safe. 342 bool HasBookmarks(); 343 344 // Returns true if there is a bookmark with the |url|. 345 // This method is thread safe. 346 // See BookmarkService for more details on this. 347 virtual bool IsBookmarked(const GURL& url) OVERRIDE; 348 349 // Returns all the bookmarked urls and their titles. 350 // This method is thread safe. 351 // See BookmarkService for more details on this. 352 virtual void GetBookmarks( 353 std::vector<BookmarkService::URLAndTitle>* urls) OVERRIDE; 354 355 // Blocks until loaded; this is NOT invoked on the main thread. 356 // See BookmarkService for more details on this. 357 virtual void BlockTillLoaded() OVERRIDE; 358 359 // Returns the node with |id|, or NULL if there is no node with |id|. 360 const BookmarkNode* GetNodeByID(int64 id) const; 361 362 // Adds a new folder node at the specified position. 363 const BookmarkNode* AddFolder(const BookmarkNode* parent, 364 int index, 365 const base::string16& title); 366 367 // Adds a url at the specified position. 368 const BookmarkNode* AddURL(const BookmarkNode* parent, 369 int index, 370 const base::string16& title, 371 const GURL& url); 372 373 // Adds a url with a specific creation date. 374 const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent, 375 int index, 376 const base::string16& title, 377 const GURL& url, 378 const base::Time& creation_time); 379 380 // Sorts the children of |parent|, notifying observers by way of the 381 // BookmarkNodeChildrenReordered method. 382 void SortChildren(const BookmarkNode* parent); 383 384 // Order the children of |parent| as specified in |ordered_nodes|. This 385 // function should only be used to reorder the child nodes of |parent| and 386 // is not meant to move nodes between different parent. Notifies observers 387 // using the BookmarkNodeChildrenReordered method. 388 void ReorderChildren(const BookmarkNode* parent, 389 const std::vector<const BookmarkNode*>& ordered_nodes); 390 391 // Sets the date when the folder was modified. 392 void SetDateFolderModified(const BookmarkNode* node, const base::Time time); 393 394 // Resets the 'date modified' time of the node to 0. This is used during 395 // importing to exclude the newly created folders from showing up in the 396 // combobox of most recently modified folders. 397 void ResetDateFolderModified(const BookmarkNode* node); 398 399 void GetBookmarksWithTitlesMatching( 400 const base::string16& text, 401 size_t max_count, 402 std::vector<BookmarkTitleMatch>* matches); 403 404 // Sets the store to NULL, making it so the BookmarkModel does not persist 405 // any changes to disk. This is only useful during testing to speed up 406 // testing. 407 void ClearStore(); 408 409 // Returns the next node ID. 410 int64 next_node_id() const { return next_node_id_; } 411 412 // Returns the object responsible for tracking the set of expanded nodes in 413 // the bookmark editor. 414 BookmarkExpandedStateTracker* expanded_state_tracker() { 415 return expanded_state_tracker_.get(); 416 } 417 418 // Sets the visibility of one of the permanent nodes. This is set by sync. 419 void SetPermanentNodeVisible(BookmarkNode::Type type, bool value); 420 421 // Sets/deletes meta info of |node|. 422 void SetNodeMetaInfo(const BookmarkNode* node, 423 const std::string& key, 424 const std::string& value); 425 void SetNodeMetaInfoMap(const BookmarkNode* node, 426 const BookmarkNode::MetaInfoMap& meta_info_map); 427 void DeleteNodeMetaInfo(const BookmarkNode* node, 428 const std::string& key); 429 430 // Sets the sync transaction version of |node|. 431 void SetNodeSyncTransactionVersion(const BookmarkNode* node, 432 int64 sync_transaction_version); 433 434 private: 435 friend class BookmarkCodecTest; 436 friend class BookmarkModelTest; 437 friend class BookmarkStorage; 438 439 // Used to order BookmarkNodes by URL. 440 class NodeURLComparator { 441 public: 442 bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const { 443 return n1->url() < n2->url(); 444 } 445 }; 446 447 // Implementation of IsBookmarked. Before calling this the caller must obtain 448 // a lock on |url_lock_|. 449 bool IsBookmarkedNoLock(const GURL& url); 450 451 // Removes the node from internal maps and recurses through all children. If 452 // the node is a url, its url is added to removed_urls. 453 // 454 // This does NOT delete the node. 455 void RemoveNode(BookmarkNode* node, std::set<GURL>* removed_urls); 456 457 // Invoked when loading is finished. Sets |loaded_| and notifies observers. 458 // BookmarkModel takes ownership of |details|. 459 void DoneLoading(BookmarkLoadDetails* details); 460 461 // Populates |nodes_ordered_by_url_set_| from root. 462 void PopulateNodesByURL(BookmarkNode* node); 463 464 // Removes the node from its parent, but does not delete it. No notifications 465 // are sent. |removed_urls| is populated with the urls which no longer have 466 // any bookmarks associated with them. 467 // This method should be called after acquiring |url_lock_|. 468 void RemoveNodeAndGetRemovedUrls(BookmarkNode* node, 469 std::set<GURL>* removed_urls); 470 471 // Removes the node from its parent, sends notification, and deletes it. 472 // type specifies how the node should be removed. 473 void RemoveAndDeleteNode(BookmarkNode* delete_me); 474 475 // Notifies the history backend about urls of removed bookmarks. 476 void NotifyHistoryAboutRemovedBookmarks( 477 const std::set<GURL>& removed_bookmark_urls) const; 478 479 // Adds the |node| at |parent| in the specified |index| and notifies its 480 // observers. 481 BookmarkNode* AddNode(BookmarkNode* parent, 482 int index, 483 BookmarkNode* node); 484 485 // Implementation of GetNodeByID. 486 const BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id) const; 487 488 // Returns true if the parent and index are valid. 489 bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end); 490 491 // Creates one of the possible permanent nodes (bookmark bar node, other node 492 // and mobile node) from |type|. 493 BookmarkPermanentNode* CreatePermanentNode(BookmarkNode::Type type); 494 495 // Notification that a favicon has finished loading. If we can decode the 496 // favicon, FaviconLoaded is invoked. 497 void OnFaviconDataAvailable(BookmarkNode* node, 498 const chrome::FaviconImageResult& image_result); 499 500 // Invoked from the node to load the favicon. Requests the favicon from the 501 // favicon service. 502 void LoadFavicon(BookmarkNode* node); 503 504 // Called to notify the observers that the favicon has been loaded. 505 void FaviconLoaded(const BookmarkNode* node); 506 507 // If we're waiting on a favicon for node, the load request is canceled. 508 void CancelPendingFaviconLoadRequests(BookmarkNode* node); 509 510 // content::NotificationObserver: 511 virtual void Observe(int type, 512 const content::NotificationSource& source, 513 const content::NotificationDetails& details) OVERRIDE; 514 515 // Generates and returns the next node ID. 516 int64 generate_next_node_id(); 517 518 // Sets the maximum node ID to the given value. 519 // This is used by BookmarkCodec to report the maximum ID after it's done 520 // decoding since during decoding codec assigns node IDs. 521 void set_next_node_id(int64 id) { next_node_id_ = id; } 522 523 // Creates and returns a new BookmarkLoadDetails. It's up to the caller to 524 // delete the returned object. 525 BookmarkLoadDetails* CreateLoadDetails(); 526 527 content::NotificationRegistrar registrar_; 528 529 Profile* profile_; 530 531 // Whether the initial set of data has been loaded. 532 bool loaded_; 533 534 // The root node. This contains the bookmark bar node and the 'other' node as 535 // children. 536 BookmarkNode root_; 537 538 BookmarkPermanentNode* bookmark_bar_node_; 539 BookmarkPermanentNode* other_node_; 540 BookmarkPermanentNode* mobile_node_; 541 542 // The maximum ID assigned to the bookmark nodes in the model. 543 int64 next_node_id_; 544 545 // The observers. 546 ObserverList<BookmarkModelObserver> observers_; 547 548 // Set of nodes ordered by URL. This is not a map to avoid copying the 549 // urls. 550 // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As 551 // such, be sure and wrap all usage of it around |url_lock_|. 552 typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet; 553 NodesOrderedByURLSet nodes_ordered_by_url_set_; 554 base::Lock url_lock_; 555 556 // Used for loading favicons. 557 CancelableTaskTracker cancelable_task_tracker_; 558 559 // Reads/writes bookmarks to disk. 560 scoped_refptr<BookmarkStorage> store_; 561 562 scoped_ptr<BookmarkIndex> index_; 563 564 base::WaitableEvent loaded_signal_; 565 566 // See description of IsDoingExtensiveChanges above. 567 int extensive_changes_; 568 569 scoped_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_; 570 571 DISALLOW_COPY_AND_ASSIGN(BookmarkModel); 572 }; 573 574 #endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_ 575