OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/bookmark_model_associator.h" | 5 #include "chrome/browser/sync/glue/bookmark_model_associator.h" |
6 | 6 |
7 #include <stack> | 7 #include <stack> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 // TODO(ncarter): Pull these tags from an external protocol specification | 59 // TODO(ncarter): Pull these tags from an external protocol specification |
60 // rather than hardcoding them here. | 60 // rather than hardcoding them here. |
61 const char kBookmarkBarTag[] = "bookmark_bar"; | 61 const char kBookmarkBarTag[] = "bookmark_bar"; |
62 const char kMobileBookmarksTag[] = "synced_bookmarks"; | 62 const char kMobileBookmarksTag[] = "synced_bookmarks"; |
63 const char kOtherBookmarksTag[] = "other_bookmarks"; | 63 const char kOtherBookmarksTag[] = "other_bookmarks"; |
64 | 64 |
65 // Maximum number of bytes to allow in a title (must match sync's internal | 65 // Maximum number of bytes to allow in a title (must match sync's internal |
66 // limits; see write_node.cc). | 66 // limits; see write_node.cc). |
67 const int kTitleLimitBytes = 255; | 67 const int kTitleLimitBytes = 255; |
68 | 68 |
69 // Bookmark comparer for map of bookmark nodes. | |
70 class BookmarkComparer { | |
71 public: | |
72 // Compares the two given nodes and returns whether node1 should appear | |
73 // before node2 in strict weak ordering. | |
74 bool operator()(const BookmarkNode* node1, | |
75 const BookmarkNode* node2) const { | |
76 DCHECK(node1); | |
77 DCHECK(node2); | |
78 | |
79 // Keep folder nodes before non-folder nodes. | |
80 if (node1->is_folder() != node2->is_folder()) | |
81 return node1->is_folder(); | |
82 | |
83 // Truncate bookmark titles in the form sync does internally to avoid | |
84 // mismatches due to sync munging titles. | |
85 std::string title1 = base::UTF16ToUTF8(node1->GetTitle()); | |
86 syncer::SyncAPINameToServerName(title1, &title1); | |
87 base::TruncateUTF8ToByteSize(title1, kTitleLimitBytes, &title1); | |
88 | |
89 std::string title2 = base::UTF16ToUTF8(node2->GetTitle()); | |
90 syncer::SyncAPINameToServerName(title2, &title2); | |
91 base::TruncateUTF8ToByteSize(title2, kTitleLimitBytes, &title2); | |
92 | |
93 int result = title1.compare(title2); | |
94 if (result != 0) | |
95 return result < 0; | |
96 | |
97 return node1->url() < node2->url(); | |
98 } | |
99 }; | |
100 | |
101 // Provides the following abstraction: given a parent bookmark node, find best | 69 // Provides the following abstraction: given a parent bookmark node, find best |
102 // matching child node for many sync nodes. | 70 // matching child node for many sync nodes. |
103 class BookmarkNodeFinder { | 71 class BookmarkNodeFinder { |
104 public: | 72 public: |
105 // Creates an instance with the given parent bookmark node. | 73 // Creates an instance with the given parent bookmark node. |
106 explicit BookmarkNodeFinder(const BookmarkNode* parent_node); | 74 explicit BookmarkNodeFinder(const BookmarkNode* parent_node); |
107 | 75 |
108 // Finds the bookmark node that matches the given url, title and folder | 76 // Finds the bookmark node that matches the given url, title and folder |
109 // attribute. Returns the matching node if one exists; NULL otherwise. If a | 77 // attribute. Returns the matching node if one exists; NULL otherwise. If a |
110 // matching node is found, it's removed for further matches. | 78 // matching node is found, it's removed for further matches. |
111 const BookmarkNode* FindBookmarkNode(const GURL& url, | 79 const BookmarkNode* FindBookmarkNode(const GURL& url, |
112 const std::string& title, | 80 const std::string& title, |
113 bool is_folder); | 81 bool is_folder); |
114 | 82 |
115 private: | 83 private: |
116 typedef std::multiset<const BookmarkNode*, BookmarkComparer> BookmarkNodesSet; | 84 // Maps bookmark node titles to instances, duplicates allowed |
Nicolas Zea
2014/09/29 18:33:56
nit: Comment that the title is stored in sync inte
stanisc
2014/09/29 22:34:22
Done.
| |
85 typedef base::hash_multimap<std::string, | |
86 const BookmarkNode*> BookmarkNodeMap; | |
87 typedef std::pair<BookmarkNodeMap::iterator, | |
88 BookmarkNodeMap::iterator> BookmarkNodeRange; | |
117 | 89 |
118 const BookmarkNode* parent_node_; | 90 const BookmarkNode* parent_node_; |
119 BookmarkNodesSet child_nodes_; | 91 BookmarkNodeMap child_nodes_; |
120 | 92 |
121 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder); | 93 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder); |
122 }; | 94 }; |
123 | 95 |
124 class ScopedAssociationUpdater { | 96 class ScopedAssociationUpdater { |
125 public: | 97 public: |
126 explicit ScopedAssociationUpdater(BookmarkModel* model) { | 98 explicit ScopedAssociationUpdater(BookmarkModel* model) { |
127 model_ = model; | 99 model_ = model; |
128 model->BeginExtensiveChanges(); | 100 model->BeginExtensiveChanges(); |
129 } | 101 } |
130 | 102 |
131 ~ScopedAssociationUpdater() { | 103 ~ScopedAssociationUpdater() { |
132 model_->EndExtensiveChanges(); | 104 model_->EndExtensiveChanges(); |
133 } | 105 } |
134 | 106 |
135 private: | 107 private: |
136 BookmarkModel* model_; | 108 BookmarkModel* model_; |
137 | 109 |
138 DISALLOW_COPY_AND_ASSIGN(ScopedAssociationUpdater); | 110 DISALLOW_COPY_AND_ASSIGN(ScopedAssociationUpdater); |
139 }; | 111 }; |
140 | 112 |
141 BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node) | 113 BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node) |
142 : parent_node_(parent_node) { | 114 : parent_node_(parent_node) { |
143 for (int i = 0; i < parent_node_->child_count(); ++i) { | 115 for (int i = 0; i < parent_node_->child_count(); ++i) { |
144 child_nodes_.insert(parent_node_->GetChild(i)); | 116 const BookmarkNode* child_node = parent_node_->GetChild(i); |
117 // Convert and truncate bookmark titles in the form sync does internally | |
118 // to avoid mismatches due to sync munging titles. | |
119 std::string title = base::UTF16ToUTF8(child_node->GetTitle()); | |
120 syncer::SyncAPINameToServerName(title, &title); | |
Nicolas Zea
2014/09/29 18:33:56
nit: probably good to go ahead and pull this and t
stanisc
2014/09/29 22:34:22
Done.
| |
121 base::TruncateUTF8ToByteSize(title, kTitleLimitBytes, &title); | |
122 | |
123 child_nodes_.insert(std::make_pair(title, child_node)); | |
145 } | 124 } |
146 } | 125 } |
147 | 126 |
148 const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode( | 127 const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode( |
149 const GURL& url, const std::string& title, bool is_folder) { | 128 const GURL& url, const std::string& title, bool is_folder) { |
150 // Create a bookmark node from the given bookmark attributes. | 129 // First lookup a range of bookmarks with the same title. |
151 BookmarkNode temp_node(url); | 130 std::string adjusted_title; |
152 temp_node.SetTitle(base::UTF8ToUTF16(title)); | 131 syncer::SyncAPINameToServerName(title, &adjusted_title); |
153 if (is_folder) | 132 base::TruncateUTF8ToByteSize( |
154 temp_node.set_type(BookmarkNode::FOLDER); | 133 adjusted_title, kTitleLimitBytes, &adjusted_title); |
155 else | 134 BookmarkNodeRange range = child_nodes_.equal_range(adjusted_title); |
156 temp_node.set_type(BookmarkNode::URL); | 135 for (BookmarkNodeMap::iterator iter = range.first; |
136 iter != range.second; | |
137 ++iter) { | |
157 | 138 |
158 const BookmarkNode* result = NULL; | 139 // Then within the range match the node by the folder bit |
159 BookmarkNodesSet::iterator iter = child_nodes_.find(&temp_node); | 140 // and the url. |
160 if (iter != child_nodes_.end()) { | 141 const BookmarkNode* node = iter->second; |
161 result = *iter; | 142 if (is_folder == node->is_folder() && url == node->url()) { |
162 // Remove the matched node so we don't match with it again. | 143 // Remove the matched node so we don't match with it again. |
163 child_nodes_.erase(iter); | 144 child_nodes_.erase(iter); |
145 return node; | |
146 } | |
164 } | 147 } |
165 | 148 |
166 return result; | 149 return NULL; |
167 } | 150 } |
168 | 151 |
169 // Helper class to build an index of bookmark nodes by their IDs. | 152 // Helper class to build an index of bookmark nodes by their IDs. |
170 class BookmarkNodeIdIndex { | 153 class BookmarkNodeIdIndex { |
171 public: | 154 public: |
172 BookmarkNodeIdIndex() { } | 155 BookmarkNodeIdIndex() { } |
173 ~BookmarkNodeIdIndex() { } | 156 ~BookmarkNodeIdIndex() { } |
174 | 157 |
175 // Adds the given bookmark node and all its descendants to the ID index. | 158 // Adds the given bookmark node and all its descendants to the ID index. |
176 // Does nothing if node is NULL. | 159 // Does nothing if node is NULL. |
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
793 syncer::SyncError::PERSISTENCE_ERROR, | 776 syncer::SyncError::PERSISTENCE_ERROR, |
794 message, | 777 message, |
795 syncer::BOOKMARKS); | 778 syncer::BOOKMARKS); |
796 } | 779 } |
797 } | 780 } |
798 } | 781 } |
799 return syncer::SyncError(); | 782 return syncer::SyncError(); |
800 } | 783 } |
801 | 784 |
802 } // namespace browser_sync | 785 } // namespace browser_sync |
OLD | NEW |