// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/importer/external_process_importer_host.h" #include "base/bind.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/importer/external_process_importer_client.h" #include "chrome/browser/importer/firefox_profile_lock.h" #include "chrome/browser/importer/importer_lock_dialog.h" #include "chrome/browser/importer/importer_progress_observer.h" #include "chrome/browser/importer/in_process_importer_bridge.h" #include "chrome/browser/search_engines/template_url_service.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "content/public/browser/browser_thread.h" using content::BrowserThread; ExternalProcessImporterHost::ExternalProcessImporterHost() : headless_(false), parent_window_(NULL), observer_(NULL), profile_(NULL), waiting_for_bookmarkbar_model_(false), installed_bookmark_observer_(false), is_source_readable_(true), client_(NULL), items_(0), cancelled_(false), weak_ptr_factory_(this) { } void ExternalProcessImporterHost::Cancel() { cancelled_ = true; // There is only a |client_| if the import was started. if (client_) client_->Cancel(); NotifyImportEnded(); // Tells the observer that we're done, and deletes us. } void ExternalProcessImporterHost::StartImportSettings( const importer::SourceProfile& source_profile, Profile* target_profile, uint16 items, ProfileWriter* writer) { // We really only support importing from one host at a time. DCHECK(!profile_); DCHECK(target_profile); profile_ = target_profile; writer_ = writer; source_profile_ = source_profile; items_ = items; if (!CheckForFirefoxLock(source_profile)) { Cancel(); return; } CheckForLoadedModels(items); LaunchImportIfReady(); } void ExternalProcessImporterHost::NotifyImportStarted() { if (observer_) observer_->ImportStarted(); } void ExternalProcessImporterHost::NotifyImportItemStarted( importer::ImportItem item) { if (observer_) observer_->ImportItemStarted(item); } void ExternalProcessImporterHost::NotifyImportItemEnded( importer::ImportItem item) { if (observer_) observer_->ImportItemEnded(item); } void ExternalProcessImporterHost::NotifyImportEnded() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); firefox_lock_.reset(); if (observer_) observer_->ImportEnded(); delete this; } ExternalProcessImporterHost::~ExternalProcessImporterHost() { if (installed_bookmark_observer_) { DCHECK(profile_); BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); } } void ExternalProcessImporterHost::LaunchImportIfReady() { if (waiting_for_bookmarkbar_model_ || template_service_subscription_.get() || !is_source_readable_ || cancelled_) return; // This is the in-process half of the bridge, which catches data from the IPC // pipe and feeds it to the ProfileWriter. The external process half of the // bridge lives in the external process (see ProfileImportThread). // The ExternalProcessImporterClient created in the next line owns the bridge, // and will delete it. InProcessImporterBridge* bridge = new InProcessImporterBridge(writer_.get(), weak_ptr_factory_.GetWeakPtr()); client_ = new ExternalProcessImporterClient( weak_ptr_factory_.GetWeakPtr(), source_profile_, items_, bridge); client_->Start(); } void ExternalProcessImporterHost::BookmarkModelLoaded(BookmarkModel* model, bool ids_reassigned) { DCHECK(model->loaded()); model->RemoveObserver(this); waiting_for_bookmarkbar_model_ = false; installed_bookmark_observer_ = false; LaunchImportIfReady(); } void ExternalProcessImporterHost::BookmarkModelBeingDeleted( BookmarkModel* model) { installed_bookmark_observer_ = false; } void ExternalProcessImporterHost::BookmarkModelChanged() { } void ExternalProcessImporterHost::OnTemplateURLServiceLoaded() { template_service_subscription_.reset(); LaunchImportIfReady(); } void ExternalProcessImporterHost::ShowWarningDialog() { DCHECK(!headless_); importer::ShowImportLockDialog( parent_window_, base::Bind(&ExternalProcessImporterHost::OnImportLockDialogEnd, weak_ptr_factory_.GetWeakPtr())); } void ExternalProcessImporterHost::OnImportLockDialogEnd(bool is_continue) { if (is_continue) { // User chose to continue, then we check the lock again to make // sure that Firefox has been closed. Try to import the settings // if successful. Otherwise, show a warning dialog. firefox_lock_->Lock(); if (firefox_lock_->HasAcquired()) { is_source_readable_ = true; LaunchImportIfReady(); } else { ShowWarningDialog(); } } else { NotifyImportEnded(); } } bool ExternalProcessImporterHost::CheckForFirefoxLock( const importer::SourceProfile& source_profile) { if (source_profile.importer_type != importer::TYPE_FIREFOX) return true; DCHECK(!firefox_lock_.get()); firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path)); if (firefox_lock_->HasAcquired()) return true; // If fail to acquire the lock, we set the source unreadable and // show a warning dialog, unless running without UI (in which case the import // must be aborted). is_source_readable_ = false; if (headless_) return false; ShowWarningDialog(); return true; } void ExternalProcessImporterHost::CheckForLoadedModels(uint16 items) { // A target profile must be loaded by StartImportSettings(). DCHECK(profile_); // BookmarkModel should be loaded before adding IE favorites. So we observe // the BookmarkModel if needed, and start the task after it has been loaded. if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); waiting_for_bookmarkbar_model_ = true; installed_bookmark_observer_ = true; } // Observes the TemplateURLService if needed to import search engines from the // other browser. We also check to see if we're importing bookmarks because // we can import bookmark keywords from Firefox as search engines. if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { if (!writer_->TemplateURLServiceIsLoaded()) { TemplateURLService* model = TemplateURLServiceFactory::GetForProfile(profile_); template_service_subscription_ = model->RegisterOnLoadedCallback( base::Bind(&ExternalProcessImporterHost::OnTemplateURLServiceLoaded, weak_ptr_factory_.GetWeakPtr())); model->Load(); } } }