| 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. |
| 85 // Titles are converted to the sync internal format before |
| 86 // being used as keys for the map. |
| 87 typedef base::hash_multimap<std::string, |
| 88 const BookmarkNode*> BookmarkNodeMap; |
| 89 typedef std::pair<BookmarkNodeMap::iterator, |
| 90 BookmarkNodeMap::iterator> BookmarkNodeRange; |
| 91 |
| 92 // Converts and truncates bookmark titles in the form sync does internally |
| 93 // to avoid mismatches due to sync munging titles. |
| 94 void ConvertTitleToSyncInternalFormat( |
| 95 const std::string& input, std::string* output); |
| 117 | 96 |
| 118 const BookmarkNode* parent_node_; | 97 const BookmarkNode* parent_node_; |
| 119 BookmarkNodesSet child_nodes_; | 98 BookmarkNodeMap child_nodes_; |
| 120 | 99 |
| 121 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder); | 100 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder); |
| 122 }; | 101 }; |
| 123 | 102 |
| 124 class ScopedAssociationUpdater { | 103 class ScopedAssociationUpdater { |
| 125 public: | 104 public: |
| 126 explicit ScopedAssociationUpdater(BookmarkModel* model) { | 105 explicit ScopedAssociationUpdater(BookmarkModel* model) { |
| 127 model_ = model; | 106 model_ = model; |
| 128 model->BeginExtensiveChanges(); | 107 model->BeginExtensiveChanges(); |
| 129 } | 108 } |
| 130 | 109 |
| 131 ~ScopedAssociationUpdater() { | 110 ~ScopedAssociationUpdater() { |
| 132 model_->EndExtensiveChanges(); | 111 model_->EndExtensiveChanges(); |
| 133 } | 112 } |
| 134 | 113 |
| 135 private: | 114 private: |
| 136 BookmarkModel* model_; | 115 BookmarkModel* model_; |
| 137 | 116 |
| 138 DISALLOW_COPY_AND_ASSIGN(ScopedAssociationUpdater); | 117 DISALLOW_COPY_AND_ASSIGN(ScopedAssociationUpdater); |
| 139 }; | 118 }; |
| 140 | 119 |
| 141 BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node) | 120 BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node) |
| 142 : parent_node_(parent_node) { | 121 : parent_node_(parent_node) { |
| 143 for (int i = 0; i < parent_node_->child_count(); ++i) { | 122 for (int i = 0; i < parent_node_->child_count(); ++i) { |
| 144 child_nodes_.insert(parent_node_->GetChild(i)); | 123 const BookmarkNode* child_node = parent_node_->GetChild(i); |
| 124 |
| 125 std::string title = base::UTF16ToUTF8(child_node->GetTitle()); |
| 126 ConvertTitleToSyncInternalFormat(title, &title); |
| 127 |
| 128 child_nodes_.insert(std::make_pair(title, child_node)); |
| 145 } | 129 } |
| 146 } | 130 } |
| 147 | 131 |
| 148 const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode( | 132 const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode( |
| 149 const GURL& url, const std::string& title, bool is_folder) { | 133 const GURL& url, const std::string& title, bool is_folder) { |
| 150 // Create a bookmark node from the given bookmark attributes. | 134 // First lookup a range of bookmarks with the same title. |
| 151 BookmarkNode temp_node(url); | 135 std::string adjusted_title; |
| 152 temp_node.SetTitle(base::UTF8ToUTF16(title)); | 136 ConvertTitleToSyncInternalFormat(title, &adjusted_title); |
| 153 if (is_folder) | 137 BookmarkNodeRange range = child_nodes_.equal_range(adjusted_title); |
| 154 temp_node.set_type(BookmarkNode::FOLDER); | 138 for (BookmarkNodeMap::iterator iter = range.first; |
| 155 else | 139 iter != range.second; |
| 156 temp_node.set_type(BookmarkNode::URL); | 140 ++iter) { |
| 157 | 141 |
| 158 const BookmarkNode* result = NULL; | 142 // Then within the range match the node by the folder bit |
| 159 BookmarkNodesSet::iterator iter = child_nodes_.find(&temp_node); | 143 // and the url. |
| 160 if (iter != child_nodes_.end()) { | 144 const BookmarkNode* node = iter->second; |
| 161 result = *iter; | 145 if (is_folder == node->is_folder() && url == node->url()) { |
| 162 // Remove the matched node so we don't match with it again. | 146 // Remove the matched node so we don't match with it again. |
| 163 child_nodes_.erase(iter); | 147 child_nodes_.erase(iter); |
| 148 return node; |
| 149 } |
| 164 } | 150 } |
| 165 | 151 |
| 166 return result; | 152 return NULL; |
| 153 } |
| 154 |
| 155 void BookmarkNodeFinder::ConvertTitleToSyncInternalFormat( |
| 156 const std::string& input, std::string* output) { |
| 157 syncer::SyncAPINameToServerName(input, output); |
| 158 base::TruncateUTF8ToByteSize(*output, kTitleLimitBytes, output); |
| 167 } | 159 } |
| 168 | 160 |
| 169 // Helper class to build an index of bookmark nodes by their IDs. | 161 // Helper class to build an index of bookmark nodes by their IDs. |
| 170 class BookmarkNodeIdIndex { | 162 class BookmarkNodeIdIndex { |
| 171 public: | 163 public: |
| 172 BookmarkNodeIdIndex() { } | 164 BookmarkNodeIdIndex() { } |
| 173 ~BookmarkNodeIdIndex() { } | 165 ~BookmarkNodeIdIndex() { } |
| 174 | 166 |
| 175 // Adds the given bookmark node and all its descendants to the ID index. | 167 // Adds the given bookmark node and all its descendants to the ID index. |
| 176 // Does nothing if node is NULL. | 168 // Does nothing if node is NULL. |
| (...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 syncer::SyncError::PERSISTENCE_ERROR, | 785 syncer::SyncError::PERSISTENCE_ERROR, |
| 794 message, | 786 message, |
| 795 syncer::BOOKMARKS); | 787 syncer::BOOKMARKS); |
| 796 } | 788 } |
| 797 } | 789 } |
| 798 } | 790 } |
| 799 return syncer::SyncError(); | 791 return syncer::SyncError(); |
| 800 } | 792 } |
| 801 | 793 |
| 802 } // namespace browser_sync | 794 } // namespace browser_sync |
| OLD | NEW |