1 // Copyright 2020 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/ui/views/extensions/settings_overridden_dialog_view.h"
6 
7 #include "base/bind.h"
8 #include "chrome/browser/ui/browser.h"
9 #include "chrome/browser/ui/browser_window.h"
10 #include "chrome/browser/ui/views/chrome_layout_provider.h"
11 #include "chrome/browser/ui/views/chrome_typography.h"
12 #include "chrome/grit/generated_resources.h"
13 #include "components/constrained_window/constrained_window_views.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #include "ui/gfx/color_palette.h"
16 #include "ui/gfx/paint_vector_icon.h"
17 #include "ui/views/controls/label.h"
18 #include "ui/views/layout/fill_layout.h"
19 
SettingsOverriddenDialogView(std::unique_ptr<SettingsOverriddenDialogController> controller)20 SettingsOverriddenDialogView::SettingsOverriddenDialogView(
21     std::unique_ptr<SettingsOverriddenDialogController> controller)
22     : controller_(std::move(controller)) {
23   SetButtonLabel(ui::DIALOG_BUTTON_OK,
24                  l10n_util::GetStringUTF16(
25                      IDS_EXTENSION_SETTINGS_OVERRIDDEN_DIALOG_CHANGE_IT_BACK));
26   SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
27                  l10n_util::GetStringUTF16(
28                      IDS_EXTENSION_SETTINGS_OVERRIDDEN_DIALOG_KEEP_IT));
29   SetLayoutManager(std::make_unique<views::FillLayout>());
30   ChromeLayoutProvider* const layout_provider = ChromeLayoutProvider::Get();
31   set_margins(
32       layout_provider->GetDialogInsetsForContentType(views::TEXT, views::TEXT));
33 
34   using DialogResult = SettingsOverriddenDialogController::DialogResult;
35   auto make_result_callback = [this](DialogResult result) {
36     // NOTE: The following Bind's are safe because the callback is
37     // owned by this object (indirectly, as a DialogDelegate).
38     return base::BindOnce(
39         &SettingsOverriddenDialogView::NotifyControllerOfResult,
40         base::Unretained(this), result);
41   };
42   SetAcceptCallback(make_result_callback(DialogResult::kChangeSettingsBack));
43   SetCancelCallback(make_result_callback(DialogResult::kKeepNewSettings));
44   SetCloseCallback(make_result_callback(DialogResult::kDialogDismissed));
45 
46   // Modals shouldn't show a close button according to the latest style
47   // guidelines. Note the dialog can still be dismissed by user action via the
48   // escape key (in addition to closing automatically if the parent widget
49   // is destroyed).
50   SetShowCloseButton(false);
51 
52   SettingsOverriddenDialogController::ShowParams show_params =
53       controller_->GetShowParams();
54 
55   SetTitle(show_params.dialog_title);
56 
57   if (show_params.icon) {
58     SetShowIcon(true);
59     // Note: Any icons added *should* fully specify their own color, so this
60     // will be a no-op. But, the call requires a color, and this enables testing
61     // with other icons and a reasonable fallback.
62     constexpr SkColor kPlaceholderColor = gfx::kGoogleGrey500;
63     SetIcon(gfx::CreateVectorIcon(*show_params.icon,
64                                   layout_provider->GetDistanceMetric(
65                                       DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE),
66                                   kPlaceholderColor));
67   }
68 
69   auto message_label = std::make_unique<views::Label>(
70       show_params.message, views::style::CONTEXT_DIALOG_BODY_TEXT,
71       views::style::STYLE_SECONDARY);
72   message_label->SetMultiLine(true);
73   message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
74   AddChildView(std::move(message_label));
75 }
76 
~SettingsOverriddenDialogView()77 SettingsOverriddenDialogView::~SettingsOverriddenDialogView() {
78   if (!result_) {
79     // The dialog may close without firing any of the [accept | cancel | close]
80     // callbacks if e.g. the parent window closes. In this case, notify the
81     // controller that the dialog closed without user action.
82     controller_->HandleDialogResult(
83         SettingsOverriddenDialogController::DialogResult::
84             kDialogClosedWithoutUserAction);
85   }
86 }
87 
Show(gfx::NativeWindow parent)88 void SettingsOverriddenDialogView::Show(gfx::NativeWindow parent) {
89   constrained_window::CreateBrowserModalDialogViews(this, parent)->Show();
90   controller_->OnDialogShown();
91 }
92 
GetModalType() const93 ui::ModalType SettingsOverriddenDialogView::GetModalType() const {
94   return ui::MODAL_TYPE_WINDOW;
95 }
96 
CalculatePreferredSize() const97 gfx::Size SettingsOverriddenDialogView::CalculatePreferredSize() const {
98   const int width = ChromeLayoutProvider::Get()->GetDistanceMetric(
99                         views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH) -
100                     margins().width();
101   return gfx::Size(width, GetHeightForWidth(width));
102 }
103 
NotifyControllerOfResult(SettingsOverriddenDialogController::DialogResult result)104 void SettingsOverriddenDialogView::NotifyControllerOfResult(
105     SettingsOverriddenDialogController::DialogResult result) {
106   DCHECK(!result_)
107       << "Trying to re-notify controller of result. Previous result: "
108       << static_cast<int>(*result_)
109       << ", new result: " << static_cast<int>(result);
110   result_ = result;
111   controller_->HandleDialogResult(result);
112 }
113 
114 namespace chrome {
115 
ShowExtensionSettingsOverriddenDialog(std::unique_ptr<SettingsOverriddenDialogController> controller,Browser * browser)116 void ShowExtensionSettingsOverriddenDialog(
117     std::unique_ptr<SettingsOverriddenDialogController> controller,
118     Browser* browser) {
119   // Note: ownership is taken by the view hierarchy.
120   auto* dialog_view = new SettingsOverriddenDialogView(std::move(controller));
121   dialog_view->Show(browser->window()->GetNativeWindow());
122 }
123 
124 }  // namespace chrome
125