15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/select_file_dialog_extension.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "apps/native_app_window.h"
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "apps/shell_window.h"
94311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch#include "apps/shell_window_registry.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_host.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_tab_helper.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_select_file_policy.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_dialog.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/base_window.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/selected_file_info.h"
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ui/views/widget/widget.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing apps::ShellWindow;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kFileManagerWidth = 972;  // pixels
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kFileManagerHeight = 640;  // pixels
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Holds references to file manager dialogs that have callbacks pending
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to their listeners.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PendingDialog {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static PendingDialog* GetInstance();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Add(int32 tab_id, scoped_refptr<SelectFileDialogExtension> dialog);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Remove(int32 tab_id);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> Find(int32 tab_id);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<PendingDialog>;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<int32, scoped_refptr<SelectFileDialogExtension> > Map;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Map map_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PendingDialog* PendingDialog::GetInstance() {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Singleton<PendingDialog>::get();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PendingDialog::Add(int32 tab_id,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         scoped_refptr<SelectFileDialogExtension> dialog) {
677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(dialog.get());
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (map_.find(tab_id) == map_.end())
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_.insert(std::make_pair(tab_id, dialog));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Duplicate pending dialog " << tab_id;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PendingDialog::Remove(int32 tab_id) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  map_.erase(tab_id);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<SelectFileDialogExtension> PendingDialog::Find(int32 tab_id) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Map::const_iterator it = map_.find(tab_id);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == map_.end())
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return it->second;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jamescook): Move this into a new file shell_dialogs_chromeos.cc
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectFileDialogExtension* SelectFileDialogExtension::Create(
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Listener* listener,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::SelectFilePolicy* policy) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new SelectFileDialogExtension(listener, policy);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectFileDialogExtension::SelectFileDialogExtension(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Listener* listener,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::SelectFilePolicy* policy)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : SelectFileDialog(listener, policy),
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_multiple_file_type_choices_(false),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_id_(0),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(NULL),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owner_window_(NULL),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selection_type_(CANCEL),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selection_index_(0),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_(NULL) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectFileDialogExtension::~SelectFileDialogExtension() {
1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (extension_dialog_.get())
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_dialog_->ObserverDestroyed();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SelectFileDialogExtension::IsRunning(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::NativeWindow owner_window) const {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return owner_window_ == owner_window;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::ListenerDestroyed() {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_ = NULL;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params_ = NULL;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PendingDialog::GetInstance()->Remove(tab_id_);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::ExtensionDialogClosing(
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExtensionDialog* /*dialog*/) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = NULL;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_window_ = NULL;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Release our reference to the underlying dialog to allow it to close.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_dialog_ = NULL;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PendingDialog::GetInstance()->Remove(tab_id_);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Actually invoke the appropriate callback on our listener.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyListener();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::ExtensionTerminated(
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionDialog* dialog) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The extension would have been unloaded because of the termination,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reload it.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string extension_id = dialog->host()->extension()->id();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reload the extension after a bit; the extension may not have been unloaded
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // yet. We don't want to try to reload the extension only to have the Unload
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code execute after us and re-unload the extension.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rkc): This is ugly. The ideal solution is that we shouldn't need to
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reload the extension at all - when we try to open the extension the next
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time, the extension subsystem would automatically reload it for us. At
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this time though this is broken because of some faulty wiring in
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExtensionProcessManager::CreateViewHost. Once that is fixed, remove this.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_) {
152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        FROM_HERE,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ExtensionService::ReloadExtension,
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                   base::Unretained(extensions::ExtensionSystem::Get(profile_)
156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                        ->extension_service()),
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                   extension_id));
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  dialog->GetWidget()->Close();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::OnFileSelected(
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 tab_id,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::SelectedFileInfo& file,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog =
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PendingDialog::GetInstance()->Find(tab_id);
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!dialog.get())
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_type_ = SINGLE_FILE;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_files_.clear();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_files_.push_back(file);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_index_ = index;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::OnMultiFilesSelected(
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 tab_id,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::SelectedFileInfo>& files) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog =
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PendingDialog::GetInstance()->Find(tab_id);
1847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!dialog.get())
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_type_ = MULTIPLE_FILES;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_files_ = files;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_index_ = 0;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::OnFileSelectionCanceled(int32 tab_id) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog =
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PendingDialog::GetInstance()->Find(tab_id);
1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!dialog.get())
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_type_ = CANCEL;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_files_.clear();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog->selection_index_ = 0;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)content::RenderViewHost* SelectFileDialogExtension::GetRenderViewHost() {
2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (extension_dialog_.get())
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return extension_dialog_->host()->render_view_host();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::NotifyListener() {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!listener_)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (selection_type_) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CANCEL:
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listener_->FileSelectionCanceled(params_);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SINGLE_FILE:
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listener_->FileSelectedWithExtraInfo(selection_files_[0],
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           selection_index_,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           params_);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case MULTIPLE_FILES:
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listener_->MultiFilesSelectedWithExtraInfo(selection_files_, params_);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::AddPending(int32 tab_id) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PendingDialog::GetInstance()->Add(tab_id, this);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SelectFileDialogExtension::PendingExists(int32 tab_id) {
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return PendingDialog::GetInstance()->Find(tab_id).get() != NULL;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SelectFileDialogExtension::HasMultipleFileTypeChoicesImpl() {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return has_multiple_file_type_choices_;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogExtension::SelectFileImpl(
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Type type,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& title,
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& default_path,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileTypeInfo* file_types,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int file_type_index,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath::StringType& default_extension,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::NativeWindow owner_window,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* params) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (owner_window_) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "File dialog already in use!";
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The base window to associate the dialog with.
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ui::BaseWindow* base_window = NULL;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The web contents to associate the dialog with.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WebContents* web_contents = NULL;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To get the base_window and profile, either a Browser or ShellWindow is
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // needed.
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Browser* owner_browser =  NULL;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ShellWindow* shell_window = NULL;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If owner_window is supplied, use that to find a browser or a shell window.
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (owner_window) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    owner_browser = chrome::FindBrowserWithWindow(owner_window);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!owner_browser) {
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If an owner_window was supplied but we couldn't find a browser, this
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // could be for a shell window.
2734311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      shell_window = apps::ShellWindowRegistry::
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetShellWindowForNativeWindowAnyProfile(owner_window);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (shell_window) {
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (shell_window->window_type_is_panel()) {
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NOTREACHED() << "File dialog opened by panel.";
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base_window = shell_window->GetBaseWindow();
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_contents = shell_window->web_contents();
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the owning window is still unknown, this could be a background page or
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // and extension popup. Use the last active browser.
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!owner_browser) {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      owner_browser =
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          chrome::FindLastActiveWithHostDesktopType(chrome::GetActiveDesktop());
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(owner_browser);
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!owner_browser) {
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Could not find browser or shell window for popup.";
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base_window = owner_browser->window();
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_contents = owner_browser->tab_strip_model()->GetActiveWebContents();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(base_window);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(web_contents);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile_);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if we have another dialog opened for the contents. It's unlikely, but
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // possible. If there is no web contents use a tab_id of -1. A dialog without
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an associated web contents will be shown full-screen; only one at a time
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is allowed in this state.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 tab_id = SessionID::IdForTab(web_contents);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (PendingExists(tab_id)) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Pending dialog exists with id " << tab_id;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath default_dialog_path;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PrefService* pref_service = profile_->GetPrefs();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (default_path.empty() && pref_service) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_dialog_path =
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pref_service->GetFilePath(prefs::kDownloadDefaultDirectory);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_dialog_path = default_path;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath virtual_path;
3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::FilePath fallback_path = profile_->last_selected_directory().Append(
3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      default_dialog_path.BaseName());
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If an absolute path is specified as the default path, convert it to the
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // virtual path in the file browser extension. Due to the current design,
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // an invalid temporal cache file path may passed as |default_dialog_path|
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // (crbug.com/178013 #9-#11). In such a case, we use the last selected
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // directory as a workaround. Real fix is tracked at crbug.com/110119.
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (default_dialog_path.IsAbsolute() &&
336a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      (file_manager::util::ConvertFileToRelativeFileSystemPath(
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           profile_, kFileBrowserDomain, default_dialog_path, &virtual_path) ||
338a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       file_manager::util::ConvertFileToRelativeFileSystemPath(
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           profile_, kFileBrowserDomain, fallback_path, &virtual_path))) {
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    virtual_path = base::FilePath("/").Append(virtual_path);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If the path was relative, or failed to convert, just use the base name,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    virtual_path = default_dialog_path.BaseName();
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  has_multiple_file_type_choices_ =
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_types ? file_types->extensions.size() > 1 : true;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
349a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  GURL file_browser_url = file_manager::util::GetFileBrowserUrlWithParams(
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type, title, virtual_path, file_types, file_type_index,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_extension);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionDialog* dialog = ExtensionDialog::Show(file_browser_url,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base_window, profile_, web_contents,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kFileManagerWidth, kFileManagerHeight,
356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kFileManagerWidth,
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kFileManagerHeight,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
359a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      file_manager::util::GetTitleFromType(type),
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // HTML-based header used.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string16(),
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this /* ExtensionDialog::Observer */);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dialog) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to create extension dialog";
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Connect our listener to FileDialogFunction's per-tab callbacks.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddPending(tab_id);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_dialog_ = dialog;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params_ = params;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_id_ = tab_id;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_window_ = owner_window;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
378