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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/importer/importer_host.h" 6 7 #include "base/utf_string_conversions.h" 8 #include "chrome/browser/bookmarks/bookmark_model.h" 9 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/importer/firefox_profile_lock.h" 11 #include "chrome/browser/importer/importer.h" 12 #include "chrome/browser/importer/importer_lock_dialog.h" 13 #include "chrome/browser/importer/importer_progress_observer.h" 14 #include "chrome/browser/importer/importer_type.h" 15 #include "chrome/browser/importer/in_process_importer_bridge.h" 16 #include "chrome/browser/importer/toolbar_importer_utils.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/search_engines/template_url.h" 19 #include "chrome/browser/search_engines/template_url_model.h" 20 #include "chrome/browser/ui/browser_list.h" 21 #include "content/browser/browser_thread.h" 22 #include "content/common/notification_source.h" 23 #include "grit/generated_resources.h" 24 #include "ui/base/l10n/l10n_util.h" 25 26 #if defined(OS_WIN) 27 // TODO(port): Port this file. 28 #include "ui/base/message_box_win.h" 29 #endif 30 31 ImporterHost::ImporterHost() 32 : profile_(NULL), 33 task_(NULL), 34 importer_(NULL), 35 waiting_for_bookmarkbar_model_(false), 36 installed_bookmark_observer_(false), 37 is_source_readable_(true), 38 headless_(false), 39 parent_window_(NULL), 40 observer_(NULL) { 41 } 42 43 void ImporterHost::ShowWarningDialog() { 44 if (headless_) 45 OnImportLockDialogEnd(false); 46 else 47 importer::ShowImportLockDialog(parent_window_, this); 48 } 49 50 void ImporterHost::OnImportLockDialogEnd(bool is_continue) { 51 if (is_continue) { 52 // User chose to continue, then we check the lock again to make 53 // sure that Firefox has been closed. Try to import the settings 54 // if successful. Otherwise, show a warning dialog. 55 firefox_lock_->Lock(); 56 if (firefox_lock_->HasAcquired()) { 57 is_source_readable_ = true; 58 InvokeTaskIfDone(); 59 } else { 60 ShowWarningDialog(); 61 } 62 } else { 63 // User chose to skip the import process. We should delete 64 // the task and notify the ImporterHost to finish. 65 delete task_; 66 task_ = NULL; 67 importer_ = NULL; 68 NotifyImportEnded(); 69 } 70 } 71 72 void ImporterHost::SetObserver(importer::ImporterProgressObserver* observer) { 73 observer_ = observer; 74 } 75 76 void ImporterHost::NotifyImportStarted() { 77 if (observer_) 78 observer_->ImportStarted(); 79 } 80 81 void ImporterHost::NotifyImportItemStarted(importer::ImportItem item) { 82 if (observer_) 83 observer_->ImportItemStarted(item); 84 } 85 86 void ImporterHost::NotifyImportItemEnded(importer::ImportItem item) { 87 if (observer_) 88 observer_->ImportItemEnded(item); 89 } 90 91 void ImporterHost::NotifyImportEnded() { 92 firefox_lock_.reset(); // Release the Firefox profile lock. 93 if (observer_) 94 observer_->ImportEnded(); 95 Release(); 96 } 97 98 void ImporterHost::StartImportSettings( 99 const importer::SourceProfile& source_profile, 100 Profile* target_profile, 101 uint16 items, 102 ProfileWriter* writer, 103 bool first_run) { 104 // We really only support importing from one host at a time. 105 DCHECK(!profile_); 106 107 profile_ = target_profile; 108 // Preserves the observer and creates a task, since we do async import so that 109 // it doesn't block the UI. When the import is complete, observer will be 110 // notified. 111 writer_ = writer; 112 importer_ = importer::CreateImporterByType(source_profile.importer_type); 113 // If we fail to create the Importer, exit, as we cannot do anything. 114 if (!importer_) { 115 NotifyImportEnded(); 116 return; 117 } 118 119 importer_->AddRef(); 120 importer_->set_import_to_bookmark_bar(ShouldImportToBookmarkBar(first_run)); 121 importer_->set_bookmark_bar_disabled(first_run); 122 123 scoped_refptr<InProcessImporterBridge> bridge( 124 new InProcessImporterBridge(writer_.get(), this)); 125 task_ = NewRunnableMethod( 126 importer_, &Importer::StartImport, source_profile, items, bridge); 127 128 CheckForFirefoxLock(source_profile, items, first_run); 129 130 #if defined(OS_WIN) 131 // For google toolbar import, we need the user to log in and store their GAIA 132 // credentials. 133 if (source_profile.importer_type == importer::GOOGLE_TOOLBAR5) { 134 if (!toolbar_importer_utils::IsGoogleGAIACookieInstalled()) { 135 ui::MessageBox( 136 NULL, 137 UTF16ToWide(l10n_util::GetStringUTF16( 138 IDS_IMPORTER_GOOGLE_LOGIN_TEXT)).c_str(), 139 L"", 140 MB_OK | MB_TOPMOST); 141 142 GURL url("https://www.google.com/accounts/ServiceLogin"); 143 BrowserList::GetLastActive()->AddSelectedTabWithURL( 144 url, PageTransition::TYPED); 145 146 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 147 this, &ImporterHost::OnImportLockDialogEnd, false)); 148 149 is_source_readable_ = false; 150 } 151 } 152 #endif 153 154 CheckForLoadedModels(items); 155 AddRef(); 156 InvokeTaskIfDone(); 157 } 158 159 void ImporterHost::Cancel() { 160 if (importer_) 161 importer_->Cancel(); 162 } 163 164 ImporterHost::~ImporterHost() { 165 if (NULL != importer_) 166 importer_->Release(); 167 168 if (installed_bookmark_observer_) { 169 DCHECK(profile_); // Only way for waiting_for_bookmarkbar_model_ to be true 170 // is if we have a profile. 171 profile_->GetBookmarkModel()->RemoveObserver(this); 172 } 173 } 174 175 bool ImporterHost::ShouldImportToBookmarkBar(bool first_run) { 176 bool import_to_bookmark_bar = first_run; 177 if (profile_ && profile_->GetBookmarkModel()->IsLoaded()) { 178 import_to_bookmark_bar = (!profile_->GetBookmarkModel()->HasBookmarks()); 179 } 180 return import_to_bookmark_bar; 181 } 182 183 void ImporterHost::CheckForFirefoxLock( 184 const importer::SourceProfile& source_profile, 185 uint16 items, 186 bool first_run) { 187 if (source_profile.importer_type == importer::FIREFOX2 || 188 source_profile.importer_type == importer::FIREFOX3) { 189 DCHECK(!firefox_lock_.get()); 190 firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path)); 191 if (!firefox_lock_->HasAcquired()) { 192 // If fail to acquire the lock, we set the source unreadable and 193 // show a warning dialog, unless running without UI. 194 is_source_readable_ = false; 195 ShowWarningDialog(); 196 } 197 } 198 } 199 200 void ImporterHost::CheckForLoadedModels(uint16 items) { 201 // BookmarkModel should be loaded before adding IE favorites. So we observe 202 // the BookmarkModel if needed, and start the task after it has been loaded. 203 if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { 204 profile_->GetBookmarkModel()->AddObserver(this); 205 waiting_for_bookmarkbar_model_ = true; 206 installed_bookmark_observer_ = true; 207 } 208 209 // Observes the TemplateURLModel if needed to import search engines from the 210 // other browser. We also check to see if we're importing bookmarks because 211 // we can import bookmark keywords from Firefox as search engines. 212 if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { 213 if (!writer_->TemplateURLModelIsLoaded()) { 214 TemplateURLModel* model = profile_->GetTemplateURLModel(); 215 registrar_.Add(this, NotificationType::TEMPLATE_URL_MODEL_LOADED, 216 Source<TemplateURLModel>(model)); 217 model->Load(); 218 } 219 } 220 } 221 222 void ImporterHost::InvokeTaskIfDone() { 223 if (waiting_for_bookmarkbar_model_ || !registrar_.IsEmpty() || 224 !is_source_readable_) 225 return; 226 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, task_); 227 } 228 229 void ImporterHost::Loaded(BookmarkModel* model) { 230 DCHECK(model->IsLoaded()); 231 model->RemoveObserver(this); 232 waiting_for_bookmarkbar_model_ = false; 233 installed_bookmark_observer_ = false; 234 235 importer_->set_import_to_bookmark_bar(!model->HasBookmarks()); 236 InvokeTaskIfDone(); 237 } 238 239 void ImporterHost::BookmarkModelBeingDeleted(BookmarkModel* model) { 240 installed_bookmark_observer_ = false; 241 } 242 243 void ImporterHost::BookmarkModelChanged() { 244 } 245 246 void ImporterHost::Observe(NotificationType type, 247 const NotificationSource& source, 248 const NotificationDetails& details) { 249 DCHECK(type == NotificationType::TEMPLATE_URL_MODEL_LOADED); 250 registrar_.RemoveAll(); 251 InvokeTaskIfDone(); 252 } 253