1// Copyright (c) 2012 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/external_process_importer_host.h" 6 7#include "base/bind.h" 8#include "chrome/browser/bookmarks/bookmark_model_factory.h" 9#include "chrome/browser/chrome_notification_types.h" 10#include "chrome/browser/importer/external_process_importer_client.h" 11#include "chrome/browser/importer/firefox_profile_lock.h" 12#include "chrome/browser/importer/importer_lock_dialog.h" 13#include "chrome/browser/importer/importer_progress_observer.h" 14#include "chrome/browser/importer/in_process_importer_bridge.h" 15#include "chrome/browser/search_engines/template_url_service_factory.h" 16#include "components/bookmarks/browser/bookmark_model.h" 17#include "components/search_engines/template_url_service.h" 18#include "content/public/browser/browser_thread.h" 19 20using content::BrowserThread; 21 22ExternalProcessImporterHost::ExternalProcessImporterHost() 23 : headless_(false), 24 parent_window_(NULL), 25 observer_(NULL), 26 profile_(NULL), 27 waiting_for_bookmarkbar_model_(false), 28 installed_bookmark_observer_(false), 29 is_source_readable_(true), 30 client_(NULL), 31 items_(0), 32 cancelled_(false), 33 weak_ptr_factory_(this) { 34} 35 36void ExternalProcessImporterHost::Cancel() { 37 cancelled_ = true; 38 // There is only a |client_| if the import was started. 39 if (client_) 40 client_->Cancel(); 41 NotifyImportEnded(); // Tells the observer that we're done, and deletes us. 42} 43 44void ExternalProcessImporterHost::StartImportSettings( 45 const importer::SourceProfile& source_profile, 46 Profile* target_profile, 47 uint16 items, 48 ProfileWriter* writer) { 49 // We really only support importing from one host at a time. 50 DCHECK(!profile_); 51 DCHECK(target_profile); 52 53 profile_ = target_profile; 54 writer_ = writer; 55 source_profile_ = source_profile; 56 items_ = items; 57 58 if (!CheckForFirefoxLock(source_profile)) { 59 Cancel(); 60 return; 61 } 62 63 CheckForLoadedModels(items); 64 65 LaunchImportIfReady(); 66} 67 68void ExternalProcessImporterHost::NotifyImportStarted() { 69 if (observer_) 70 observer_->ImportStarted(); 71} 72 73void ExternalProcessImporterHost::NotifyImportItemStarted( 74 importer::ImportItem item) { 75 if (observer_) 76 observer_->ImportItemStarted(item); 77} 78 79void ExternalProcessImporterHost::NotifyImportItemEnded( 80 importer::ImportItem item) { 81 if (observer_) 82 observer_->ImportItemEnded(item); 83} 84 85void ExternalProcessImporterHost::NotifyImportEnded() { 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 87 firefox_lock_.reset(); 88 if (observer_) 89 observer_->ImportEnded(); 90 delete this; 91} 92 93ExternalProcessImporterHost::~ExternalProcessImporterHost() { 94 if (installed_bookmark_observer_) { 95 DCHECK(profile_); 96 BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); 97 } 98} 99 100void ExternalProcessImporterHost::LaunchImportIfReady() { 101 if (waiting_for_bookmarkbar_model_ || template_service_subscription_.get() || 102 !is_source_readable_ || cancelled_) 103 return; 104 105 // This is the in-process half of the bridge, which catches data from the IPC 106 // pipe and feeds it to the ProfileWriter. The external process half of the 107 // bridge lives in the external process (see ProfileImportThread). 108 // The ExternalProcessImporterClient created in the next line owns the bridge, 109 // and will delete it. 110 InProcessImporterBridge* bridge = 111 new InProcessImporterBridge(writer_.get(), 112 weak_ptr_factory_.GetWeakPtr()); 113 client_ = new ExternalProcessImporterClient( 114 weak_ptr_factory_.GetWeakPtr(), source_profile_, items_, bridge); 115 client_->Start(); 116} 117 118void ExternalProcessImporterHost::BookmarkModelLoaded(BookmarkModel* model, 119 bool ids_reassigned) { 120 DCHECK(model->loaded()); 121 model->RemoveObserver(this); 122 waiting_for_bookmarkbar_model_ = false; 123 installed_bookmark_observer_ = false; 124 125 LaunchImportIfReady(); 126} 127 128void ExternalProcessImporterHost::BookmarkModelBeingDeleted( 129 BookmarkModel* model) { 130 installed_bookmark_observer_ = false; 131} 132 133void ExternalProcessImporterHost::BookmarkModelChanged() { 134} 135 136void ExternalProcessImporterHost::OnTemplateURLServiceLoaded() { 137 template_service_subscription_.reset(); 138 LaunchImportIfReady(); 139} 140 141void ExternalProcessImporterHost::ShowWarningDialog() { 142 DCHECK(!headless_); 143 importer::ShowImportLockDialog( 144 parent_window_, 145 base::Bind(&ExternalProcessImporterHost::OnImportLockDialogEnd, 146 weak_ptr_factory_.GetWeakPtr())); 147} 148 149void ExternalProcessImporterHost::OnImportLockDialogEnd(bool is_continue) { 150 if (is_continue) { 151 // User chose to continue, then we check the lock again to make 152 // sure that Firefox has been closed. Try to import the settings 153 // if successful. Otherwise, show a warning dialog. 154 firefox_lock_->Lock(); 155 if (firefox_lock_->HasAcquired()) { 156 is_source_readable_ = true; 157 LaunchImportIfReady(); 158 } else { 159 ShowWarningDialog(); 160 } 161 } else { 162 NotifyImportEnded(); 163 } 164} 165 166bool ExternalProcessImporterHost::CheckForFirefoxLock( 167 const importer::SourceProfile& source_profile) { 168 if (source_profile.importer_type != importer::TYPE_FIREFOX) 169 return true; 170 171 DCHECK(!firefox_lock_.get()); 172 firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path)); 173 if (firefox_lock_->HasAcquired()) 174 return true; 175 176 // If fail to acquire the lock, we set the source unreadable and 177 // show a warning dialog, unless running without UI (in which case the import 178 // must be aborted). 179 is_source_readable_ = false; 180 if (headless_) 181 return false; 182 183 ShowWarningDialog(); 184 return true; 185} 186 187void ExternalProcessImporterHost::CheckForLoadedModels(uint16 items) { 188 // A target profile must be loaded by StartImportSettings(). 189 DCHECK(profile_); 190 191 // BookmarkModel should be loaded before adding IE favorites. So we observe 192 // the BookmarkModel if needed, and start the task after it has been loaded. 193 if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { 194 BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); 195 waiting_for_bookmarkbar_model_ = true; 196 installed_bookmark_observer_ = true; 197 } 198 199 // Observes the TemplateURLService if needed to import search engines from the 200 // other browser. We also check to see if we're importing bookmarks because 201 // we can import bookmark keywords from Firefox as search engines. 202 if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { 203 if (!writer_->TemplateURLServiceIsLoaded()) { 204 TemplateURLService* model = 205 TemplateURLServiceFactory::GetForProfile(profile_); 206 template_service_subscription_ = model->RegisterOnLoadedCallback( 207 base::Bind(&ExternalProcessImporterHost::OnTemplateURLServiceLoaded, 208 weak_ptr_factory_.GetWeakPtr())); 209 model->Load(); 210 } 211 } 212} 213