Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: chrome/browser/bookmarks/bookmark_tag_model.cc

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

Powered by Google App Engine
This is Rietveld 408576698