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

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

Issue 3035: Move importer files into an importer subdirectory. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 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.h ('k') | chrome/browser/importer/firefox2_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
(Empty)
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/importer.h"
6
7 #include <map>
8
9 #include "base/file_util.h"
10 #include "base/gfx/image_operations.h"
11 #include "base/gfx/png_encoder.h"
12 #include "base/string_util.h"
13 #include "chrome/browser/bookmarks/bookmark_model.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/firefox2_importer.h"
16 #include "chrome/browser/firefox3_importer.h"
17 #include "chrome/browser/firefox_importer_utils.h"
18 #include "chrome/browser/firefox_profile_lock.h"
19 #include "chrome/browser/ie_importer.h"
20 #include "chrome/browser/template_url_model.h"
21 #include "chrome/browser/shell_integration.h"
22 #include "chrome/browser/webdata/web_data_service.h"
23 #include "chrome/common/gfx/favicon_size.h"
24 #include "chrome/common/l10n_util.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/pref_service.h"
27 #include "chrome/views/window.h"
28 #include "webkit/glue/image_decoder.h"
29
30 #include "generated_resources.h"
31
32 // ProfileWriter.
33
34 bool ProfileWriter::BookmarkModelIsLoaded() const {
35 return profile_->GetBookmarkModel()->IsLoaded();
36 }
37
38 void ProfileWriter::AddBookmarkModelObserver(BookmarkModelObserver* observer) {
39 profile_->GetBookmarkModel()->AddObserver(observer);
40 }
41
42 bool ProfileWriter::TemplateURLModelIsLoaded() const {
43 return profile_->GetTemplateURLModel()->loaded();
44 }
45
46 void ProfileWriter::AddTemplateURLModelObserver(
47 NotificationObserver* observer) {
48 TemplateURLModel* model = profile_->GetTemplateURLModel();
49 NotificationService::current()->AddObserver(
50 observer, TEMPLATE_URL_MODEL_LOADED,
51 Source<TemplateURLModel>(model));
52 model->Load();
53 }
54
55 void ProfileWriter::AddPasswordForm(const PasswordForm& form) {
56 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->AddLogin(form);
57 }
58
59 void ProfileWriter::AddIE7PasswordInfo(const IE7PasswordInfo& info) {
60 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->AddIE7Login(info);
61 }
62
63 void ProfileWriter::AddHistoryPage(const std::vector<history::URLRow>& page) {
64 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->
65 AddPagesWithDetails(page);
66 }
67
68 void ProfileWriter::AddHomepage(const GURL& home_page) {
69 DCHECK(profile_);
70
71 PrefService* prefs = profile_->GetPrefs();
72 // NOTE: We set the kHomePage value, but keep the NewTab page as the homepage.
73 prefs->SetString(prefs::kHomePage, ASCIIToWide(home_page.spec()));
74 prefs->ScheduleSavePersistentPrefs(g_browser_process->file_thread());
75 }
76
77 void ProfileWriter::AddBookmarkEntry(
78 const std::vector<BookmarkEntry>& bookmark) {
79 BookmarkModel* model = profile_->GetBookmarkModel();
80 DCHECK(model->IsLoaded());
81
82 bool show_bookmark_toolbar = false;
83 std::set<BookmarkNode*> groups_added_to;
84 for (std::vector<BookmarkEntry>::const_iterator it = bookmark.begin();
85 it != bookmark.end(); ++it) {
86 // Don't insert this url if it exists in model or url is not valid.
87 if (model->GetNodeByURL(it->url) != NULL || !it->url.is_valid())
88 continue;
89
90 // Set up groups in BookmarkModel in such a way that path[i] is
91 // the subgroup of path[i-1]. Finally they construct a path in the
92 // model:
93 // path[0] \ path[1] \ ... \ path[size() - 1]
94 BookmarkNode* parent =
95 (it->in_toolbar ? model->GetBookmarkBarNode() : model->other_node());
96 for (std::vector<std::wstring>::const_iterator i = it->path.begin();
97 i != it->path.end(); ++i) {
98 BookmarkNode* child = NULL;
99 for (int index = 0; index < parent->GetChildCount(); ++index) {
100 BookmarkNode* node = parent->GetChild(index);
101 if ((node->GetType() == history::StarredEntry::BOOKMARK_BAR ||
102 node->GetType() == history::StarredEntry::USER_GROUP) &&
103 node->GetTitle() == *i) {
104 child = node;
105 break;
106 }
107 }
108 if (child == NULL)
109 child = model->AddGroup(parent, parent->GetChildCount(), *i);
110 parent = child;
111 }
112 groups_added_to.insert(parent);
113 model->AddURLWithCreationTime(parent, parent->GetChildCount(),
114 it->title, it->url, it->creation_time);
115
116 // If some items are put into toolbar, it looks like the user was using
117 // it in their last browser. We turn on the bookmarks toolbar.
118 if (it->in_toolbar)
119 show_bookmark_toolbar = true;
120 }
121
122 // Reset the date modified time of the groups we added to. We do this to
123 // make sure the 'recently added to' combobox in the bubble doesn't get random
124 // groups.
125 for (std::set<BookmarkNode*>::const_iterator i = groups_added_to.begin();
126 i != groups_added_to.end(); ++i) {
127 model->ResetDateGroupModified(*i);
128 }
129
130 if (show_bookmark_toolbar)
131 ShowBookmarkBar();
132 }
133
134 void ProfileWriter::AddFavicons(
135 const std::vector<history::ImportedFavIconUsage>& favicons) {
136 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->
137 SetImportedFavicons(favicons);
138 }
139
140 typedef std::map<std::string, const TemplateURL*> HostPathMap;
141
142 // Builds the key to use in HostPathMap for the specified TemplateURL. Returns
143 // an empty string if a host+path can't be generated for the TemplateURL.
144 // If an empty string is returned, it should not be added to HostPathMap.
145 static std::string BuildHostPathKey(const TemplateURL* t_url) {
146 if (t_url->url() && t_url->url()->SupportsReplacement()) {
147 GURL search_url(t_url->url()->ReplaceSearchTerms(
148 *t_url, L"random string", TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
149 std::wstring()));
150 if (search_url.is_valid())
151 return search_url.host() + search_url.path();
152 }
153 return std::string();
154 }
155
156 // Builds a set that contains an entry of the host+path for each TemplateURL in
157 // the TemplateURLModel that has a valid search url.
158 static void BuildHostPathMap(const TemplateURLModel& model,
159 HostPathMap* host_path_map) {
160 std::vector<const TemplateURL*> template_urls = model.GetTemplateURLs();
161 for (size_t i = 0; i < template_urls.size(); ++i) {
162 const std::string host_path = BuildHostPathKey(template_urls[i]);
163 if (!host_path.empty()) {
164 const TemplateURL* existing_turl = (*host_path_map)[host_path];
165 if (!existing_turl ||
166 (template_urls[i]->show_in_default_list() &&
167 !existing_turl->show_in_default_list())) {
168 // If there are multiple TemplateURLs with the same host+path, favor
169 // those shown in the default list. If there are multiple potential
170 // defaults, favor the first one, which should be the more commonly used
171 // one.
172 (*host_path_map)[host_path] = template_urls[i];
173 }
174 } // else case, TemplateURL doesn't have a search url, doesn't support
175 // replacement, or doesn't have valid GURL. Ignore it.
176 }
177 }
178
179 void ProfileWriter::AddKeywords(const std::vector<TemplateURL*>& template_urls,
180 int default_keyword_index,
181 bool unique_on_host_and_path) {
182 TemplateURLModel* model = profile_->GetTemplateURLModel();
183 HostPathMap host_path_map;
184 if (unique_on_host_and_path)
185 BuildHostPathMap(*model, &host_path_map);
186
187 for (std::vector<TemplateURL*>::const_iterator i = template_urls.begin();
188 i != template_urls.end(); ++i) {
189 TemplateURL* t_url = *i;
190 bool default_keyword =
191 default_keyword_index >= 0 &&
192 (i - template_urls.begin() == default_keyword_index);
193
194 // TemplateURLModel requires keywords to be unique. If there is already a
195 // TemplateURL with this keyword, don't import it again.
196 const TemplateURL* turl_with_keyword =
197 model->GetTemplateURLForKeyword(t_url->keyword());
198 if (turl_with_keyword != NULL) {
199 if (default_keyword)
200 model->SetDefaultSearchProvider(turl_with_keyword);
201 delete t_url;
202 continue;
203 }
204
205 // For search engines if there is already a keyword with the same
206 // host+path, we don't import it. This is done to avoid both duplicate
207 // search providers (such as two Googles, or two Yahoos) as well as making
208 // sure the search engines we provide aren't replaced by those from the
209 // imported browser.
210 if (unique_on_host_and_path &&
211 host_path_map.find(BuildHostPathKey(t_url)) != host_path_map.end()) {
212 if (default_keyword) {
213 const TemplateURL* turl_with_host_path =
214 host_path_map[BuildHostPathKey(t_url)];
215 if (turl_with_host_path)
216 model->SetDefaultSearchProvider(turl_with_host_path);
217 else
218 NOTREACHED(); // BuildHostPathMap should only insert non-null values.
219 }
220 delete t_url;
221 continue;
222 }
223 model->Add(t_url);
224 if (default_keyword)
225 model->SetDefaultSearchProvider(t_url);
226 }
227 }
228
229 void ProfileWriter::ShowBookmarkBar() {
230 DCHECK(profile_);
231
232 PrefService* prefs = profile_->GetPrefs();
233 // Check whether the bookmark bar is shown in current pref.
234 if (!prefs->GetBoolean(prefs::kShowBookmarkBar)) {
235 // Set the pref and notify the notification service.
236 prefs->SetBoolean(prefs::kShowBookmarkBar, true);
237 prefs->ScheduleSavePersistentPrefs(g_browser_process->file_thread());
238 Source<Profile> source(profile_);
239 NotificationService::current()->Notify(
240 NOTIFY_BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, source,
241 NotificationService::NoDetails());
242 }
243 }
244
245 // Importer.
246
247 // static
248 bool Importer::ReencodeFavicon(const unsigned char* src_data, size_t src_len,
249 std::vector<unsigned char>* png_data) {
250 // Decode the favicon using WebKit's image decoder.
251 webkit_glue::ImageDecoder decoder(gfx::Size(kFavIconSize, kFavIconSize));
252 SkBitmap decoded = decoder.Decode(src_data, src_len);
253 if (decoded.empty())
254 return false; // Unable to decode.
255
256 if (decoded.width() != kFavIconSize || decoded.height() != kFavIconSize) {
257 // The bitmap is not the correct size, re-sample.
258 int new_width = decoded.width();
259 int new_height = decoded.height();
260 calc_favicon_target_size(&new_width, &new_height);
261 decoded = gfx::ImageOperations::Resize(
262 decoded, gfx::ImageOperations::RESIZE_LANCZOS3,
263 gfx::Size(new_width, new_height));
264 }
265
266 // Encode our bitmap as a PNG.
267 SkAutoLockPixels decoded_lock(decoded);
268 PNGEncoder::Encode(reinterpret_cast<unsigned char*>(decoded.getPixels()),
269 PNGEncoder::FORMAT_BGRA, decoded.width(),
270 decoded.height(), decoded.width() * 4, false, png_data);
271 return true;
272 }
273
274 // ImporterHost.
275
276 ImporterHost::ImporterHost()
277 : observer_(NULL),
278 task_(NULL),
279 importer_(NULL),
280 file_loop_(g_browser_process->file_thread()->message_loop()),
281 waiting_for_bookmarkbar_model_(false),
282 waiting_for_template_url_model_(false),
283 is_source_readable_(true) {
284 DetectSourceProfiles();
285 }
286
287 ImporterHost::ImporterHost(MessageLoop* file_loop)
288 : observer_(NULL),
289 task_(NULL),
290 importer_(NULL),
291 file_loop_(file_loop),
292 waiting_for_bookmarkbar_model_(false),
293 waiting_for_template_url_model_(false),
294 is_source_readable_(true) {
295 DetectSourceProfiles();
296 }
297
298 ImporterHost::~ImporterHost() {
299 STLDeleteContainerPointers(source_profiles_.begin(), source_profiles_.end());
300 }
301
302 void ImporterHost::Loaded(BookmarkModel* model) {
303 model->RemoveObserver(this);
304 waiting_for_bookmarkbar_model_ = false;
305 InvokeTaskIfDone();
306 }
307
308 void ImporterHost::Observe(NotificationType type,
309 const NotificationSource& source,
310 const NotificationDetails& details) {
311 DCHECK(type == TEMPLATE_URL_MODEL_LOADED);
312 TemplateURLModel* model = Source<TemplateURLModel>(source).ptr();
313 NotificationService::current()->RemoveObserver(
314 this, TEMPLATE_URL_MODEL_LOADED,
315 Source<TemplateURLModel>(model));
316 waiting_for_template_url_model_ = false;
317 InvokeTaskIfDone();
318 }
319
320 void ImporterHost::ShowWarningDialog() {
321 ChromeViews::Window::CreateChromeWindow(GetActiveWindow(), gfx::Rect(),
322 new ImporterLockView(this))->Show();
323 }
324
325 void ImporterHost::OnLockViewEnd(bool is_continue) {
326 if (is_continue) {
327 // User chose to continue, then we check the lock again to make
328 // sure that Firefox has been closed. Try to import the settings
329 // if successful. Otherwise, show a warning dialog.
330 firefox_lock_->Lock();
331 if (firefox_lock_->HasAcquired()) {
332 is_source_readable_ = true;
333 InvokeTaskIfDone();
334 } else {
335 ShowWarningDialog();
336 }
337 } else {
338 // User chose to skip the import process. We should delete
339 // the task and notify the ImporterHost to finish.
340 delete task_;
341 task_ = NULL;
342 importer_ = NULL;
343 ImportEnded();
344 }
345 }
346
347 void ImporterHost::StartImportSettings(const ProfileInfo& profile_info,
348 uint16 items,
349 ProfileWriter* writer,
350 bool first_run) {
351 // Preserves the observer and creates a task, since we do async import
352 // so that it doesn't block the UI. When the import is complete, observer
353 // will be notified.
354 writer_ = writer;
355 importer_ = CreateImporterByType(profile_info.browser_type);
356 importer_->set_first_run(first_run);
357 task_ = NewRunnableMethod(importer_, &Importer::StartImport,
358 profile_info, items, writer_.get(), this);
359
360 // We should lock the Firefox profile directory to prevent corruption.
361 if (profile_info.browser_type == FIREFOX2 ||
362 profile_info.browser_type == FIREFOX3) {
363 firefox_lock_.reset(new FirefoxProfileLock(profile_info.source_path));
364 if (!firefox_lock_->HasAcquired()) {
365 // If fail to acquire the lock, we set the source unreadable and
366 // show a warning dialog.
367 is_source_readable_ = false;
368 ShowWarningDialog();
369 }
370 }
371
372 // BookmarkModel should be loaded before adding IE favorites. So we observe
373 // the BookmarkModel if needed, and start the task after it has been loaded.
374 if ((items & FAVORITES) && !writer_->BookmarkModelIsLoaded()) {
375 writer_->AddBookmarkModelObserver(this);
376 waiting_for_bookmarkbar_model_ = true;
377 }
378
379 // Observes the TemplateURLModel if needed to import search engines from the
380 // other browser. We also check to see if we're importing bookmarks because
381 // we can import bookmark keywords from Firefox as search engines.
382 if ((items & SEARCH_ENGINES) || (items & FAVORITES)) {
383 if (!writer_->TemplateURLModelIsLoaded()) {
384 writer_->AddTemplateURLModelObserver(this);
385 waiting_for_template_url_model_ = true;
386 }
387 }
388
389 AddRef();
390 InvokeTaskIfDone();
391 }
392
393 void ImporterHost::Cancel() {
394 if (importer_)
395 importer_->Cancel();
396 }
397
398 void ImporterHost::SetObserver(Observer* observer) {
399 observer_ = observer;
400 }
401
402 void ImporterHost::InvokeTaskIfDone() {
403 if (waiting_for_bookmarkbar_model_ || waiting_for_template_url_model_ ||
404 !is_source_readable_)
405 return;
406 file_loop_->PostTask(FROM_HERE, task_);
407 }
408
409 void ImporterHost::ImportItemStarted(ImportItem item) {
410 if (observer_)
411 observer_->ImportItemStarted(item);
412 }
413
414 void ImporterHost::ImportItemEnded(ImportItem item) {
415 if (observer_)
416 observer_->ImportItemEnded(item);
417 }
418
419 void ImporterHost::ImportStarted() {
420 if (observer_)
421 observer_->ImportStarted();
422 }
423
424 void ImporterHost::ImportEnded() {
425 firefox_lock_.reset(); // Release the Firefox profile lock.
426 if (observer_)
427 observer_->ImportEnded();
428 Release();
429 }
430
431 Importer* ImporterHost::CreateImporterByType(ProfileType type) {
432 switch (type) {
433 case MS_IE:
434 return new IEImporter();
435 case FIREFOX2:
436 return new Firefox2Importer();
437 case FIREFOX3:
438 return new Firefox3Importer();
439 }
440 NOTREACHED();
441 return NULL;
442 }
443
444 int ImporterHost::GetAvailableProfileCount() {
445 return static_cast<int>(source_profiles_.size());
446 }
447
448 std::wstring ImporterHost::GetSourceProfileNameAt(int index) const {
449 DCHECK(index < static_cast<int>(source_profiles_.size()));
450 return source_profiles_[index]->description;
451 }
452
453 const ProfileInfo& ImporterHost::GetSourceProfileInfoAt(int index) const {
454 DCHECK(index < static_cast<int>(source_profiles_.size()));
455 return *source_profiles_[index];
456 }
457
458 void ImporterHost::DetectSourceProfiles() {
459 if (ShellIntegration::IsFirefoxDefaultBrowser()) {
460 DetectFirefoxProfiles();
461 DetectIEProfiles();
462 } else {
463 DetectIEProfiles();
464 DetectFirefoxProfiles();
465 }
466 }
467
468 void ImporterHost::DetectIEProfiles() {
469 // IE always exists and don't have multiple profiles.
470 ProfileInfo* ie = new ProfileInfo();
471 ie->description = l10n_util::GetString(IDS_IMPORT_FROM_IE);
472 ie->browser_type = MS_IE;
473 ie->source_path.clear();
474 ie->app_path.clear();
475 source_profiles_.push_back(ie);
476 }
477
478 void ImporterHost::DetectFirefoxProfiles() {
479 // Detects which version of Firefox is installed.
480 int version = GetCurrentFirefoxMajorVersion();
481 ProfileType firefox_type;
482 if (version == 2) {
483 firefox_type = FIREFOX2;
484 } else if (version == 3) {
485 firefox_type = FIREFOX3;
486 } else {
487 // Ignores other versions of firefox.
488 return;
489 }
490
491 std::wstring ini_file = GetProfilesINI();
492 DictionaryValue root;
493 ParseProfileINI(ini_file, &root);
494
495 std::wstring source_path;
496 for (int i = 0; ; ++i) {
497 std::wstring current_profile = L"Profile" + IntToWString(i);
498 if (!root.HasKey(current_profile)) {
499 // Profiles are continuously numbered. So we exit when we can't
500 // find the i-th one.
501 break;
502 }
503 std::wstring is_relative, path, profile_path;
504 if (root.GetString(current_profile + L".IsRelative", &is_relative) &&
505 root.GetString(current_profile + L".Path", &path)) {
506 ReplaceSubstringsAfterOffset(&path, 0, L"/", L"\\");
507
508 // IsRelative=1 means the folder path would be relative to the
509 // path of profiles.ini. IsRelative=0 refers to a custom profile
510 // location.
511 if (is_relative == L"1") {
512 profile_path = file_util::GetDirectoryFromPath(ini_file);
513 file_util::AppendToPath(&profile_path, path);
514 } else {
515 profile_path = path;
516 }
517
518 // We only import the default profile when multiple profiles exist,
519 // since the other profiles are used mostly by developers for testing.
520 // Otherwise, Profile0 will be imported.
521 std::wstring is_default;
522 if ((root.GetString(current_profile + L".Default", &is_default) &&
523 is_default == L"1") || i == 0) {
524 source_path = profile_path;
525 // We break out of the loop when we have found the default profile.
526 if (is_default == L"1")
527 break;
528 }
529 }
530 }
531
532 if (!source_path.empty()) {
533 ProfileInfo* firefox = new ProfileInfo();
534 firefox->description = l10n_util::GetString(IDS_IMPORT_FROM_FIREFOX);
535 firefox->browser_type = firefox_type;
536 firefox->source_path = source_path;
537 firefox->app_path = GetFirefoxInstallPath();
538 source_profiles_.push_back(firefox);
539 }
540 }
541
OLDNEW
« no previous file with comments | « chrome/browser/importer.h ('k') | chrome/browser/importer/firefox2_importer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698