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