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