Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(479)

Side by Side Diff: chrome/browser/importer/profile_writer.cc

Issue 6979007: Many fixes to bookmark importing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Happy tests =) Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/importer/profile_writer.h ('k') | chrome/browser/importer/safari_importer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/importer/profile_writer.h ('k') | chrome/browser/importer/safari_importer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698