Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 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 #include "chrome/browser/bookmarks/bookmark_tag_model.h" | |
| 6 | |
| 7 #include "base/auto_reset.h" | |
| 8 #include "base/json/json_string_value_serializer.h" | |
| 9 #include "base/observer_list.h" | |
| 10 #include "base/strings/string_util.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
| 13 #include "chrome/browser/bookmarks/bookmark_tag_model_observer.h" | |
| 14 #include "ui/base/models/tree_node_iterator.h" | |
| 15 | |
| 16 namespace { | |
| 17 // The key used to store the tag list in the metainfo of a bookmark. | |
| 18 const char* TAG_KEY = "TAG_KEY"; | |
| 19 | |
| 20 // Comparator to sort tags by usage. | |
| 21 struct TagComparator { | |
| 22 TagComparator(std::map<BookmarkTag, unsigned int>& tags) : tags_(tags) { | |
| 23 } | |
| 24 ~TagComparator() {} | |
| 25 | |
| 26 bool operator()(const BookmarkTag& a, const BookmarkTag& b) { | |
| 27 return (tags_[a] < tags_[b]); | |
| 28 } | |
| 29 | |
| 30 std::map<BookmarkTag, unsigned int>& tags_; | |
| 31 }; | |
| 32 | |
| 33 // The tags are currently stored in the BookmarkNode's metaInfo in JSON | |
| 34 // format. This function extracts the info from there and returns it in | |
| 35 // digestible format. | |
| 36 // If the Bookmark was never tagged before it is implicitely tagged with the | |
| 37 // title of all its ancestors in the BookmarkModel. | |
| 38 std::set<BookmarkTag> ExtractTagsFromBookmark( | |
| 39 const BookmarkNode* bookmark) { | |
|
sky
2013/10/16 13:46:19
nit: seems like you can fit all on one line.
noyau (Ping after 24h)
2013/10/16 16:51:32
Done.
| |
| 40 // This is awful BTW. Metainfo is itself an encoded JSON, and here we decode | |
| 41 // another layer. | |
| 42 | |
| 43 // Retrieve the encodedData from the bookmark. If there is no encoded data | |
| 44 // at all returns the name of all the ancestors as separate tags. | |
| 45 std::string encoded; | |
| 46 if (!bookmark->GetMetaInfo(TAG_KEY, &encoded)) { | |
| 47 std::set<BookmarkTag> tags; | |
| 48 const BookmarkNode* folder = bookmark->parent(); | |
| 49 while (folder && folder->type() == BookmarkNode::FOLDER) { | |
| 50 BookmarkTag trimmed_tag = CollapseWhitespace(folder->GetTitle(), true); | |
| 51 if (!trimmed_tag.empty()) | |
| 52 tags.insert(trimmed_tag); | |
| 53 folder = folder->parent(); | |
| 54 } | |
| 55 return tags; | |
| 56 } | |
| 57 | |
| 58 // Decode into a base::Value. If the data is not encoded properly as a list | |
| 59 // return an empty result. | |
| 60 JSONStringValueSerializer serializer(&encoded); | |
| 61 int error_code = 0; | |
| 62 std::string error_message; | |
| 63 scoped_ptr<base::Value> result(serializer.Deserialize(&error_code, | |
| 64 &error_message)); | |
| 65 | |
| 66 if (error_code || !result->IsType(base::Value::TYPE_LIST)) | |
| 67 return std::set<BookmarkTag>(); | |
| 68 | |
| 69 base::ListValue* list = NULL; | |
| 70 if (!result->GetAsList(&list) || list->empty()) | |
| 71 return std::set<BookmarkTag>(); | |
| 72 | |
| 73 // Build the set. | |
| 74 std::set<BookmarkTag> return_value; | |
| 75 | |
| 76 for (base::ListValue::iterator it = list->begin(); | |
| 77 it != list->end(); ++it) { | |
| 78 base::Value* item = *it; | |
| 79 BookmarkTag tag; | |
| 80 if (!item->GetAsString(&tag)) | |
| 81 continue; | |
| 82 return_value.insert(tag); | |
| 83 } | |
| 84 return return_value; | |
| 85 } | |
| 86 } // namespace | |
| 87 | |
| 88 BookmarkTagModel::BookmarkTagModel(BookmarkModel* bookmark_model) | |
| 89 : bookmark_model_(bookmark_model), | |
| 90 loaded_(false), | |
| 91 observers_(ObserverList<BookmarkTagModelObserver>::NOTIFY_EXISTING_ONLY), | |
| 92 inhibit_change_notifications_(false) { | |
| 93 bookmark_model_->AddObserver(this); | |
| 94 if (bookmark_model_->loaded()) | |
| 95 Load(); | |
| 96 } | |
| 97 | |
| 98 BookmarkTagModel::~BookmarkTagModel() { | |
| 99 if (bookmark_model_) | |
| 100 bookmark_model_->RemoveObserver(this); | |
| 101 } | |
| 102 | |
| 103 // BookmarkModel forwarding. | |
| 104 | |
| 105 void BookmarkTagModel::AddObserver(BookmarkTagModelObserver* observer) { | |
| 106 observers_.AddObserver(observer); | |
| 107 } | |
| 108 | |
| 109 void BookmarkTagModel::RemoveObserver(BookmarkTagModelObserver* observer) { | |
| 110 observers_.RemoveObserver(observer); | |
| 111 } | |
| 112 | |
| 113 void BookmarkTagModel::BeginExtensiveChanges() { | |
| 114 DCHECK(bookmark_model_); | |
| 115 bookmark_model_->BeginExtensiveChanges(); | |
| 116 } | |
| 117 | |
| 118 void BookmarkTagModel::EndExtensiveChanges() { | |
| 119 DCHECK(bookmark_model_); | |
| 120 bookmark_model_->EndExtensiveChanges(); | |
| 121 } | |
| 122 | |
| 123 bool BookmarkTagModel::IsDoingExtensiveChanges() const { | |
| 124 DCHECK(bookmark_model_); | |
| 125 return bookmark_model_->IsDoingExtensiveChanges(); | |
| 126 } | |
| 127 | |
| 128 void BookmarkTagModel::Remove(const BookmarkNode* bookmark) { | |
| 129 DCHECK(bookmark_model_); | |
| 130 DCHECK(loaded_); | |
| 131 const BookmarkNode* parent = bookmark->parent(); | |
| 132 bookmark_model_->Remove(parent, parent->GetIndexOf(bookmark)); | |
| 133 } | |
| 134 | |
| 135 void BookmarkTagModel::RemoveAll() { | |
| 136 DCHECK(bookmark_model_); | |
| 137 DCHECK(loaded_); | |
| 138 bookmark_model_->RemoveAll(); | |
| 139 } | |
| 140 | |
| 141 const gfx::Image& BookmarkTagModel::GetFavicon(const BookmarkNode* bookmark) { | |
| 142 DCHECK(bookmark_model_); | |
| 143 DCHECK(loaded_); | |
| 144 return bookmark_model_->GetFavicon(bookmark); | |
| 145 } | |
| 146 | |
| 147 void BookmarkTagModel::SetTitle(const BookmarkNode* bookmark, | |
| 148 const string16& title) { | |
| 149 DCHECK(bookmark_model_); | |
| 150 DCHECK(loaded_); | |
| 151 bookmark_model_->SetTitle(bookmark, title); | |
| 152 } | |
| 153 | |
| 154 void BookmarkTagModel::SetURL(const BookmarkNode* bookmark, const GURL& url) { | |
| 155 DCHECK(bookmark_model_); | |
| 156 DCHECK(loaded_); | |
| 157 bookmark_model_->SetURL(bookmark, url); | |
| 158 } | |
| 159 | |
| 160 void BookmarkTagModel::SetDateAdded(const BookmarkNode* bookmark, | |
| 161 base::Time date_added) { | |
| 162 DCHECK(bookmark_model_); | |
| 163 DCHECK(loaded_); | |
| 164 bookmark_model_->SetDateAdded(bookmark, date_added); | |
| 165 } | |
| 166 | |
| 167 const BookmarkNode* | |
| 168 BookmarkTagModel::GetMostRecentlyAddedBookmarkForURL(const GURL& url) { | |
| 169 DCHECK(bookmark_model_); | |
| 170 DCHECK(loaded_); | |
| 171 return bookmark_model_->GetMostRecentlyAddedNodeForURL(url); | |
| 172 } | |
| 173 | |
| 174 // Tags specific code. | |
| 175 | |
| 176 const BookmarkNode* BookmarkTagModel::AddURL( | |
| 177 const string16& title, | |
| 178 const GURL& url, | |
| 179 const std::set<BookmarkTag>& tags) { | |
| 180 DCHECK(bookmark_model_); | |
| 181 DCHECK(loaded_); | |
| 182 | |
| 183 const BookmarkNode* bookmark; | |
| 184 { | |
| 185 base::AutoReset<bool> inhibitor(&inhibit_change_notifications_, true); | |
| 186 const BookmarkNode* parent = bookmark_model_->GetParentForNewNodes(); | |
| 187 bookmark = bookmark_model_->AddURL(parent, 0, title, url); | |
| 188 AddTagsToBookmark(tags, bookmark); | |
| 189 } | |
| 190 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 191 BookmarkNodeAdded(this, bookmark)); | |
| 192 | |
| 193 return bookmark; | |
| 194 } | |
| 195 | |
| 196 std::set<BookmarkTag> BookmarkTagModel::GetTagsForBookmark( | |
| 197 const BookmarkNode* bookmark) { | |
| 198 DCHECK(loaded_); | |
| 199 return bookmark_to_tags_[bookmark]; | |
| 200 } | |
| 201 | |
| 202 void BookmarkTagModel::AddTagsToBookmark( | |
| 203 const std::set<BookmarkTag>& tags, | |
| 204 const BookmarkNode* bookmark) { | |
| 205 DCHECK(bookmark_model_); | |
| 206 std::set<BookmarkTag> all_tags(GetTagsForBookmark(bookmark)); | |
| 207 for (std::set<BookmarkTag>::const_iterator it = tags.begin(); | |
| 208 it != tags.end(); ++it) { | |
| 209 BookmarkTag trimmed_tag = CollapseWhitespace(*it, true); | |
| 210 if (trimmed_tag.empty()) | |
| 211 continue; | |
| 212 all_tags.insert(trimmed_tag); | |
| 213 } | |
| 214 SetTagsOnBookmark(all_tags, bookmark); | |
| 215 } | |
| 216 | |
| 217 void BookmarkTagModel::AddTagsToBookmarks( | |
| 218 const std::set<BookmarkTag>& tags, | |
| 219 const std::set<const BookmarkNode*>& bookmarks) { | |
| 220 for (std::set<const BookmarkNode*>::const_iterator it = bookmarks.begin(); | |
| 221 it != bookmarks.end(); ++it) { | |
| 222 AddTagsToBookmark(tags, *it); | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 void BookmarkTagModel::RemoveTagsFromBookmark( | |
| 227 const std::set<BookmarkTag>& tags, | |
| 228 const BookmarkNode* bookmark) { | |
| 229 std::set<BookmarkTag> all_tags(GetTagsForBookmark(bookmark)); | |
| 230 for (std::set<BookmarkTag>::const_iterator it = tags.begin(); | |
| 231 it != tags.end(); ++it) { | |
| 232 all_tags.erase(*it); | |
| 233 } | |
| 234 SetTagsOnBookmark(all_tags, bookmark); | |
| 235 } | |
| 236 | |
| 237 void BookmarkTagModel::RemoveTagsFromBookmarks( | |
| 238 const std::set<BookmarkTag>& tags, | |
| 239 const std::set<const BookmarkNode*>& bookmarks){ | |
| 240 for (std::set<const BookmarkNode*>::const_iterator it = bookmarks.begin(); | |
| 241 it != bookmarks.end(); ++it) { | |
| 242 RemoveTagsFromBookmark(tags, *it); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 std::set<const BookmarkNode*> BookmarkTagModel::BookmarksForTags( | |
| 247 const std::set<BookmarkTag>& tags) { | |
| 248 DCHECK(loaded_); | |
| 249 // Count for each tags how many times a bookmark appeared. | |
| 250 std::map<const BookmarkNode*, size_t> bookmark_counts; | |
| 251 for (std::set<BookmarkTag>::const_iterator it = tags.begin(); | |
| 252 it != tags.end(); ++it) { | |
| 253 const std::set<const BookmarkNode*>& subset(tag_to_bookmarks_[*it]); | |
| 254 for (std::set<const BookmarkNode*>::const_iterator tag_it = subset.begin(); | |
| 255 tag_it != subset.end(); ++tag_it) { | |
| 256 bookmark_counts[*tag_it] += 1; | |
| 257 } | |
| 258 } | |
| 259 // Keep only the bookmarks that appeared in all the tags. | |
| 260 std::set<const BookmarkNode*> common_bookmarks; | |
| 261 for (std::map<const BookmarkNode*, size_t>::iterator it = | |
| 262 bookmark_counts.begin(); it != bookmark_counts.end(); ++it) { | |
| 263 if (it->second == tags.size()) | |
| 264 common_bookmarks.insert(it->first); | |
| 265 } | |
| 266 return common_bookmarks; | |
| 267 } | |
| 268 | |
| 269 std::set<const BookmarkNode*> BookmarkTagModel::BookmarksForTag( | |
| 270 const BookmarkTag& tag) { | |
| 271 DCHECK(!tag.empty()); | |
| 272 return tag_to_bookmarks_[tag]; | |
| 273 } | |
| 274 | |
| 275 std::vector<BookmarkTag> BookmarkTagModel::TagsRelatedToTag( | |
| 276 const BookmarkTag& tag) { | |
| 277 DCHECK(loaded_); | |
| 278 std::map<BookmarkTag, unsigned int> tags; | |
| 279 | |
| 280 if (tag.empty()) { | |
| 281 // Returns all the tags. | |
| 282 for (std::map<const BookmarkTag, std::set<const BookmarkNode*> >::iterator | |
| 283 it = tag_to_bookmarks_.begin(); it != tag_to_bookmarks_.end(); ++it) { | |
| 284 tags[it->first] = it->second.size(); | |
| 285 } | |
| 286 } else { | |
| 287 std::set<const BookmarkNode*> bookmarks(BookmarksForTag(tag)); | |
| 288 | |
| 289 for (std::set<const BookmarkNode*>::iterator it = bookmarks.begin(); | |
| 290 it != bookmarks.end(); ++it) { | |
| 291 const std::set<BookmarkTag>& subset(bookmark_to_tags_[*it]); | |
| 292 for (std::set<BookmarkTag>::const_iterator tag_it = subset.begin(); | |
| 293 tag_it != subset.end(); ++tag_it) { | |
| 294 tags[*tag_it] += 1; | |
| 295 } | |
| 296 } | |
| 297 tags.erase(tag); // A tag is not related to itself. | |
| 298 } | |
| 299 | |
| 300 std::vector<BookmarkTag> sorted_tags; | |
| 301 for (std::map<BookmarkTag, unsigned int>::iterator it = tags.begin(); | |
| 302 it != tags.end(); ++it) { | |
| 303 sorted_tags.push_back(it->first); | |
| 304 } | |
| 305 std::sort(sorted_tags.begin(), sorted_tags.end(), TagComparator(tags)); | |
| 306 return sorted_tags; | |
| 307 } | |
| 308 | |
| 309 // BookmarkModelObserver methods. | |
| 310 | |
| 311 // Invoked when the model has finished loading. | |
| 312 void BookmarkTagModel::Loaded(BookmarkModel* model, bool ids_reassigned) { | |
| 313 Load(); | |
| 314 }; | |
|
sky
2013/10/16 13:46:19
nit: no ;
noyau (Ping after 24h)
2013/10/16 16:51:32
Done.
| |
| 315 | |
| 316 // Invoked from the destructor of the BookmarkModel. | |
|
sky
2013/10/16 13:46:19
Are these comments really helpful? We generally do
noyau (Ping after 24h)
2013/10/16 16:51:32
You are right, those were duplicated from the Book
| |
| 317 void BookmarkTagModel::BookmarkModelBeingDeleted(BookmarkModel* model) { | |
| 318 DCHECK(bookmark_model_); | |
| 319 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 320 BookmarkTagModelBeingDeleted(this)); | |
| 321 bookmark_model_ = NULL; | |
| 322 } | |
| 323 | |
| 324 // Invoked when a node has moved. | |
| 325 void BookmarkTagModel::BookmarkNodeMoved(BookmarkModel* model, | |
| 326 const BookmarkNode* old_parent, | |
| 327 int old_index, | |
| 328 const BookmarkNode* new_parent, | |
| 329 int new_index) { | |
| 330 DCHECK(loaded_); | |
| 331 const BookmarkNode* bookmark = new_parent->GetChild(new_index); | |
| 332 std::string encoded; | |
| 333 if (!bookmark->GetMetaInfo(TAG_KEY, &encoded)) { | |
| 334 // The bookmark moved and the system currently use its ancestors name as a | |
| 335 // poor approximation for tags. | |
| 336 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 337 OnWillChangeBookmarkTags(this, bookmark)); | |
| 338 RemoveBookmark(bookmark); | |
| 339 LoadBookmark(bookmark); | |
| 340 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 341 BookmarkTagsChanged(this, bookmark)); | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 // Invoked when a node has been added. | |
| 346 void BookmarkTagModel::BookmarkNodeAdded(BookmarkModel* model, | |
| 347 const BookmarkNode* parent, | |
| 348 int index) { | |
| 349 DCHECK(loaded_); | |
| 350 const BookmarkNode* bookmark = parent->GetChild(index); | |
| 351 if (!bookmark->is_url()) | |
| 352 return; | |
| 353 LoadBookmark(bookmark); | |
| 354 | |
| 355 if (!inhibit_change_notifications_) | |
| 356 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 357 BookmarkNodeAdded(this, bookmark)); | |
| 358 } | |
| 359 | |
| 360 // Invoked before a node is removed. | |
| 361 // |parent| the parent of the node that will be removed. | |
| 362 // |old_index| the index of the node about to be removed in |parent|. | |
| 363 // |node| is the node to be removed. | |
| 364 void BookmarkTagModel::OnWillRemoveBookmarks(BookmarkModel* model, | |
| 365 const BookmarkNode* parent, | |
| 366 int old_index, | |
| 367 const BookmarkNode* node) { | |
| 368 DCHECK(loaded_); | |
| 369 RemoveBookmark(node); | |
| 370 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 371 OnWillRemoveBookmarks(this, node)); | |
| 372 } | |
| 373 | |
| 374 // Invoked when a node has been removed, the item may still be starred though. | |
| 375 // |parent| the parent of the node that was removed. | |
| 376 // |old_index| the index of the removed node in |parent| before it was | |
| 377 // removed. | |
| 378 // |node| is the node that was removed. | |
| 379 void BookmarkTagModel::BookmarkNodeRemoved(BookmarkModel* model, | |
| 380 const BookmarkNode* parent, | |
|
sky
2013/10/16 13:46:19
nit: indentation off.
noyau (Ping after 24h)
2013/10/16 16:51:32
Fixed all of them.
| |
| 381 int old_index, | |
| 382 const BookmarkNode* node) { | |
| 383 DCHECK(loaded_); | |
| 384 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 385 BookmarkNodeRemoved(this, node)); | |
| 386 } | |
| 387 | |
| 388 // Invoked before the title or url of a node is changed. | |
| 389 void BookmarkTagModel::OnWillChangeBookmarkNode(BookmarkModel* model, | |
| 390 const BookmarkNode* node) { | |
| 391 DCHECK(loaded_); | |
| 392 if (!inhibit_change_notifications_) | |
| 393 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 394 OnWillChangeBookmarkNode(this, node)); | |
| 395 } | |
| 396 | |
| 397 // Invoked when the title or url of a node changes. | |
| 398 void BookmarkTagModel::BookmarkNodeChanged(BookmarkModel* model, | |
| 399 const BookmarkNode* node) { | |
| 400 DCHECK(loaded_); | |
| 401 if (node->is_folder()) { | |
| 402 // A folder title changed. This may change the tags on all the descendants | |
|
sky
2013/10/16 13:46:19
Do you need to remove node too as iteration doesn'
noyau (Ping after 24h)
2013/10/16 16:51:32
There is no mapping kept for folder nodes, RemoveB
| |
| 403 // still using the default tag list of all ancestors. | |
| 404 ExtensiveChanges scoped(ExtensiveChanges(this)); | |
| 405 ui::TreeNodeIterator<const BookmarkNode> iterator(node); | |
| 406 while (iterator.has_next()) { | |
| 407 const BookmarkNode* bookmark = iterator.Next(); | |
| 408 RemoveBookmark(bookmark); | |
| 409 LoadBookmark(bookmark); | |
| 410 } | |
| 411 } else { | |
| 412 if (!inhibit_change_notifications_) | |
| 413 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 414 BookmarkNodeChanged(this, node)); | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 // Invoked before the metainfo of a node is changed. | |
| 419 void BookmarkTagModel::OnWillChangeBookmarkMetaInfo(BookmarkModel* model, | |
| 420 const BookmarkNode* node) { | |
| 421 DCHECK(loaded_); | |
| 422 if (!inhibit_change_notifications_) | |
| 423 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 424 OnWillChangeBookmarkTags(this, node)); | |
| 425 } | |
| 426 | |
| 427 // Invoked when the metainfo on a node changes. | |
| 428 void BookmarkTagModel::BookmarkMetaInfoChanged(BookmarkModel* model, | |
| 429 const BookmarkNode* node) { | |
| 430 DCHECK(loaded_); | |
| 431 RemoveBookmark(node); | |
| 432 LoadBookmark(node); | |
| 433 if (!inhibit_change_notifications_) | |
| 434 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 435 BookmarkTagsChanged(this, node)); | |
| 436 } | |
| 437 | |
| 438 // Invoked when a favicon has been loaded or changed. | |
| 439 void BookmarkTagModel::BookmarkNodeFaviconChanged(BookmarkModel* model, | |
| 440 const BookmarkNode* node) { | |
| 441 DCHECK(loaded_); | |
| 442 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 443 BookmarkNodeFaviconChanged(this, node)); | |
| 444 } | |
| 445 | |
| 446 // Invoked before the direct children of |node| have been reordered in some | |
| 447 // way, such as sorted. | |
| 448 void BookmarkTagModel::OnWillReorderBookmarkNode(BookmarkModel* model, | |
| 449 const BookmarkNode* node) { | |
| 450 // This model doesn't care. | |
| 451 } | |
| 452 | |
| 453 // Invoked when the children (just direct children, not descendants) of | |
| 454 // |node| have been reordered in some way, such as sorted. | |
| 455 void BookmarkTagModel::BookmarkNodeChildrenReordered(BookmarkModel* model, | |
| 456 const BookmarkNode* node) { | |
| 457 // This model doesn't care. | |
| 458 } | |
| 459 | |
| 460 // Invoked before an extensive set of model changes is about to begin. | |
| 461 // This tells UI intensive observers to wait until the updates finish to | |
| 462 // update themselves. | |
| 463 // These methods should only be used for imports and sync. | |
| 464 // Observers should still respond to BookmarkNodeRemoved immediately, | |
| 465 // to avoid holding onto stale node pointers. | |
| 466 void BookmarkTagModel::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) { | |
| 467 DCHECK(loaded_); | |
| 468 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 469 ExtensiveBookmarkChangesBeginning(this)); | |
| 470 } | |
| 471 | |
| 472 // Invoked after an extensive set of model changes has ended. | |
| 473 // This tells observers to update themselves if they were waiting for the | |
| 474 // update to finish. | |
| 475 void BookmarkTagModel::ExtensiveBookmarkChangesEnded(BookmarkModel* model) { | |
| 476 DCHECK(loaded_); | |
| 477 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 478 ExtensiveBookmarkChangesEnded(this)); | |
| 479 } | |
| 480 | |
| 481 // Invoked before all non-permanent bookmark nodes are removed. | |
| 482 void BookmarkTagModel::OnWillRemoveAllBookmarks(BookmarkModel* model) { | |
| 483 DCHECK(loaded_); | |
| 484 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 485 OnWillRemoveAllBookmarks(this)); | |
| 486 } | |
| 487 | |
| 488 // Invoked when all non-permanent bookmark nodes have been removed. | |
| 489 void BookmarkTagModel::BookmarkAllNodesRemoved(BookmarkModel* model){ | |
| 490 DCHECK(loaded_); | |
| 491 tag_to_bookmarks_.clear(); | |
| 492 bookmark_to_tags_.clear(); | |
| 493 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 494 BookmarkAllNodesRemoved(this)); | |
| 495 } | |
| 496 | |
| 497 // Private methods. | |
| 498 | |
| 499 void BookmarkTagModel::SetTagsOnBookmark( | |
| 500 const std::set<BookmarkTag>& tags, const BookmarkNode* bookmark) { | |
| 501 DCHECK(bookmark_model_); | |
| 502 DCHECK(loaded_); | |
| 503 | |
| 504 // Build a ListValue. | |
| 505 std::vector<BookmarkTag> tag_vector(tags.begin(), tags.end()); | |
| 506 base::ListValue list; | |
| 507 list.AppendStrings(tag_vector); | |
| 508 | |
| 509 // Encodes it. | |
| 510 std::string encoded; | |
| 511 JSONStringValueSerializer serializer(&encoded); | |
| 512 | |
| 513 // Pushes it in the bookmark's metainfo. Even if the tag list is empty the | |
| 514 // empty list must be put on the node to avoid reverting to the tag list | |
| 515 // derived from the hierarchy. | |
| 516 // The internal caches of the BookmarkTagModel are updated when the | |
| 517 // notification from the BookmarkModel is received. | |
| 518 serializer.Serialize(list); | |
| 519 bookmark_model_->SetNodeMetaInfo(bookmark, TAG_KEY, encoded); | |
| 520 } | |
| 521 | |
| 522 void BookmarkTagModel::Load() { | |
| 523 DCHECK(bookmark_model_); | |
| 524 DCHECK(!loaded_); | |
| 525 ui::TreeNodeIterator<const BookmarkNode> iterator( | |
| 526 bookmark_model_->root_node()); | |
| 527 while (iterator.has_next()) | |
| 528 LoadBookmark(iterator.Next()); | |
| 529 loaded_ = true; | |
| 530 FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, | |
| 531 Loaded(this)); | |
| 532 } | |
| 533 | |
| 534 void BookmarkTagModel::LoadBookmark(const BookmarkNode* bookmark) { | |
| 535 DCHECK(bookmark_model_); | |
| 536 if (bookmark->is_url()) { | |
| 537 std::set<BookmarkTag> tags(ExtractTagsFromBookmark(bookmark)); | |
| 538 | |
| 539 bookmark_to_tags_[bookmark] = tags; | |
| 540 for (std::set<BookmarkTag>::iterator it = tags.begin(); | |
| 541 it != tags.end(); ++it) { | |
| 542 tag_to_bookmarks_[*it].insert(bookmark); | |
| 543 } | |
| 544 } | |
| 545 } | |
| 546 | |
| 547 void BookmarkTagModel::RemoveBookmark(const BookmarkNode* bookmark) { | |
| 548 DCHECK(bookmark_model_); | |
| 549 if (bookmark->is_url()) { | |
| 550 std::set<BookmarkTag> tags(bookmark_to_tags_[bookmark]); | |
| 551 bookmark_to_tags_.erase(bookmark); | |
| 552 | |
| 553 for (std::set<BookmarkTag>::iterator it = tags.begin(); | |
| 554 it != tags.end(); ++it) { | |
| 555 tag_to_bookmarks_[*it].erase(bookmark); | |
| 556 // Remove the tags no longer used. | |
| 557 if (!tag_to_bookmarks_[*it].size()) | |
| 558 tag_to_bookmarks_.erase(*it); | |
| 559 } | |
| 560 } | |
| 561 } | |
| OLD | NEW |