OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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/bookmark_bar_model.h" | |
6 | |
7 #include "base/gfx/png_decoder.h" | |
8 #include "chrome/browser/history/query_parser.h" | |
9 #include "chrome/browser/profile.h" | |
10 #include "chrome/browser/bookmark_storage.h" | |
11 #include "chrome/common/scoped_vector.h" | |
12 | |
13 #include "generated_resources.h" | |
14 | |
15 namespace { | |
16 | |
17 // Functions used for sorting. | |
18 bool MoreRecentlyModified(BookmarkBarNode* n1, BookmarkBarNode* n2) { | |
19 return n1->date_group_modified() > n2->date_group_modified(); | |
20 } | |
21 | |
22 bool MoreRecentlyAdded(BookmarkBarNode* n1, BookmarkBarNode* n2) { | |
23 return n1->date_added() > n2->date_added(); | |
24 } | |
25 | |
26 } // namespace | |
27 | |
28 // BookmarkBarNode ------------------------------------------------------------ | |
29 | |
30 namespace { | |
31 | |
32 // ID for BookmarkBarNodes. | |
33 // Various places assume an invalid id if == 0, for that reason we start with 1. | |
34 int next_id_ = 1; | |
35 | |
36 } | |
37 | |
38 const SkBitmap& BookmarkBarNode::GetFavIcon() { | |
39 if (!loaded_favicon_) { | |
40 loaded_favicon_ = true; | |
41 model_->LoadFavIcon(this); | |
42 } | |
43 return favicon_; | |
44 } | |
45 | |
46 BookmarkBarNode::BookmarkBarNode(BookmarkBarModel* model, const GURL& url) | |
47 : model_(model), | |
48 id_(next_id_++), | |
49 loaded_favicon_(false), | |
50 favicon_load_handle_(0), | |
51 url_(url), | |
52 type_(!url.is_empty() ? history::StarredEntry::URL : | |
53 history::StarredEntry::BOOKMARK_BAR), | |
54 date_added_(Time::Now()) { | |
55 } | |
56 | |
57 void BookmarkBarNode::Reset(const history::StarredEntry& entry) { | |
58 DCHECK(entry.type != history::StarredEntry::URL || | |
59 entry.url == url_); | |
60 | |
61 favicon_ = SkBitmap(); | |
62 type_ = entry.type; | |
63 date_added_ = entry.date_added; | |
64 date_group_modified_ = entry.date_group_modified; | |
65 SetTitle(entry.title); | |
66 } | |
67 | |
68 // BookmarkBarModel ----------------------------------------------------------- | |
69 | |
70 BookmarkBarModel::BookmarkBarModel(Profile* profile) | |
71 : profile_(profile), | |
72 loaded_(false), | |
73 #pragma warning(suppress: 4355) // Okay to pass "this" here. | |
74 root_(this, GURL()), | |
75 bookmark_bar_node_(NULL), | |
76 other_node_(NULL), | |
77 waiting_for_history_load_(false), | |
78 loaded_signal_(CreateEvent(NULL, TRUE, FALSE, NULL)) { | |
79 // Create the bookmark bar and other bookmarks folders. These always exist. | |
80 CreateBookmarkBarNode(); | |
81 CreateOtherBookmarksNode(); | |
82 | |
83 // And add them to the root. | |
84 // | |
85 // WARNING: order is important here, various places assume bookmark bar then | |
86 // other node. | |
87 root_.Add(0, bookmark_bar_node_); | |
88 root_.Add(1, other_node_); | |
89 | |
90 if (!profile_) { | |
91 // Profile is null during testing. | |
92 DoneLoading(); | |
93 } | |
94 } | |
95 | |
96 BookmarkBarModel::~BookmarkBarModel() { | |
97 if (profile_ && store_.get()) { | |
98 NotificationService::current()->RemoveObserver( | |
99 this, NOTIFY_FAVICON_CHANGED, Source<Profile>(profile_)); | |
100 } | |
101 | |
102 if (waiting_for_history_load_) { | |
103 NotificationService::current()->RemoveObserver( | |
104 this, NOTIFY_HISTORY_LOADED, Source<Profile>(profile_)); | |
105 } | |
106 | |
107 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
108 BookmarkModelBeingDeleted(this)); | |
109 | |
110 if (store_) { | |
111 // The store maintains a reference back to us. We need to tell it we're gone | |
112 // so that it doesn't try and invoke a method back on us again. | |
113 store_->BookmarkModelDeleted(); | |
114 } | |
115 } | |
116 | |
117 void BookmarkBarModel::Load() { | |
118 if (store_.get()) { | |
119 // If the store is non-null, it means Load was already invoked. Load should | |
120 // only be invoked once. | |
121 NOTREACHED(); | |
122 return; | |
123 } | |
124 | |
125 // Listen for changes to favicons so that we can update the favicon of the | |
126 // node appropriately. | |
127 NotificationService::current()->AddObserver( | |
128 this, NOTIFY_FAVICON_CHANGED, Source<Profile>(profile_)); | |
129 | |
130 // Load the bookmarks. BookmarkStorage notifies us when done. | |
131 store_ = new BookmarkStorage(profile_, this); | |
132 store_->LoadBookmarks(false); | |
133 } | |
134 | |
135 BookmarkBarNode* BookmarkBarModel::GetParentForNewNodes() { | |
136 std::vector<BookmarkBarNode*> nodes; | |
137 | |
138 GetMostRecentlyModifiedGroupNodes(&root_, 1, &nodes); | |
139 return nodes.empty() ? bookmark_bar_node_ : nodes[0]; | |
140 } | |
141 | |
142 std::vector<BookmarkBarNode*> BookmarkBarModel::GetMostRecentlyModifiedGroups( | |
143 size_t max_count) { | |
144 std::vector<BookmarkBarNode*> nodes; | |
145 GetMostRecentlyModifiedGroupNodes(&root_, max_count, &nodes); | |
146 | |
147 if (nodes.size() < max_count) { | |
148 // Add the bookmark bar and other nodes if there is space. | |
149 if (find(nodes.begin(), nodes.end(), bookmark_bar_node_) == nodes.end()) | |
150 nodes.push_back(bookmark_bar_node_); | |
151 | |
152 if (nodes.size() < max_count && | |
153 find(nodes.begin(), nodes.end(), other_node_) == nodes.end()) { | |
154 nodes.push_back(other_node_); | |
155 } | |
156 } | |
157 return nodes; | |
158 } | |
159 | |
160 void BookmarkBarModel::GetMostRecentlyAddedEntries( | |
161 size_t count, | |
162 std::vector<BookmarkBarNode*>* nodes) { | |
163 AutoLock url_lock(url_lock_); | |
164 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin(); | |
165 i != nodes_ordered_by_url_set_.end(); ++i) { | |
166 std::vector<BookmarkBarNode*>::iterator insert_position = | |
167 std::upper_bound(nodes->begin(), nodes->end(), *i, &MoreRecentlyAdded); | |
168 if (nodes->size() < count || insert_position != nodes->end()) { | |
169 nodes->insert(insert_position, *i); | |
170 while (nodes->size() > count) | |
171 nodes->pop_back(); | |
172 } | |
173 } | |
174 } | |
175 | |
176 void BookmarkBarModel::GetBookmarksMatchingText( | |
177 const std::wstring& text, | |
178 size_t max_count, | |
179 std::vector<TitleMatch>* matches) { | |
180 QueryParser parser; | |
181 ScopedVector<QueryNode> query_nodes; | |
182 parser.ParseQuery(text, &query_nodes.get()); | |
183 if (query_nodes.empty()) | |
184 return; | |
185 | |
186 AutoLock url_lock(url_lock_); | |
187 Snippet::MatchPositions match_position; | |
188 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin(); | |
189 i != nodes_ordered_by_url_set_.end(); ++i) { | |
190 if (parser.DoesQueryMatch((*i)->GetTitle(), query_nodes.get(), | |
191 &match_position)) { | |
192 matches->push_back(TitleMatch()); | |
193 matches->back().node = *i; | |
194 matches->back().match_positions.swap(match_position); | |
195 if (matches->size() == max_count) | |
196 break; | |
197 } | |
198 } | |
199 } | |
200 | |
201 void BookmarkBarModel::Remove(BookmarkBarNode* parent, int index) { | |
202 if (!loaded_ || !IsValidIndex(parent, index, false) || parent == &root_) { | |
203 NOTREACHED(); | |
204 return; | |
205 } | |
206 RemoveAndDeleteNode(parent->GetChild(index)); | |
207 } | |
208 | |
209 void BookmarkBarModel::Move(BookmarkBarNode* node, | |
210 BookmarkBarNode* new_parent, | |
211 int index) { | |
212 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || | |
213 new_parent == &root_ || node == &root_ || node == bookmark_bar_node_ || | |
214 node == other_node_) { | |
215 NOTREACHED(); | |
216 return; | |
217 } | |
218 | |
219 if (new_parent->HasAncestor(node)) { | |
220 // Can't make an ancestor of the node be a child of the node. | |
221 NOTREACHED(); | |
222 return; | |
223 } | |
224 | |
225 SetDateGroupModified(new_parent, Time::Now()); | |
226 | |
227 BookmarkBarNode* old_parent = node->GetParent(); | |
228 int old_index = old_parent->IndexOfChild(node); | |
229 | |
230 if (old_parent == new_parent && | |
231 (index == old_index || index == old_index + 1)) { | |
232 // Node is already in this position, nothing to do. | |
233 return; | |
234 } | |
235 | |
236 if (old_parent == new_parent && index > old_index) | |
237 index--; | |
238 new_parent->Add(index, node); | |
239 | |
240 if (store_.get()) | |
241 store_->ScheduleSave(); | |
242 | |
243 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
244 BookmarkNodeMoved(this, old_parent, old_index, | |
245 new_parent, index)); | |
246 } | |
247 | |
248 void BookmarkBarModel::SetTitle(BookmarkBarNode* node, | |
249 const std::wstring& title) { | |
250 if (!node) { | |
251 NOTREACHED(); | |
252 return; | |
253 } | |
254 if (node->GetTitle() == title) | |
255 return; | |
256 | |
257 node->SetTitle(title); | |
258 | |
259 if (store_.get()) | |
260 store_->ScheduleSave(); | |
261 | |
262 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
263 BookmarkNodeChanged(this, node)); | |
264 } | |
265 | |
266 BookmarkBarNode* BookmarkBarModel::GetNodeByURL(const GURL& url) { | |
267 AutoLock url_lock(url_lock_); | |
268 BookmarkBarNode tmp_node(this, url); | |
269 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node); | |
270 return (i != nodes_ordered_by_url_set_.end()) ? *i : NULL; | |
271 } | |
272 | |
273 void BookmarkBarModel::GetBookmarks(std::vector<GURL>* urls) { | |
274 AutoLock url_lock(url_lock_); | |
275 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin(); | |
276 i != nodes_ordered_by_url_set_.end(); ++i) { | |
277 urls->push_back((*i)->GetURL()); | |
278 } | |
279 } | |
280 | |
281 BookmarkBarNode* BookmarkBarModel::GetNodeByID(int id) { | |
282 // TODO(sky): TreeNode needs a method that visits all nodes using a predicate. | |
283 return GetNodeByID(&root_, id); | |
284 } | |
285 | |
286 BookmarkBarNode* BookmarkBarModel::AddGroup( | |
287 BookmarkBarNode* parent, | |
288 int index, | |
289 const std::wstring& title) { | |
290 if (!loaded_ || parent == &root_ || !IsValidIndex(parent, index, true)) { | |
291 // Can't add to the root. | |
292 NOTREACHED(); | |
293 return NULL; | |
294 } | |
295 | |
296 BookmarkBarNode* new_node = new BookmarkBarNode(this, GURL()); | |
297 new_node->SetTitle(title); | |
298 new_node->type_ = history::StarredEntry::USER_GROUP; | |
299 | |
300 return AddNode(parent, index, new_node); | |
301 } | |
302 | |
303 BookmarkBarNode* BookmarkBarModel::AddURL(BookmarkBarNode* parent, | |
304 int index, | |
305 const std::wstring& title, | |
306 const GURL& url) { | |
307 return AddURLWithCreationTime(parent, index, title, url, Time::Now()); | |
308 } | |
309 | |
310 BookmarkBarNode* BookmarkBarModel::AddURLWithCreationTime( | |
311 BookmarkBarNode* parent, | |
312 int index, | |
313 const std::wstring& title, | |
314 const GURL& url, | |
315 const Time& creation_time) { | |
316 if (!loaded_ || !url.is_valid() || parent == &root_ || | |
317 !IsValidIndex(parent, index, true)) { | |
318 NOTREACHED(); | |
319 return NULL; | |
320 } | |
321 | |
322 BookmarkBarNode* existing_node = GetNodeByURL(url); | |
323 if (existing_node) { | |
324 Move(existing_node, parent, index); | |
325 SetTitle(existing_node, title); | |
326 return existing_node; | |
327 } | |
328 | |
329 SetDateGroupModified(parent, creation_time); | |
330 | |
331 BookmarkBarNode* new_node = new BookmarkBarNode(this, url); | |
332 new_node->SetTitle(title); | |
333 new_node->date_added_ = creation_time; | |
334 new_node->type_ = history::StarredEntry::URL; | |
335 | |
336 AutoLock url_lock(url_lock_); | |
337 nodes_ordered_by_url_set_.insert(new_node); | |
338 | |
339 return AddNode(parent, index, new_node); | |
340 } | |
341 | |
342 void BookmarkBarModel::SetURLStarred(const GURL& url, | |
343 const std::wstring& title, | |
344 bool is_starred) { | |
345 BookmarkBarNode* node = GetNodeByURL(url); | |
346 if (is_starred && !node) { | |
347 // Add the url. | |
348 BookmarkBarNode* parent = GetParentForNewNodes(); | |
349 AddURL(parent, parent->GetChildCount(), title, url); | |
350 } else if (!is_starred && node) { | |
351 Remove(node->GetParent(), node->GetParent()->IndexOfChild(node)); | |
352 } | |
353 } | |
354 | |
355 void BookmarkBarModel::ResetDateGroupModified(BookmarkBarNode* node) { | |
356 SetDateGroupModified(node, Time()); | |
357 } | |
358 | |
359 void BookmarkBarModel::FavIconLoaded(BookmarkBarNode* node) { | |
360 // Send out notification to the observer. | |
361 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
362 BookmarkNodeFavIconLoaded(this, node)); | |
363 } | |
364 | |
365 void BookmarkBarModel::RemoveNode(BookmarkBarNode* node, | |
366 std::set<GURL>* removed_urls) { | |
367 if (!loaded_ || !node || node == &root_ || node == bookmark_bar_node_ || | |
368 node == other_node_) { | |
369 NOTREACHED(); | |
370 return; | |
371 } | |
372 | |
373 if (node->GetType() == history::StarredEntry::URL) { | |
374 // NOTE: this is called in such a way that url_lock_ is already held. As | |
375 // such, this doesn't explicitly grab the lock. | |
376 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); | |
377 DCHECK(i != nodes_ordered_by_url_set_.end()); | |
378 nodes_ordered_by_url_set_.erase(i); | |
379 removed_urls->insert(node->GetURL()); | |
380 } | |
381 | |
382 CancelPendingFavIconLoadRequests(node); | |
383 | |
384 // Recurse through children. | |
385 for (int i = node->GetChildCount() - 1; i >= 0; --i) | |
386 RemoveNode(node->GetChild(i), removed_urls); | |
387 } | |
388 | |
389 void BookmarkBarModel::OnBookmarkStorageLoadedBookmarks( | |
390 bool file_exists, | |
391 bool loaded_from_history) { | |
392 if (loaded_) { | |
393 NOTREACHED(); | |
394 return; | |
395 } | |
396 | |
397 if (file_exists || loaded_from_history || !profile_ || | |
398 !profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)) { | |
399 // The file exists, we're loaded. | |
400 DoneLoading(); | |
401 | |
402 if (loaded_from_history) { | |
403 // We were just populated from the historical file. Schedule a save so | |
404 // that the main file is up to date. | |
405 store_->ScheduleSave(); | |
406 } | |
407 return; | |
408 } | |
409 | |
410 // The file doesn't exist. This means one of two things: | |
411 // 1. A clean profile. | |
412 // 2. The user is migrating from an older version where bookmarks were saved | |
413 // in history. | |
414 // We assume step 2. If history had the bookmarks, history will write the | |
415 // bookmarks to a file for us. We need to wait until history has finished | |
416 // loading before reading from that file. | |
417 HistoryService* history = | |
418 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | |
419 if (!history->backend_loaded()) { | |
420 // The backend isn't finished loading. Wait for it. | |
421 waiting_for_history_load_ = true; | |
422 NotificationService::current()->AddObserver( | |
423 this, NOTIFY_HISTORY_LOADED, Source<Profile>(profile_)); | |
424 } else { | |
425 OnHistoryDone(); | |
426 } | |
427 } | |
428 | |
429 void BookmarkBarModel::OnHistoryDone() { | |
430 if (loaded_) { | |
431 NOTREACHED(); | |
432 return; | |
433 } | |
434 | |
435 // If the bookmarks were stored in the db the db will have migrated them to | |
436 // a file now. Try loading from the file. | |
437 store_->LoadBookmarks(true); | |
438 } | |
439 | |
440 void BookmarkBarModel::DoneLoading() { | |
441 { | |
442 AutoLock url_lock(url_lock_); | |
443 // Update nodes_ordered_by_url_set_ from the nodes. | |
444 PopulateNodesByURL(&root_); | |
445 } | |
446 | |
447 loaded_ = true; | |
448 | |
449 if (loaded_signal_.Get()) | |
450 SetEvent(loaded_signal_.Get()); | |
451 | |
452 | |
453 // Notify our direct observers. | |
454 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, Loaded(this)); | |
455 | |
456 // And generic notification. | |
457 NotificationService::current()->Notify( | |
458 NOTIFY_BOOKMARK_MODEL_LOADED, | |
459 Source<Profile>(profile_), | |
460 NotificationService::NoDetails()); | |
461 } | |
462 | |
463 void BookmarkBarModel::RemoveAndDeleteNode(BookmarkBarNode* delete_me) { | |
464 scoped_ptr<BookmarkBarNode> node(delete_me); | |
465 | |
466 BookmarkBarNode* parent = node->GetParent(); | |
467 DCHECK(parent); | |
468 int index = parent->IndexOfChild(node.get()); | |
469 parent->Remove(index); | |
470 history::URLsStarredDetails details(false); | |
471 { | |
472 AutoLock url_lock(url_lock_); | |
473 RemoveNode(node.get(), &details.changed_urls); | |
474 } | |
475 | |
476 if (store_.get()) | |
477 store_->ScheduleSave(); | |
478 | |
479 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
480 BookmarkNodeRemoved(this, parent, index)); | |
481 | |
482 if (profile_) { | |
483 HistoryService* history = | |
484 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | |
485 if (history) | |
486 history->URLsNoLongerBookmarked(details.changed_urls); | |
487 } | |
488 | |
489 NotificationService::current()->Notify(NOTIFY_URLS_STARRED, | |
490 Source<Profile>(profile_), | |
491 Details<history::URLsStarredDetails>(&details)); | |
492 } | |
493 | |
494 BookmarkBarNode* BookmarkBarModel::AddNode(BookmarkBarNode* parent, | |
495 int index, | |
496 BookmarkBarNode* node) { | |
497 parent->Add(index, node); | |
498 | |
499 if (store_.get()) | |
500 store_->ScheduleSave(); | |
501 | |
502 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
503 BookmarkNodeAdded(this, parent, index)); | |
504 | |
505 if (node->GetType() == history::StarredEntry::URL) { | |
506 history::URLsStarredDetails details(true); | |
507 details.changed_urls.insert(node->GetURL()); | |
508 NotificationService::current()->Notify(NOTIFY_URLS_STARRED, | |
509 Source<Profile>(profile_), | |
510 Details<history::URLsStarredDetails>(&details)); | |
511 } | |
512 return node; | |
513 } | |
514 | |
515 void BookmarkBarModel::BlockTillLoaded() { | |
516 if (loaded_signal_.Get()) | |
517 WaitForSingleObject(loaded_signal_.Get(), INFINITE); | |
518 } | |
519 | |
520 BookmarkBarNode* BookmarkBarModel::GetNodeByID(BookmarkBarNode* node, | |
521 int id) { | |
522 if (node->id() == id) | |
523 return node; | |
524 | |
525 for (int i = 0; i < node->GetChildCount(); ++i) { | |
526 BookmarkBarNode* result = GetNodeByID(node->GetChild(i), id); | |
527 if (result) | |
528 return result; | |
529 } | |
530 return NULL; | |
531 } | |
532 | |
533 bool BookmarkBarModel::IsValidIndex(BookmarkBarNode* parent, | |
534 int index, | |
535 bool allow_end) { | |
536 return (parent && | |
537 (index >= 0 && (index < parent->GetChildCount() || | |
538 (allow_end && index == parent->GetChildCount())))); | |
539 } | |
540 | |
541 void BookmarkBarModel::SetDateGroupModified(BookmarkBarNode* parent, | |
542 const Time time) { | |
543 DCHECK(parent); | |
544 parent->date_group_modified_ = time; | |
545 | |
546 if (store_.get()) | |
547 store_->ScheduleSave(); | |
548 } | |
549 | |
550 void BookmarkBarModel::CreateBookmarkBarNode() { | |
551 history::StarredEntry entry; | |
552 entry.type = history::StarredEntry::BOOKMARK_BAR; | |
553 bookmark_bar_node_ = CreateRootNodeFromStarredEntry(entry); | |
554 } | |
555 | |
556 void BookmarkBarModel::CreateOtherBookmarksNode() { | |
557 history::StarredEntry entry; | |
558 entry.type = history::StarredEntry::OTHER; | |
559 other_node_ = CreateRootNodeFromStarredEntry(entry); | |
560 } | |
561 | |
562 BookmarkBarNode* BookmarkBarModel::CreateRootNodeFromStarredEntry( | |
563 const history::StarredEntry& entry) { | |
564 DCHECK(entry.type == history::StarredEntry::BOOKMARK_BAR || | |
565 entry.type == history::StarredEntry::OTHER); | |
566 BookmarkBarNode* node = new BookmarkBarNode(this, GURL()); | |
567 node->Reset(entry); | |
568 if (entry.type == history::StarredEntry::BOOKMARK_BAR) | |
569 node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME)); | |
570 else | |
571 node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME)); | |
572 return node; | |
573 } | |
574 | |
575 void BookmarkBarModel::OnFavIconDataAvailable( | |
576 HistoryService::Handle handle, | |
577 bool know_favicon, | |
578 scoped_refptr<RefCountedBytes> data, | |
579 bool expired, | |
580 GURL icon_url) { | |
581 SkBitmap fav_icon; | |
582 BookmarkBarNode* node = | |
583 load_consumer_.GetClientData( | |
584 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS), handle); | |
585 DCHECK(node); | |
586 node->favicon_load_handle_ = 0; | |
587 if (know_favicon && data.get() && | |
588 PNGDecoder::Decode(&data->data, &fav_icon)) { | |
589 node->favicon_ = fav_icon; | |
590 FavIconLoaded(node); | |
591 } | |
592 } | |
593 | |
594 void BookmarkBarModel::LoadFavIcon(BookmarkBarNode* node) { | |
595 if (node->GetType() != history::StarredEntry::URL) | |
596 return; | |
597 | |
598 DCHECK(node->GetURL().is_valid()); | |
599 HistoryService* history_service = | |
600 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | |
601 if (!history_service) | |
602 return; | |
603 | |
604 HistoryService::Handle handle = history_service->GetFavIconForURL( | |
605 node->GetURL(), &load_consumer_, | |
606 NewCallback(this, &BookmarkBarModel::OnFavIconDataAvailable)); | |
607 load_consumer_.SetClientData(history_service, handle, node); | |
608 node->favicon_load_handle_ = handle; | |
609 } | |
610 | |
611 void BookmarkBarModel::CancelPendingFavIconLoadRequests(BookmarkBarNode* node) { | |
612 if (node->favicon_load_handle_) { | |
613 HistoryService* history = | |
614 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | |
615 if (history) | |
616 history->CancelRequest(node->favicon_load_handle_); | |
617 node->favicon_load_handle_ = 0; | |
618 } | |
619 } | |
620 | |
621 void BookmarkBarModel::GetMostRecentlyModifiedGroupNodes( | |
622 BookmarkBarNode* parent, | |
623 size_t count, | |
624 std::vector<BookmarkBarNode*>* nodes) { | |
625 if (parent != &root_ && parent->is_folder() && | |
626 parent->date_group_modified() > Time()) { | |
627 if (count == 0) { | |
628 nodes->push_back(parent); | |
629 } else { | |
630 std::vector<BookmarkBarNode*>::iterator i = | |
631 std::upper_bound(nodes->begin(), nodes->end(), parent, | |
632 &MoreRecentlyModified); | |
633 if (nodes->size() < count || i != nodes->end()) { | |
634 nodes->insert(i, parent); | |
635 while (nodes->size() > count) | |
636 nodes->pop_back(); | |
637 } | |
638 } | |
639 } // else case, the root node, which we don't care about or imported nodes | |
640 // (which have a time of 0). | |
641 for (int i = 0; i < parent->GetChildCount(); ++i) { | |
642 BookmarkBarNode* child = parent->GetChild(i); | |
643 if (child->is_folder()) | |
644 GetMostRecentlyModifiedGroupNodes(child, count, nodes); | |
645 } | |
646 } | |
647 | |
648 void BookmarkBarModel::Observe(NotificationType type, | |
649 const NotificationSource& source, | |
650 const NotificationDetails& details) { | |
651 switch (type) { | |
652 case NOTIFY_FAVICON_CHANGED: { | |
653 // Prevent the observers from getting confused for multiple favicon loads. | |
654 Details<history::FavIconChangeDetails> favicon_details(details); | |
655 for (std::set<GURL>::const_iterator i = favicon_details->urls.begin(); | |
656 i != favicon_details->urls.end(); ++i) { | |
657 BookmarkBarNode* node = GetNodeByURL(*i); | |
658 if (node) { | |
659 // Got an updated favicon, for a URL, do a new request. | |
660 node->InvalidateFavicon(); | |
661 CancelPendingFavIconLoadRequests(node); | |
662 FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, | |
663 BookmarkNodeChanged(this, node)); | |
664 } | |
665 } | |
666 break; | |
667 } | |
668 | |
669 case NOTIFY_HISTORY_LOADED: { | |
670 if (waiting_for_history_load_) { | |
671 waiting_for_history_load_ = false; | |
672 NotificationService::current()->RemoveObserver( | |
673 this, NOTIFY_HISTORY_LOADED, Source<Profile>(profile_)); | |
674 OnHistoryDone(); | |
675 } else { | |
676 NOTREACHED(); | |
677 } | |
678 break; | |
679 } | |
680 | |
681 default: | |
682 NOTREACHED(); | |
683 break; | |
684 } | |
685 } | |
686 | |
687 void BookmarkBarModel::PopulateNodesByURL(BookmarkBarNode* node) { | |
688 // NOTE: this is called with url_lock_ already held. As such, this doesn't | |
689 // explicitly grab the lock. | |
690 if (node->is_url()) | |
691 nodes_ordered_by_url_set_.insert(node); | |
692 for (int i = 0; i < node->GetChildCount(); ++i) | |
693 PopulateNodesByURL(node->GetChild(i)); | |
694 } | |
OLD | NEW |