| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/importer/profile_writer.h" | 5 #include "chrome/browser/importer/profile_writer.h" |
| 6 | 6 |
| 7 #include <string> |
| 8 |
| 9 #include "base/string_number_conversions.h" |
| 7 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| 8 #include "base/threading/thread.h" | 11 #include "base/threading/thread.h" |
| 9 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/browser/bookmarks/bookmark_model.h" | 13 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 11 #include "chrome/browser/password_manager/password_store.h" | 14 #include "chrome/browser/password_manager/password_store.h" |
| 12 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
| 13 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/search_engines/template_url.h" | 17 #include "chrome/browser/search_engines/template_url.h" |
| 15 #include "chrome/browser/search_engines/template_url_model.h" | 18 #include "chrome/browser/search_engines/template_url_model.h" |
| 16 #include "chrome/common/pref_names.h" | 19 #include "chrome/common/pref_names.h" |
| 17 #include "content/common/notification_service.h" | 20 #include "content/common/notification_service.h" |
| 18 | 21 |
| 22 namespace { |
| 23 |
| 24 // Generates a unique folder name. If |folder_name| is not unique, then this |
| 25 // repeatedly tests for '|folder_name| + (i)' until a unique name is found. |
| 26 string16 GenerateUniqueFolderName(BookmarkModel* model, |
| 27 const string16& folder_name) { |
| 28 // Build a set containing the bookmark bar folder names. |
| 29 std::set<string16> existing_folder_names; |
| 30 const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode(); |
| 31 for (int i = 0; i < bookmark_bar->child_count(); ++i) { |
| 32 const BookmarkNode* node = bookmark_bar->GetChild(i); |
| 33 if (node->is_folder()) |
| 34 existing_folder_names.insert(node->GetTitle()); |
| 35 } |
| 36 |
| 37 // If the given name is unique, use it. |
| 38 if (existing_folder_names.find(folder_name) == existing_folder_names.end()) |
| 39 return folder_name; |
| 40 |
| 41 // Otherwise iterate until we find a unique name. |
| 42 for (size_t i = 1; i <= existing_folder_names.size(); ++i) { |
| 43 string16 name = folder_name + ASCIIToUTF16(" (") + base::IntToString16(i) + |
| 44 ASCIIToUTF16(")"); |
| 45 if (existing_folder_names.find(name) == existing_folder_names.end()) |
| 46 return name; |
| 47 } |
| 48 |
| 49 NOTREACHED(); |
| 50 return folder_name; |
| 51 } |
| 52 |
| 53 // Shows the bookmarks toolbar. |
| 54 void ShowBookmarkBar(Profile* profile) { |
| 55 PrefService* prefs = profile->GetPrefs(); |
| 56 // Check whether the bookmark bar is shown in current pref. |
| 57 if (!prefs->GetBoolean(prefs::kShowBookmarkBar)) { |
| 58 // Set the pref and notify the notification service. |
| 59 prefs->SetBoolean(prefs::kShowBookmarkBar, true); |
| 60 prefs->ScheduleSavePersistentPrefs(); |
| 61 Source<Profile> source(profile); |
| 62 NotificationService::current()->Notify( |
| 63 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, source, |
| 64 NotificationService::NoDetails()); |
| 65 } |
| 66 } |
| 67 |
| 68 } // namespace |
| 69 |
| 19 ProfileWriter::BookmarkEntry::BookmarkEntry() | 70 ProfileWriter::BookmarkEntry::BookmarkEntry() |
| 20 : in_toolbar(false), | 71 : in_toolbar(false), |
| 21 is_folder(false) {} | 72 is_folder(false) {} |
| 22 | 73 |
| 23 ProfileWriter::BookmarkEntry::~BookmarkEntry() {} | 74 ProfileWriter::BookmarkEntry::~BookmarkEntry() {} |
| 24 | 75 |
| 25 ProfileWriter::ProfileWriter(Profile* profile) : profile_(profile) {} | 76 ProfileWriter::ProfileWriter(Profile* profile) : profile_(profile) {} |
| 26 | 77 |
| 27 bool ProfileWriter::BookmarkModelIsLoaded() const { | 78 bool ProfileWriter::BookmarkModelIsLoaded() const { |
| 28 return profile_->GetBookmarkModel()->IsLoaded(); | 79 return profile_->GetBookmarkModel()->IsLoaded(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 54 PrefService* prefs = profile_->GetPrefs(); | 105 PrefService* prefs = profile_->GetPrefs(); |
| 55 // NOTE: We set the kHomePage value, but keep the NewTab page as the homepage. | 106 // NOTE: We set the kHomePage value, but keep the NewTab page as the homepage. |
| 56 const PrefService::Preference* pref = prefs->FindPreference(prefs::kHomePage); | 107 const PrefService::Preference* pref = prefs->FindPreference(prefs::kHomePage); |
| 57 if (pref && !pref->IsManaged()) { | 108 if (pref && !pref->IsManaged()) { |
| 58 prefs->SetString(prefs::kHomePage, home_page.spec()); | 109 prefs->SetString(prefs::kHomePage, home_page.spec()); |
| 59 prefs->ScheduleSavePersistentPrefs(); | 110 prefs->ScheduleSavePersistentPrefs(); |
| 60 } | 111 } |
| 61 } | 112 } |
| 62 | 113 |
| 63 void ProfileWriter::AddBookmarks(const std::vector<BookmarkEntry>& bookmarks, | 114 void ProfileWriter::AddBookmarks(const std::vector<BookmarkEntry>& bookmarks, |
| 64 const string16& first_folder_name, | 115 const string16& top_level_folder_name) { |
| 65 int options) { | |
| 66 if (bookmarks.empty()) | 116 if (bookmarks.empty()) |
| 67 return; | 117 return; |
| 68 | 118 |
| 69 BookmarkModel* model = profile_->GetBookmarkModel(); | 119 BookmarkModel* model = profile_->GetBookmarkModel(); |
| 70 DCHECK(model->IsLoaded()); | 120 DCHECK(model->IsLoaded()); |
| 71 | 121 |
| 72 bool import_to_bookmark_bar = ((options & IMPORT_TO_BOOKMARK_BAR) != 0); | 122 // If the bookmark bar is currently empty, we should import directly to it. |
| 73 string16 real_first_folder = import_to_bookmark_bar ? first_folder_name : | 123 // Otherwise, we should import everything to a subfolder. |
| 74 GenerateUniqueFolderName(model, first_folder_name); | 124 const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode(); |
| 125 bool import_to_top_level = bookmark_bar->child_count() == 0; |
| 75 | 126 |
| 76 bool show_bookmark_toolbar = false; | 127 // If the user currently has no bookmarks in the bookmark bar, make sure that |
| 77 std::set<const BookmarkNode*> folders_added_to; | 128 // at least some of the imported bookmarks end up there. Otherwise, we'll end |
| 129 // up with just a single folder containing the imported bookmarks, which makes |
| 130 // for unnecessary nesting. |
| 131 bool add_all_to_top_level = import_to_top_level; |
| 132 for (std::vector<BookmarkEntry>::const_iterator it = bookmarks.begin(); |
| 133 it != bookmarks.end() && add_all_to_top_level; ++it) { |
| 134 if (it->in_toolbar) |
| 135 add_all_to_top_level = false; |
| 136 } |
| 78 | 137 |
| 79 model->BeginImportMode(); | 138 model->BeginImportMode(); |
| 80 | 139 |
| 81 for (std::vector<BookmarkEntry>::const_iterator it = bookmarks.begin(); | 140 std::set<const BookmarkNode*> folders_added_to; |
| 82 it != bookmarks.end(); ++it) { | 141 const BookmarkNode* top_level_folder = NULL; |
| 83 // Don't insert this url if it isn't valid. | 142 for (std::vector<BookmarkEntry>::const_iterator bookmark = bookmarks.begin(); |
| 84 if (!it->is_folder && !it->url.is_valid()) | 143 bookmark != bookmarks.end(); ++bookmark) { |
| 144 // Disregard any bookmarks with invalid urls. |
| 145 if (!bookmark->is_folder && !bookmark->url.is_valid()) |
| 85 continue; | 146 continue; |
| 86 | 147 |
| 87 // We suppose that bookmarks are unique by Title, URL, and Folder. Since | 148 const BookmarkNode* parent = NULL; |
| 88 // checking for uniqueness may not be always the user's intention we have | 149 if (import_to_top_level && (add_all_to_top_level || bookmark->in_toolbar)) { |
| 89 // this as an option. | 150 // Add directly to the bookmarks bar. |
| 90 if (options & ADD_IF_UNIQUE && DoesBookmarkExist(model, *it, | 151 parent = bookmark_bar; |
| 91 real_first_folder, import_to_bookmark_bar)) | 152 } else { |
| 92 continue; | 153 // Add to a folder that will contain all the imported bookmarks not added |
| 154 // to the bar. The first time we do so, create the folder. |
| 155 if (!top_level_folder) { |
| 156 string16 name = GenerateUniqueFolderName(model, top_level_folder_name); |
| 157 top_level_folder = model->AddFolder(bookmark_bar, |
| 158 bookmark_bar->child_count(), |
| 159 name); |
| 160 } |
| 161 parent = top_level_folder; |
| 162 } |
| 93 | 163 |
| 94 // Set up folders in BookmarkModel in such a way that path[i] is | 164 // Ensure any enclosing folders are present in the model. The bookmark's |
| 95 // the subfolder of path[i-1]. Finally they construct a path in the | 165 // enclosing folder structure should be |
| 96 // model: | 166 // path[0] > path[1] > ... > path[size() - 1] |
| 97 // path[0] \ path[1] \ ... \ path[size() - 1] | 167 for (std::vector<string16>::const_iterator folder_name = |
| 98 const BookmarkNode* parent = | 168 bookmark->path.begin(); |
| 99 (it->in_toolbar ? model->GetBookmarkBarNode() : model->other_node()); | 169 folder_name != bookmark->path.end(); ++folder_name) { |
| 100 for (std::vector<string16>::const_iterator i = it->path.begin(); | 170 if (bookmark->in_toolbar && parent == bookmark_bar && |
| 101 i != it->path.end(); ++i) { | 171 folder_name == bookmark->path.begin()) { |
| 172 // If we're importing directly to the bookmarks bar, skip over the |
| 173 // folder named "Bookmarks Toolbar" (or any non-Firefox equivalent). |
| 174 continue; |
| 175 } |
| 176 |
| 102 const BookmarkNode* child = NULL; | 177 const BookmarkNode* child = NULL; |
| 103 const string16& folder_name = (!import_to_bookmark_bar && | |
| 104 !it->in_toolbar && (i == it->path.begin())) ? real_first_folder : *i; | |
| 105 | |
| 106 for (int index = 0; index < parent->child_count(); ++index) { | 178 for (int index = 0; index < parent->child_count(); ++index) { |
| 107 const BookmarkNode* node = parent->GetChild(index); | 179 const BookmarkNode* node = parent->GetChild(index); |
| 108 if (node->is_folder() && node->GetTitle() == folder_name) { | 180 if (node->is_folder() && node->GetTitle() == *folder_name) { |
| 109 child = node; | 181 child = node; |
| 110 break; | 182 break; |
| 111 } | 183 } |
| 112 } | 184 } |
| 113 if (!child) | 185 if (!child) |
| 114 child = model->AddFolder(parent, parent->child_count(), folder_name); | 186 child = model->AddFolder(parent, parent->child_count(), *folder_name); |
| 115 parent = child; | 187 parent = child; |
| 116 } | 188 } |
| 117 | 189 |
| 118 folders_added_to.insert(parent); | 190 folders_added_to.insert(parent); |
| 119 if (it->is_folder) { | 191 if (bookmark->is_folder) { |
| 120 model->AddFolder(parent, parent->child_count(), it->title); | 192 model->AddFolder(parent, parent->child_count(), bookmark->title); |
| 121 } else { | 193 } else { |
| 122 model->AddURLWithCreationTime(parent, parent->child_count(), | 194 model->AddURLWithCreationTime(parent, parent->child_count(), |
| 123 it->title, it->url, it->creation_time); | 195 bookmark->title, bookmark->url, |
| 196 bookmark->creation_time); |
| 124 } | 197 } |
| 125 | |
| 126 // If some items are put into toolbar, it looks like the user was using | |
| 127 // it in their last browser. We turn on the bookmarks toolbar. | |
| 128 if (it->in_toolbar) | |
| 129 show_bookmark_toolbar = true; | |
| 130 } | 198 } |
| 131 | 199 |
| 132 // In order to keep the imported-to folders from appearing in the 'recently | 200 // In order to keep the imported-to folders from appearing in the 'recently |
| 133 // added to' combobox, reset their modified times. | 201 // added to' combobox, reset their modified times. |
| 134 for (std::set<const BookmarkNode*>::const_iterator i = | 202 for (std::set<const BookmarkNode*>::const_iterator i = |
| 135 folders_added_to.begin(); | 203 folders_added_to.begin(); |
| 136 i != folders_added_to.end(); ++i) { | 204 i != folders_added_to.end(); ++i) { |
| 137 model->ResetDateFolderModified(*i); | 205 model->ResetDateFolderModified(*i); |
| 138 } | 206 } |
| 139 | 207 |
| 140 model->EndImportMode(); | 208 model->EndImportMode(); |
| 141 | 209 |
| 142 if (show_bookmark_toolbar && !(options & BOOKMARK_BAR_DISABLED)) | 210 // If the user was previously using a toolbar, we should show the bar. |
| 143 ShowBookmarkBar(); | 211 if (import_to_top_level && !add_all_to_top_level) |
| 212 ShowBookmarkBar(profile_); |
| 144 } | 213 } |
| 145 | 214 |
| 146 void ProfileWriter::AddFavicons( | 215 void ProfileWriter::AddFavicons( |
| 147 const std::vector<history::ImportedFaviconUsage>& favicons) { | 216 const std::vector<history::ImportedFaviconUsage>& favicons) { |
| 148 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS)-> | 217 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS)-> |
| 149 SetImportedFavicons(favicons); | 218 SetImportedFavicons(favicons); |
| 150 } | 219 } |
| 151 | 220 |
| 152 typedef std::map<std::string, const TemplateURL*> HostPathMap; | 221 typedef std::map<std::string, const TemplateURL*> HostPathMap; |
| 153 | 222 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 model->Add(t_url); | 327 model->Add(t_url); |
| 259 if (default_keyword && TemplateURL::SupportsReplacement(t_url)) | 328 if (default_keyword && TemplateURL::SupportsReplacement(t_url)) |
| 260 model->SetDefaultSearchProvider(t_url); | 329 model->SetDefaultSearchProvider(t_url); |
| 261 } else { | 330 } else { |
| 262 // Don't add invalid TemplateURLs to the model. | 331 // Don't add invalid TemplateURLs to the model. |
| 263 delete t_url; | 332 delete t_url; |
| 264 } | 333 } |
| 265 } | 334 } |
| 266 } | 335 } |
| 267 | 336 |
| 268 void ProfileWriter::ShowBookmarkBar() { | |
| 269 DCHECK(profile_); | |
| 270 | |
| 271 PrefService* prefs = profile_->GetPrefs(); | |
| 272 // Check whether the bookmark bar is shown in current pref. | |
| 273 if (!prefs->GetBoolean(prefs::kShowBookmarkBar)) { | |
| 274 // Set the pref and notify the notification service. | |
| 275 prefs->SetBoolean(prefs::kShowBookmarkBar, true); | |
| 276 prefs->ScheduleSavePersistentPrefs(); | |
| 277 Source<Profile> source(profile_); | |
| 278 NotificationService::current()->Notify( | |
| 279 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, source, | |
| 280 NotificationService::NoDetails()); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 ProfileWriter::~ProfileWriter() {} | 337 ProfileWriter::~ProfileWriter() {} |
| 285 | |
| 286 string16 ProfileWriter::GenerateUniqueFolderName( | |
| 287 BookmarkModel* model, | |
| 288 const string16& folder_name) { | |
| 289 // Build a set containing the folder names of the other folder. | |
| 290 std::set<string16> other_folder_names; | |
| 291 const BookmarkNode* other = model->other_node(); | |
| 292 | |
| 293 for (int i = 0, child_count = other->child_count(); i < child_count; ++i) { | |
| 294 const BookmarkNode* node = other->GetChild(i); | |
| 295 if (node->is_folder()) | |
| 296 other_folder_names.insert(node->GetTitle()); | |
| 297 } | |
| 298 | |
| 299 if (other_folder_names.find(folder_name) == other_folder_names.end()) | |
| 300 return folder_name; // Name is unique, use it. | |
| 301 | |
| 302 // Otherwise iterate until we find a unique name. | |
| 303 for (int i = 1; i < 100; ++i) { | |
| 304 string16 name = folder_name + UTF8ToUTF16(base::StringPrintf(" (%d)", i)); | |
| 305 if (other_folder_names.find(name) == other_folder_names.end()) | |
| 306 return name; | |
| 307 } | |
| 308 | |
| 309 return folder_name; | |
| 310 } | |
| 311 | |
| 312 bool ProfileWriter::DoesBookmarkExist( | |
| 313 BookmarkModel* model, | |
| 314 const BookmarkEntry& entry, | |
| 315 const string16& first_folder_name, | |
| 316 bool import_to_bookmark_bar) { | |
| 317 std::vector<const BookmarkNode*> nodes_with_same_url; | |
| 318 model->GetNodesByURL(entry.url, &nodes_with_same_url); | |
| 319 if (nodes_with_same_url.empty()) | |
| 320 return false; | |
| 321 | |
| 322 for (size_t i = 0; i < nodes_with_same_url.size(); ++i) { | |
| 323 const BookmarkNode* node = nodes_with_same_url[i]; | |
| 324 if (entry.title != node->GetTitle()) | |
| 325 continue; | |
| 326 | |
| 327 // Does the path match? | |
| 328 bool found_match = true; | |
| 329 const BookmarkNode* parent = node->parent(); | |
| 330 for (std::vector<string16>::const_reverse_iterator path_it = | |
| 331 entry.path.rbegin(); | |
| 332 (path_it != entry.path.rend()) && found_match; ++path_it) { | |
| 333 const string16& folder_name = | |
| 334 (!import_to_bookmark_bar && path_it + 1 == entry.path.rend()) ? | |
| 335 first_folder_name : *path_it; | |
| 336 if (NULL == parent || *path_it != folder_name) | |
| 337 found_match = false; | |
| 338 else | |
| 339 parent = parent->parent(); | |
| 340 } | |
| 341 | |
| 342 // We need a post test to differentiate checks such as | |
| 343 // /home/hello and /hello. The parent should either by the other folder | |
| 344 // node, or the bookmarks bar, depending upon import_to_bookmark_bar and | |
| 345 // entry.in_toolbar. | |
| 346 if (found_match && | |
| 347 ((import_to_bookmark_bar && entry.in_toolbar && parent != | |
| 348 model->GetBookmarkBarNode()) || | |
| 349 ((!import_to_bookmark_bar || !entry.in_toolbar) && | |
| 350 parent != model->other_node()))) { | |
| 351 found_match = false; | |
| 352 } | |
| 353 | |
| 354 if (found_match) | |
| 355 return true; // Found a match with the same url path and title. | |
| 356 } | |
| 357 return false; | |
| 358 } | |
| OLD | NEW |