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