15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <functional> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/i18n/string_compare.h" 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/logging.h" 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/macros.h" 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/string_util.h" 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h" 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_index.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_match.h" 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model_observer.h" 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_node_data.h" 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_storage.h" 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_utils.h" 230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/favicon_base/favicon_types.h" 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "grit/components_strings.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time; 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing bookmarks::BookmarkClient; 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using bookmarks::BookmarkExpandedStateTracker; 3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using bookmarks::BookmarkIndex; 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using bookmarks::BookmarkLoadDetails; 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using bookmarks::BookmarkMatch; 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using bookmarks::BookmarkNodeData; 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using bookmarks::BookmarkStorage; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper to get a mutable bookmark node. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkNode* AsMutable(const BookmarkNode* node) { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return const_cast<BookmarkNode*>(node); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Helper to get a mutable permanent bookmark node. 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) { 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return const_cast<BookmarkPermanentNode*>(node); 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Comparator used when sorting permanent nodes. Nodes that are initially 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// visible are sorted before nodes that are initially hidden. 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class VisibilityComparator 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : public std::binary_function<const BookmarkPermanentNode*, 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const BookmarkPermanentNode*, 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool> { 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public: 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) explicit VisibilityComparator(BookmarkClient* client) : client_(client) {} 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Returns true if |n1| preceeds |n2|. 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool operator()(const BookmarkPermanentNode* n1, 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const BookmarkPermanentNode* n2) { 6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) bool n1_visible = client_->IsPermanentNodeVisible(n1); 6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) bool n2_visible = client_->IsPermanentNodeVisible(n2); 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return n1_visible != n2_visible && n1_visible; 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private: 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BookmarkClient* client_; 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Comparator used when sorting bookmarks. Folders are sorted first, then 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// bookmarks. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SortComparator : public std::binary_function<const BookmarkNode*, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode*, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool> { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit SortComparator(icu::Collator* collator) : collator_(collator) {} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if |n1| preceeds |n2|. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (n1->type() == n2->type()) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Types are the same, compare the names. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!collator_) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return n1->GetTitle() < n2->GetTitle(); 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return base::i18n::CompareString16WithCollator( 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Types differ, sort such that folders come first. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return n1->is_folder(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icu::Collator* collator_; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BookmarkModel -------------------------------------------------------------- 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBookmarkModel::BookmarkModel(BookmarkClient* client) 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : client_(client), 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_(false), 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root_(GURL()), 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark_bar_node_(NULL), 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other_node_(NULL), 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mobile_node_(NULL), 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_node_id_(1), 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observers_(ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY), 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_signal_(true, false), 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensive_changes_(0) { 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(client_); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkModel::~BookmarkModel() { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkModelBeingDeleted(this)); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (store_.get()) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The store maintains a reference back to us. We need to tell it we're gone 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that it doesn't try and invoke a method back on us again. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->BookmarkModelDeleted(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Shutdown() { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (loaded_) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See comment in HistoryService::ShutdownOnUIThread where this is invoked for 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // details. It is also called when the BookmarkModel is deleted. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_signal_.Signal(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BookmarkModel::Load( 1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PrefService* pref_service, 1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& accept_languages, 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::FilePath& profile_path, 1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const scoped_refptr<base::SequencedTaskRunner>& io_task_runner, 1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the store is non-null, it means Load was already invoked. Load should 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only be invoked once. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch expanded_state_tracker_.reset( 1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu new BookmarkExpandedStateTracker(this, pref_service)); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the bookmarks. BookmarkStorage notifies us when done. 150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch store_ .reset(new BookmarkStorage(this, profile_path, io_task_runner.get())); 1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu store_->LoadBookmarks(CreateLoadDetails(accept_languages), ui_task_runner); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkModel::GetParentForNewNodes() { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const BookmarkNode*> nodes = 156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bookmarks::GetMostRecentlyModifiedUserFolders(this, 1); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!nodes.empty()); // This list is always padded with default folders. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nodes[0]; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::AddObserver(BookmarkModelObserver* observer) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observers_.AddObserver(observer); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observers_.RemoveObserver(observer); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::BeginExtensiveChanges() { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (++extensive_changes_ == 1) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensiveBookmarkChangesBeginning(this)); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::EndExtensiveChanges() { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --extensive_changes_; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(extensive_changes_, 0); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (extensive_changes_ == 0) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensiveBookmarkChangesEnded(this)); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BookmarkModel::BeginGroupedChanges() { 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GroupedBookmarkChangesBeginning(this)); 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BookmarkModel::EndGroupedChanges() { 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GroupedBookmarkChangesEnded(this)); 193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Remove(const BookmarkNode* parent, int index) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_ || !IsValidIndex(parent, index, false) || is_root_node(parent)) { 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveAndDeleteNode(AsMutable(parent->GetChild(index))); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void BookmarkModel::RemoveAllUserBookmarks() { 2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::set<GURL> removed_urls; 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScopedVector<BookmarkNode> removed_nodes; 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnWillRemoveAllUserBookmarks(this)); 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) BeginExtensiveChanges(); 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Skip deleting permanent nodes. Permanent bookmark nodes are the root and 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // its immediate children. For removing all non permanent nodes just remove 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // all children of non-root permanent nodes. 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::AutoLock url_lock(url_lock_); 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int i = 0; i < root_.child_count(); ++i) { 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BookmarkNode* permanent_node = root_.GetChild(i); 21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 21946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!client_->CanBeEditedByUser(permanent_node)) 22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) continue; 22146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int j = permanent_node->child_count() - 1; j >= 0; --j) { 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BookmarkNode* child_node = permanent_node->GetChild(j); 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) removed_nodes.push_back(child_node); 2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) RemoveNodeAndGetRemovedUrls(child_node, &removed_urls); 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EndExtensiveChanges(); 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (store_.get()) 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) store_->ScheduleSave(); 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BookmarkAllUserNodesRemoved(this, removed_urls)); 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Move(const BookmarkNode* node, 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* new_parent, 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_root_node(new_parent) || is_permanent_node(node)) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_parent->HasAncestor(node)) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't make an ancestor of the node be a child of the node. 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* old_parent = node->parent(); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_index = old_parent->GetIndexOf(node); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_parent == new_parent && 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (index == old_index || index == old_index + 1)) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Node is already in this position, nothing to do. 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetDateFolderModified(new_parent, Time::Now()); 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_parent == new_parent && index > old_index) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index--; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode* mutable_new_parent = AsMutable(new_parent); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable_new_parent->Add(AsMutable(node), index); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNodeMoved(this, old_parent, old_index, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_parent, index)); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Copy(const BookmarkNode* node, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* new_parent, 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_root_node(new_parent) || is_permanent_node(node)) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_parent->HasAncestor(node)) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't make an ancestor of the node be a child of the node. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDateFolderModified(new_parent, Time::Now()); 29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) BookmarkNodeData drag_data(node); 29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::vector<BookmarkNodeData::Element> elements(drag_data.elements); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CloneBookmarkNode will use BookmarkModel methods to do the job, so we 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't need to send notifications here. 296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bookmarks::CloneBookmarkNode(this, elements, new_parent, index, true); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(node); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode* mutable_node = AsMutable(node); 306010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) LoadFavicon( 307010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) mutable_node, 308010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) client_->PreferTouchIcon() ? 309010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) favicon_base::TOUCH_ICON : 310010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) favicon_base::FAVICON); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return node->favicon(); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) { 316010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(node); 317010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return node->favicon_type(); 318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BookmarkModel::SetTitle(const BookmarkNode* node, 3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::string16& title) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!node) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->GetTitle() == title) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnWillChangeBookmarkNode(this, node)); 336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The title index doesn't support changing the title, instead we remove then 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add it back. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index_->Remove(node); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AsMutable(node)->SetTitle(title); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index_->Add(node); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNodeChanged(this, node)); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!node) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We cannot change the URL of a folder. 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->is_folder()) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->url() == url) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode* mutable_node = AsMutable(node); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable_node->InvalidateFavicon(); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelPendingFaviconLoadRequests(mutable_node); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnWillChangeBookmarkNode(this, node)); 371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RemoveNodeFromURLSet(mutable_node); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable_node->set_url(url); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nodes_ordered_by_url_set_.insert(mutable_node); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNodeChanged(this, node)); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node, 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& key, 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& value) { 389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string old_value; 390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (node->GetMetaInfo(key, &old_value) && old_value == value) 391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 3938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 3948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) OnWillChangeBookmarkMetaInfo(this, node)); 3958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (AsMutable(node)->SetMetaInfo(key, value) && store_.get()) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 3988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 4008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) BookmarkMetaInfoChanged(this, node)); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BookmarkModel::SetNodeMetaInfoMap( 404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const BookmarkNode* node, 405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const BookmarkNode::MetaInfoMap& meta_info_map) { 406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap(); 407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if ((!old_meta_info_map && meta_info_map.empty()) || 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) (old_meta_info_map && meta_info_map == *old_meta_info_map)) 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) OnWillChangeBookmarkMetaInfo(this, node)); 413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) AsMutable(node)->SetMetaInfoMap(meta_info_map); 415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (store_.get()) 416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) store_->ScheduleSave(); 417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BookmarkMetaInfoChanged(this, node)); 420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node, 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& key) { 424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap(); 425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end()) 426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 4288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 4298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) OnWillChangeBookmarkMetaInfo(this, node)); 4308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (AsMutable(node)->DeleteMetaInfo(key) && store_.get()) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 4338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 4348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 4358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) BookmarkMetaInfoChanged(this, node)); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BookmarkModel::SetNodeSyncTransactionVersion( 439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const BookmarkNode* node, 440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int64 sync_transaction_version) { 44146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(client_->CanSyncNode(node)); 44246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (sync_transaction_version == node->sync_transaction_version()) 444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AsMutable(node)->set_sync_transaction_version(sync_transaction_version); 447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (store_.get()) 448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) store_->ScheduleSave(); 449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 4515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BookmarkModel::OnFaviconChanged(const std::set<GURL>& urls) { 4525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Ignore events if |Load| has not been called yet. 4535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!store_) 4545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 4555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Prevent the observers from getting confused for multiple favicon loads. 4575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) { 4585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::vector<const BookmarkNode*> nodes; 4595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu GetNodesByURL(*i, &nodes); 4605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (size_t i = 0; i < nodes.size(); ++i) { 4615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Got an updated favicon, for a URL, do a new request. 4625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BookmarkNode* node = AsMutable(nodes[i]); 4635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu node->InvalidateFavicon(); 4645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu CancelPendingFaviconLoadRequests(node); 4655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FOR_EACH_OBSERVER(BookmarkModelObserver, 4665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu observers_, 4675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BookmarkNodeFaviconChanged(this, node)); 4685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 4715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetDateAdded(const BookmarkNode* node, 473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Time date_added) { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!node) { 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->date_added() == date_added) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_permanent_node(node)) { 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AsMutable(node)->set_date_added(date_added); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Syncing might result in dates newer than the folder's last modified date. 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (date_added > node->parent()->date_folder_modified()) { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Will trigger store_->ScheduleSave(). 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDateFolderModified(node->parent(), date_added); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (store_.get()) { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::GetNodesByURL(const GURL& url, 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const BookmarkNode*>* nodes) { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode tmp_node(url); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) { 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nodes->push_back(*i); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 50946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL( 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const BookmarkNode*> nodes; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetNodesByURL(url, &nodes); 513116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded); 51446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 51546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Look for the first node that the user can edit. 51646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for (size_t i = 0; i < nodes.size(); ++i) { 51746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (client_->CanBeEditedByUser(nodes[i])) 51846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return nodes[i]; 51946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 52046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 52146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return NULL; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::HasBookmarks() { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !nodes_ordered_by_url_set_.empty(); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::IsBookmarked(const GURL& url) { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsBookmarkedNoLock(url); 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::GetBookmarks( 53546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) std::vector<BookmarkModel::URLAndTitle>* bookmarks) { 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL* last_url = NULL; 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin(); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != nodes_ordered_by_url_set_.end(); ++i) { 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL* url = &((*i)->url()); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only add unique URLs. 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!last_url || *url != *last_url) { 54346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) BookmarkModel::URLAndTitle bookmark; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark.url = *url; 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark.title = (*i)->GetTitle(); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmarks->push_back(bookmark); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_url = url; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::BlockTillLoaded() { 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_signal_.Wait(); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent, 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 558a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& title) { 5590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return AddFolderWithMetaInfo(parent, index, title, NULL); 5600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 5610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst BookmarkNode* BookmarkModel::AddFolderWithMetaInfo( 5620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const BookmarkNode* parent, 5630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch int index, 5640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const base::string16& title, 5650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const BookmarkNode::MetaInfoMap* meta_info) { 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) { 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't add to the root. 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), GURL()); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_node->set_date_folder_modified(Time::Now()); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Folders shouldn't have line breaks in their titles. 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_node->SetTitle(title); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_node->set_type(BookmarkNode::FOLDER); 5770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (meta_info) 5780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch new_node->SetMetaInfoMap(*meta_info); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return AddNode(AsMutable(parent), index, new_node); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent, 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& title, 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url) { 5870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return AddURLWithCreationTimeAndMetaInfo( 5880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch parent, 5890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch index, 5900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch base::CollapseWhitespace(title, false), 5910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch url, 5920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Time::Now(), 5930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch NULL); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo( 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* parent, 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 599a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& title, 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, 6010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const Time& creation_time, 6020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const BookmarkNode::MetaInfoMap* meta_info) { 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_ || !url.is_valid() || is_root_node(parent) || 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !IsValidIndex(parent, index, true)) { 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Syncing may result in dates newer than the last modified date. 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (creation_time > parent->date_folder_modified()) 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDateFolderModified(parent, creation_time); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), url); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_node->SetTitle(title); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_node->set_date_added(creation_time); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_node->set_type(BookmarkNode::URL); 6170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (meta_info) 6180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch new_node->SetMetaInfoMap(*meta_info); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only hold the lock for the duration of the insert. 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nodes_ordered_by_url_set_.insert(new_node); 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return AddNode(AsMutable(parent), index, new_node); 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SortChildren(const BookmarkNode* parent) { 63046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(client_->CanBeEditedByUser(parent)); 63146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!parent || !parent->is_folder() || is_root_node(parent) || 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parent->child_count() <= 1) { 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 637868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnWillReorderBookmarkNode(this, parent)); 639868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UErrorCode error = U_ZERO_ERROR; 641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error)); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (U_FAILURE(error)) 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) collator.reset(NULL); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode* mutable_parent = AsMutable(parent); 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::sort(mutable_parent->children().begin(), 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable_parent->children().end(), 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SortComparator(collator.get())); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNodeChildrenReordered(this, parent)); 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void BookmarkModel::ReorderChildren( 657868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const BookmarkNode* parent, 6582385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch const std::vector<const BookmarkNode*>& ordered_nodes) { 65946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(client_->CanBeEditedByUser(parent)); 66046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 661868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Ensure that all children in |parent| are in |ordered_nodes|. 662868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size()); 663868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (size_t i = 0; i < ordered_nodes.size(); ++i) 664868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_EQ(parent, ordered_nodes[i]->parent()); 665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 666868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 667868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnWillReorderBookmarkNode(this, parent)); 668868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 6692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch AsMutable(parent)->SetChildren( 6702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch *(reinterpret_cast<const std::vector<BookmarkNode*>*>(&ordered_nodes))); 671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 672868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (store_.get()) 673868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) store_->ScheduleSave(); 674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 675868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 676868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BookmarkNodeChildrenReordered(this, parent)); 677868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 678868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent, 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Time time) { 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(parent); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AsMutable(parent)->set_date_folder_modified(time); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) { 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDateFolderModified(node, Time()); 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid BookmarkModel::GetBookmarksMatching( 693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t max_count, 6950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch std::vector<BookmarkMatch>* matches) { 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_) 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch index_->GetBookmarksMatching(text, max_count, matches); 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::ClearStore() { 703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch store_.reset(); 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type, 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool value) { 70846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) BookmarkPermanentNode* node = AsMutable(PermanentNode(type)); 70946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) node->set_visible(value || client_->IsPermanentNodeVisible(node)); 710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const BookmarkPermanentNode* BookmarkModel::PermanentNode( 713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BookmarkNode::Type type) { 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(loaded_); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BookmarkNode::BOOKMARK_BAR: 717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return bookmark_bar_node_; 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BookmarkNode::OTHER_NODE: 719cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return other_node_; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BookmarkNode::MOBILE: 721cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return mobile_node_; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 724cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return NULL; 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) { 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode tmp_node(url); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (nodes_ordered_by_url_set_.find(&tmp_node) != 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nodes_ordered_by_url_set_.end()); 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::RemoveNode(BookmarkNode* node, 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<GURL>* removed_urls) { 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!loaded_ || !node || is_permanent_node(node)) { 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) url_lock_.AssertAcquired(); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->is_url()) { 7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RemoveNodeFromURLSet(node); 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) removed_urls->insert(node->url()); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index_->Remove(node); 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelPendingFaviconLoadRequests(node); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Recurse through children. 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = node->child_count() - 1; i >= 0; --i) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveNode(node->GetChild(i), removed_urls); 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BookmarkModel::DoneLoading(scoped_ptr<BookmarkLoadDetails> details) { 7565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(details); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (loaded_) { 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should only ever be loaded once. 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_node_id_ = details->max_id(); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (details->computed_checksum() != details->stored_checksum() || 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) details->ids_reassigned()) { 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If bookmarks file changed externally, the IDs may have changed 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // externally. In that case, the decoder may have reassigned IDs to make 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them unique. So when the file has changed externally, we should save the 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bookmarks file to persist new IDs. 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark_bar_node_ = details->release_bb_node(); 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other_node_ = details->release_other_folder_node(); 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mobile_node_ = details->release_mobile_folder_node(); 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index_.reset(details->release_index()); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Get any extra nodes and take ownership of them at the |root_|. 77946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) std::vector<BookmarkPermanentNode*> extra_nodes; 78046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) details->release_extra_nodes(&extra_nodes); 78146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // WARNING: order is important here, various places assume the order is 783cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // constant (but can vary between embedders with the initial visibility 784cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // of permanent nodes). 78546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) std::vector<BookmarkPermanentNode*> root_children; 78646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) root_children.push_back(bookmark_bar_node_); 78746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) root_children.push_back(other_node_); 78846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) root_children.push_back(mobile_node_); 78946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for (size_t i = 0; i < extra_nodes.size(); ++i) 79046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) root_children.push_back(extra_nodes[i]); 79146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) std::stable_sort(root_children.begin(), 79246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) root_children.end(), 793cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VisibilityComparator(client_)); 79446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for (size_t i = 0; i < root_children.size(); ++i) 795cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) root_.Add(root_children[i], static_cast<int>(i)); 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 797f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) root_.SetMetaInfoMap(details->model_meta_info_map()); 798f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) root_.set_sync_transaction_version(details->model_sync_transaction_version()); 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update nodes_ordered_by_url_set_ from the nodes. 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PopulateNodesByURL(&root_); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_ = true; 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_signal_.Signal(); 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify our direct observers. 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BookmarkModelLoaded(this, details->ids_reassigned())); 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) { 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<BookmarkNode> node(delete_me); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 818c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const BookmarkNode* parent = node->parent(); 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(parent); 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = parent->GetIndexOf(node.get()); 821c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 822868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 823868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnWillRemoveBookmarks(this, parent, index, node.get())); 824868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 8257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::set<GURL> removed_urls; 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock url_lock(url_lock_); 8287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls); 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 834010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FOR_EACH_OBSERVER( 835010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BookmarkModelObserver, 836010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) observers_, 837010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); 838c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 839c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BookmarkModel::RemoveNodeFromURLSet(BookmarkNode* node) { 8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // NOTE: this is called in such a way that url_lock_ is already held. As 8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // such, this doesn't explicitly grab the lock. 8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); 8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(i != nodes_ordered_by_url_set_.end()); 8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // i points to the first node with the URL, advance until we find the 8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // node we're removing. 8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (*i != node) 8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++i; 8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) nodes_ordered_by_url_set_.erase(i); 8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node, 853c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::set<GURL>* removed_urls) { 854c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // NOTE: this method should be always called with |url_lock_| held. 855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This method does not explicitly acquires a lock. 856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) url_lock_.AssertAcquired(); 857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(removed_urls); 858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) BookmarkNode* parent = AsMutable(node->parent()); 859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(parent); 860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parent->Remove(node); 861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RemoveNode(node, removed_urls); 862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // RemoveNode adds an entry to removed_urls for each node of type URL. As we 863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // allow duplicates we need to remove any entries that are still bookmarked. 864c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (std::set<GURL>::iterator i = removed_urls->begin(); 865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) i != removed_urls->end();) { 866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (IsBookmarkedNoLock(*i)) { 867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // When we erase the iterator pointing at the erasee is 868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // invalidated, so using i++ here within the "erase" call is 869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // important as it advances the iterator before passing the 870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // old value through to erase. 871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) removed_urls->erase(i++); 872c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++i; 874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 876c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BookmarkNode* node) { 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parent->Add(node, index); 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_.get()) 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_->ScheduleSave(); 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNodeAdded(this, parent, index)); 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index_->Add(node); 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return node; 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool allow_end) { 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (parent && parent->is_folder() && 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (index >= 0 && (index < parent->child_count() || 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (allow_end && index == parent->child_count())))); 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkPermanentNode* BookmarkModel::CreatePermanentNode( 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::Type type) { 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type == BookmarkNode::BOOKMARK_BAR || 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type == BookmarkNode::OTHER_NODE || 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type == BookmarkNode::MOBILE); 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkPermanentNode* node = 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new BookmarkPermanentNode(generate_next_node_id()); 90946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) node->set_type(type); 91046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) node->set_visible(client_->IsPermanentNodeVisible(node)); 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int title_id; 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BookmarkNode::BOOKMARK_BAR: 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_id = IDS_BOOKMARK_BAR_FOLDER_NAME; 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BookmarkNode::OTHER_NODE: 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME; 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BookmarkNode::MOBILE: 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME; 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_id = IDS_BOOKMARK_BAR_FOLDER_NAME; 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->SetTitle(l10n_util::GetStringUTF16(title_id)); 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return node; 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::OnFaviconDataAvailable( 9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BookmarkNode* node, 934010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) favicon_base::IconType icon_type, 9350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const favicon_base::FaviconImageResult& image_result) { 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(node); 9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->set_favicon_state(BookmarkNode::LOADED_FAVICON); 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!image_result.image.IsEmpty()) { 940010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) node->set_favicon_type(icon_type); 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->set_favicon(image_result.image); 9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) node->set_icon_url(image_result.icon_url); 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconLoaded(node); 944010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else if (icon_type == favicon_base::TOUCH_ICON) { 945010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Couldn't load the touch icon, fallback to the regular favicon. 946010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(client_->PreferTouchIcon()); 947010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) LoadFavicon(node, favicon_base::FAVICON); 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 951010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BookmarkModel::LoadFavicon( 952010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BookmarkNode* node, 953010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) favicon_base::IconType icon_type) { 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->is_folder()) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(node->url().is_valid()); 958010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) node->set_favicon_state(BookmarkNode::LOADING_FAVICON); 959116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::CancelableTaskTracker::TaskId taskId = 960116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch client_->GetFaviconImageForPageURL( 961116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch node->url(), 962116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch icon_type, 963116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind( 964116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &BookmarkModel::OnFaviconDataAvailable, 965116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Unretained(this), 966116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch node, 967116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch icon_type), 968116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &cancelable_task_tracker_); 9695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (taskId != base::CancelableTaskTracker::kBadTaskId) 9705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu node->set_favicon_load_task_id(taskId); 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::FaviconLoaded(const BookmarkNode* node) { 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNodeFaviconChanged(this, node)); 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) { 9795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) { 9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cancelable_task_tracker_.TryCancel(node->favicon_load_task_id()); 9815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) { 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: this is called with url_lock_ already held. As such, this doesn't 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // explicitly grab the lock. 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->is_url()) 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nodes_ordered_by_url_set_.insert(node); 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < node->child_count(); ++i) 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PopulateNodesByURL(node->GetChild(i)); 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 BookmarkModel::generate_next_node_id() { 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return next_node_id_++; 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuscoped_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails( 9995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& accept_languages) { 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkPermanentNode* bb_node = 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreatePermanentNode(BookmarkNode::BOOKMARK_BAR); 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkPermanentNode* other_node = 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreatePermanentNode(BookmarkNode::OTHER_NODE); 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkPermanentNode* mobile_node = 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreatePermanentNode(BookmarkNode::MOBILE); 10065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( 10075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu bb_node, 10085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu other_node, 10095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu mobile_node, 101046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) client_->GetLoadExtraNodesCallback(), 10111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci new BookmarkIndex(client_, accept_languages), 10125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu next_node_id_)); 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1014