folder_selection_dialog_controller.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2021 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. #include "ash/capture_mode/folder_selection_dialog_controller.h"
  5. #include <memory>
  6. #include "ash/keyboard/ui/keyboard_ui_controller.h"
  7. #include "ash/public/cpp/shell_window_ids.h"
  8. #include "ash/strings/grit/ash_strings.h"
  9. #include "ash/style/ash_color_id.h"
  10. #include "ash/style/ash_color_provider.h"
  11. #include "base/files/file_path.h"
  12. #include "ui/aura/client/aura_constants.h"
  13. #include "ui/aura/window_observer.h"
  14. #include "ui/base/l10n/l10n_util.h"
  15. #include "ui/events/event.h"
  16. #include "ui/shell_dialogs/select_file_dialog.h"
  17. #include "ui/shell_dialogs/select_file_policy.h"
  18. #include "ui/views/widget/widget.h"
  19. #include "ui/views/widget/widget_delegate.h"
  20. #include "ui/wm/core/transient_window_manager.h"
  21. namespace ash {
  22. namespace {
  23. class NullSelectFolderPolicy : public ui::SelectFilePolicy {
  24. public:
  25. NullSelectFolderPolicy() = default;
  26. ~NullSelectFolderPolicy() override = default;
  27. // ui::SelectFileDialog:
  28. bool CanOpenSelectFileDialog() override { return true; }
  29. void SelectFileDenied() override {}
  30. };
  31. // Returns true if |event| is targeting a window in the subtree rooted at
  32. // |window|.
  33. bool IsEventTargetingWindowInSubtree(const ui::Event* event,
  34. const aura::Window* window) {
  35. DCHECK(window);
  36. auto* target = static_cast<aura::Window*>(event->target());
  37. return window->Contains(target);
  38. }
  39. } // namespace
  40. FolderSelectionDialogController::FolderSelectionDialogController(
  41. Delegate* delegate,
  42. aura::Window* root)
  43. : delegate_(delegate),
  44. // The SettingBubbleContainer was chosen since it's below the virtual
  45. // keyboard container, and therefore users can use the VK to interact with
  46. // this dialog e.g. to rename a folder.
  47. dialog_background_dimmer_(
  48. root->GetChildById(kShellWindowId_SettingBubbleContainer)),
  49. select_folder_dialog_(ui::SelectFileDialog::Create(
  50. /*listener=*/this,
  51. std::make_unique<NullSelectFolderPolicy>())) {
  52. DCHECK(delegate_);
  53. DCHECK(root);
  54. DCHECK(root->IsRootWindow());
  55. auto* owner = dialog_background_dimmer_.window();
  56. owner->SetId(kShellWindowId_CaptureModeFolderSelectionDialogOwner);
  57. window_observation_.Observe(wm::TransientWindowManager::GetOrCreate(owner));
  58. dialog_background_dimmer_.SetDimColor(kColorAshShieldAndBase40);
  59. owner->Show();
  60. select_folder_dialog_->SelectFile(
  61. ui::SelectFileDialog::SELECT_FOLDER,
  62. l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_DIALOG_TITLE),
  63. /*default_path=*/base::FilePath(),
  64. /*file_types=*/nullptr,
  65. /*file_type_index=*/0,
  66. /*default_extension=*/base::FilePath::StringType(),
  67. /*owning_window=*/owner,
  68. /*params=*/nullptr);
  69. }
  70. FolderSelectionDialogController::~FolderSelectionDialogController() {
  71. if (select_folder_dialog_)
  72. select_folder_dialog_->ListenerDestroyed();
  73. }
  74. bool FolderSelectionDialogController::ShouldConsumeEvent(
  75. const ui::Event* event) const {
  76. if (!dialog_window_)
  77. return true;
  78. if (IsEventTargetingWindowInSubtree(event, dialog_window_))
  79. return false;
  80. // The event maybe targeting a virtual keyboard window that is being used to
  81. // interact with the dialog. In this case the event should not be consumed.
  82. auto* keyboard_ui_controller = keyboard::KeyboardUIController::Get();
  83. DCHECK(keyboard_ui_controller);
  84. if (!keyboard_ui_controller->IsKeyboardVisible())
  85. return true;
  86. auto* keyboard_window = keyboard_ui_controller->GetKeyboardWindow();
  87. if (!keyboard_window ||
  88. keyboard_window->GetRootWindow() != dialog_window_->GetRootWindow()) {
  89. return true;
  90. }
  91. return !IsEventTargetingWindowInSubtree(event, keyboard_window);
  92. }
  93. void FolderSelectionDialogController::FileSelected(const base::FilePath& path,
  94. int index,
  95. void* params) {
  96. did_user_select_a_folder_ = true;
  97. delegate_->OnFolderSelected(path);
  98. }
  99. void FolderSelectionDialogController::OnTransientChildAdded(
  100. aura::Window* window,
  101. aura::Window* transient) {
  102. DCHECK_EQ(window, dialog_background_dimmer_.window());
  103. DCHECK(!dialog_window_);
  104. dialog_window_ = transient;
  105. // The dialog should never resize, minimize or maximize.
  106. auto* widget = views::Widget::GetWidgetForNativeWindow(dialog_window_);
  107. DCHECK(widget);
  108. views::WidgetDelegate* widget_delegate = widget->widget_delegate();
  109. DCHECK(widget_delegate);
  110. widget_delegate->SetCanResize(false);
  111. widget_delegate->SetCanMinimize(false);
  112. widget_delegate->SetCanMaximize(false);
  113. delegate_->OnSelectionWindowAdded();
  114. if (on_dialog_window_added_callback_for_test_)
  115. std::move(on_dialog_window_added_callback_for_test_).Run();
  116. }
  117. void FolderSelectionDialogController::OnTransientChildRemoved(
  118. aura::Window* window,
  119. aura::Window* transient) {
  120. DCHECK_EQ(window, dialog_background_dimmer_.window());
  121. DCHECK(dialog_window_);
  122. DCHECK_EQ(transient, dialog_window_);
  123. dialog_window_ = nullptr;
  124. delegate_->OnSelectionWindowClosed();
  125. // |this| will be deleted after the above call.
  126. }
  127. } // namespace ash