text: // 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 "ui/shell_dialogs/select_file_dialog.h"
  
  #include "base/bind.h"
  #include "base/logging.h"
  #include "base/message_loop/message_loop.h"
  #include "build/build_config.h"
  #include "ui/shell_dialogs/select_file_dialog_factory.h"
  #include "ui/shell_dialogs/select_file_policy.h"
  #include "ui/shell_dialogs/selected_file_info.h"
  #include "ui/shell_dialogs/shell_dialogs_delegate.h"
  
  #if defined(OS_WIN)
  #include "ui/shell_dialogs/select_file_dialog_win.h"
  #elif defined(OS_MACOSX)
  #include "ui/shell_dialogs/select_file_dialog_mac.h"
  #elif defined(OS_ANDROID)
  #include "ui/shell_dialogs/select_file_dialog_android.h"
  #elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
  #include "ui/shell_dialogs/linux_shell_dialog.h"
  #endif
  
  namespace {
  
  // Optional dialog factory. Leaked.
  ui::SelectFileDialogFactory* dialog_factory_ = NULL;
  
  // The global shell dialogs delegate.
  ui::ShellDialogsDelegate* g_shell_dialogs_delegate_ = NULL;
  
  }  // namespace
  
  namespace ui {
  
  SelectFileDialog::FileTypeInfo::FileTypeInfo()
      : include_all_files(false),
        support_drive(false) {}
  
  SelectFileDialog::FileTypeInfo::~FileTypeInfo() {}
  
  void SelectFileDialog::Listener::FileSelectedWithExtraInfo(
      const ui::SelectedFileInfo& file,
      int index,
      void* params) {
    // Most of the dialogs need actual local path, so default to it.
    // If local path is empty, use file_path instead.
    FileSelected(file.local_path.empty() ? file.file_path : file.local_path,
                 index,
                 params);
  }
  
  void SelectFileDialog::Listener::MultiFilesSelectedWithExtraInfo(
      const std::vector<ui::SelectedFileInfo>& files,
      void* params) {
    std::vector<base::FilePath> file_paths;
    for (size_t i = 0; i < files.size(); ++i)
      file_paths.push_back(files[i].local_path.empty() ? files[i].file_path
                                                       : files[i].local_path);
  
    MultiFilesSelected(file_paths, params);
  }
  
  // static
  void SelectFileDialog::SetFactory(ui::SelectFileDialogFactory* factory) {
    delete dialog_factory_;
    dialog_factory_ = factory;
  }
  
  // static
  scoped_refptr<SelectFileDialog> SelectFileDialog::Create(
      Listener* listener,
      ui::SelectFilePolicy* policy) {
    if (dialog_factory_) {
      SelectFileDialog* dialog = dialog_factory_->Create(listener, policy);
      if (dialog)
        return dialog;
    }
  
  #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
    const ui::LinuxShellDialog* shell_dialogs = ui::LinuxShellDialog::instance();
    if (shell_dialogs)
      return shell_dialogs->CreateSelectFileDialog(listener, policy);
  #endif
  
  #if defined(OS_WIN)
    // TODO(ananta)
    // Fix this for Chrome ASH on Windows.
    return CreateDefaultWinSelectFileDialog(listener, policy);
  #elif defined(OS_MACOSX) && !defined(USE_AURA)
    return CreateMacSelectFileDialog(listener, policy);
  #elif defined(OS_ANDROID)
    return CreateAndroidSelectFileDialog(listener, policy);
  #else
    NOTIMPLEMENTED();
    return NULL;
  #endif
  }
  
  void SelectFileDialog::SelectFile(
      Type type,
      const base::string16& title,
      const base::FilePath& default_path,
      const FileTypeInfo* file_types,
      int file_type_index,
      const base::FilePath::StringType& default_extension,
      gfx::NativeWindow owning_window,
      void* params) {
    DCHECK(listener_);
  
    if (select_file_policy_.get() &&
        !select_file_policy_->CanOpenSelectFileDialog()) {
      select_file_policy_->SelectFileDenied();
  
      // Inform the listener that no file was selected.
      // Post a task rather than calling FileSelectionCanceled directly to ensure
      // that the listener is called asynchronously.
      base::MessageLoop::current()->PostTask(
          FROM_HERE,
          base::Bind(&SelectFileDialog::CancelFileSelection, this, params));
      return;
    }
  
    // Call the platform specific implementation of the file selection dialog.
    SelectFileImpl(type, title, default_path, file_types, file_type_index,
                   default_extension, owning_window, params);
  }
  
  bool SelectFileDialog::HasMultipleFileTypeChoices() {
    return HasMultipleFileTypeChoicesImpl();
  }
  
  // static
  void SelectFileDialog::SetShellDialogsDelegate(ShellDialogsDelegate* delegate) {
    g_shell_dialogs_delegate_ = delegate;
  }
  
  SelectFileDialog::SelectFileDialog(Listener* listener,
                                     ui::SelectFilePolicy* policy)
      : listener_(listener),
        select_file_policy_(policy) {
    DCHECK(listener_);
  }
  
  SelectFileDialog::~SelectFileDialog() {}
  
  void SelectFileDialog::CancelFileSelection(void* params) {
    if (listener_)
      listener_->FileSelectionCanceled(params);
  }
  
  ShellDialogsDelegate* SelectFileDialog::GetShellDialogsDelegate() {
    return g_shell_dialogs_delegate_;
  }
  
  }  // namespace ui
  