chromium/ash/capture_mode/fake_folder_selection_dialog_factory.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/capture_mode/fake_folder_selection_dialog_factory.h"

#include <memory>

#include "base/check.h"
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/shell_dialogs/select_file_dialog.h"
#include "ui/shell_dialogs/select_file_policy.h"
#include "ui/shell_dialogs/selected_file_info.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"

namespace ash {

namespace {
FakeFolderSelectionDialogFactory* g_factory_instance = nullptr;
}  // namespace

// -----------------------------------------------------------------------------
// FakeFolderSelectionDialog:

class FakeFolderSelectionDialog : public ui::SelectFileDialog {
 public:
  FakeFolderSelectionDialog(Listener* listener,
                            std::unique_ptr<ui::SelectFilePolicy> policy)
      : ui::SelectFileDialog(listener, std::move(policy)) {}

  aura::Window* GetDialogWindow() {
    DCHECK(dialog_widget_);
    return dialog_widget_->GetNativeWindow();
  }

  void AcceptPath(const base::FilePath& path) {
    DCHECK(dialog_widget_);
    if (listener_) {
      listener_->FileSelected(ui::SelectedFileInfo(path), /*index=*/0);
    }
    DismissDialog();
  }

  void CancelDialog() {
    DCHECK(dialog_widget_);
    if (listener_) {
      listener_->FileSelectionCanceled();
    }
    DismissDialog();
  }

  // ui::BaseShellDialog:
  bool IsRunning(gfx::NativeWindow owning_window) const override {
    // The dialog is not shown modally.
    return false;
  }
  void ListenerDestroyed() override { listener_ = nullptr; }

 protected:
  ~FakeFolderSelectionDialog() override {
    if (g_factory_instance)
      g_factory_instance->OnDialogDeleted(this);
  }

  // ui::SelectFileDialog:
  void SelectFileImpl(Type type,
                      const std::u16string& title,
                      const base::FilePath& default_path,
                      const FileTypeInfo* file_types,
                      int file_type_index,
                      const base::FilePath::StringType& default_extension,
                      gfx::NativeWindow owning_window,
                      const GURL* caller) override {
    dialog_widget_ = views::UniqueWidgetPtr(std::make_unique<views::Widget>());
    views::Widget::InitParams widget_params(
        views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET,
        views::Widget::InitParams::TYPE_POPUP);
    widget_params.parent = owning_window;
    widget_params.bounds = owning_window->GetRootWindow()->bounds();
    widget_params.bounds.Inset(gfx::Insets(20));
    widget_params.name = "FakeFolderSelectionDialogWidget";
    dialog_widget_->Init(std::move(widget_params));
    dialog_widget_->Show();
  }

 private:
  void DismissDialog() {
    dialog_widget_->CloseNow();
    // |this| is deleted after the above call.
    DCHECK(!g_factory_instance || !(g_factory_instance->dialog_));
  }

  // ui::SelectFileDialog:
  bool HasMultipleFileTypeChoicesImpl() override { return false; }

  views::UniqueWidgetPtr dialog_widget_;
};

// -----------------------------------------------------------------------------
// FakeFolderSelectionDialogFactory:

// static
void FakeFolderSelectionDialogFactory::Start() {
  ui::SelectFileDialog::SetFactory(
      // Private constructor.
      base::WrapUnique(new FakeFolderSelectionDialogFactory()));
}

// static
void FakeFolderSelectionDialogFactory::Stop() {
  ui::SelectFileDialog::SetFactory(nullptr);
  DCHECK(!g_factory_instance);
}

// static
FakeFolderSelectionDialogFactory* FakeFolderSelectionDialogFactory::Get() {
  DCHECK(g_factory_instance);
  return g_factory_instance;
}

aura::Window* FakeFolderSelectionDialogFactory::GetDialogWindow() {
  DCHECK(dialog_);
  return dialog_->GetDialogWindow();
}

void FakeFolderSelectionDialogFactory::AcceptPath(const base::FilePath& path) {
  DCHECK(dialog_);
  dialog_->AcceptPath(path);
}

void FakeFolderSelectionDialogFactory::CancelDialog() {
  DCHECK(dialog_);
  dialog_->CancelDialog();
}

ui::SelectFileDialog* FakeFolderSelectionDialogFactory::Create(
    ui::SelectFileDialog::Listener* listener,
    std::unique_ptr<ui::SelectFilePolicy> policy) {
  dialog_ = new FakeFolderSelectionDialog(listener, std::move(policy));
  return dialog_;
}

FakeFolderSelectionDialogFactory::FakeFolderSelectionDialogFactory() {
  DCHECK(!g_factory_instance);
  g_factory_instance = this;
}

FakeFolderSelectionDialogFactory::~FakeFolderSelectionDialogFactory() {
  DCHECK_EQ(g_factory_instance, this);
  g_factory_instance = nullptr;
}

void FakeFolderSelectionDialogFactory::OnDialogDeleted(
    FakeFolderSelectionDialog* dialog) {
  DCHECK_EQ(dialog_, dialog);
  dialog_ = nullptr;
}

}  // namespace ash