OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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/srt_prompt_dialog.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/strings/string16.h" | |
10 #include "chrome/app/vector_icons/vector_icons.h" | |
11 #include "chrome/browser/safe_browsing/srt_prompt_controller.h" | |
12 #include "chrome/browser/ui/browser.h" | |
13 #include "chrome/browser/ui/browser_dialogs.h" | |
14 #include "chrome/browser/ui/browser_window.h" | |
15 #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" | |
16 #include "components/constrained_window/constrained_window_views.h" | |
17 #include "components/web_modal/web_contents_modal_dialog_host.h" | |
18 #include "ui/base/ui_base_types.h" | |
19 #include "ui/events/event.h" | |
20 #include "ui/gfx/geometry/size.h" | |
21 #include "ui/gfx/native_widget_types.h" | |
22 #include "ui/gfx/paint_vector_icon.h" | |
23 #include "ui/gfx/text_constants.h" | |
24 #include "ui/native_theme/native_theme.h" | |
25 #include "ui/views/border.h" | |
26 #include "ui/views/controls/label.h" | |
27 #include "ui/views/controls/scroll_view.h" | |
28 #include "ui/views/controls/separator.h" | |
29 #include "ui/views/layout/box_layout.h" | |
30 #include "ui/views/layout/fill_layout.h" | |
31 #include "ui/views/layout/grid_layout.h" | |
32 #include "ui/views/layout/layout_constants.h" | |
33 #include "ui/views/widget/widget.h" | |
34 | |
35 namespace chrome { | |
36 | |
37 void ShowSRTPrompt(Browser* browser, | |
38 safe_browsing::SRTPromptController* controller) { | |
39 SRTPromptDialog* dialog = new SRTPromptDialog(controller); | |
40 dialog->Show(browser); | |
41 } | |
42 | |
43 } // namespace chrome | |
44 | |
45 namespace { | |
46 | |
47 using LabelInfo = safe_browsing::SRTPromptController::LabelInfo; | |
48 | |
49 constexpr int kDialogWidth = 448; | |
50 constexpr int kDetailsSectionMaxHeight = 150; | |
51 constexpr int kBulletColumnWidth = 10; | |
52 // Constants used for the layout of the label views. | |
53 constexpr int kMainColumSetId = 0; | |
54 constexpr int kBulletColumnSetId = 1; | |
55 | |
56 // Returns a view containing |item| with insets defined by |top|, |left|, | |
57 // |bottom|, and |right|. | |
58 views::View* CreateViewWithInsets(views::View* item, | |
59 int top, | |
60 int left, | |
61 int bottom, | |
62 int right) { | |
63 views::View* view = new views::View(); | |
64 view->SetLayoutManager(new views::FillLayout()); | |
65 view->SetBorder(views::CreateEmptyBorder(top, left, bottom, right)); | |
66 view->AddChildView(item); | |
67 return view; | |
68 } | |
69 | |
70 // Helper function used by |CreateLabelView()| below that adds |labels| to | |
71 // |label_view|. | |
72 void AddLabelsToLabelView(views::View* label_view, | |
73 views::GridLayout* layout, | |
74 const std::vector<LabelInfo>& labels) { | |
75 static constexpr base::char16 kBulletPoint[] = {0x2022, 0}; | |
76 | |
77 bool first_label = true; | |
78 bool last_label_was_bullet = false; | |
79 for (const LabelInfo& label_info : labels) { | |
80 const bool is_bullet = label_info.type == LabelInfo::BULLET_ITEM; | |
81 views::Label* label = new views::Label(label_info.text); | |
82 label->SetMultiLine(true); | |
83 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
84 | |
85 // Do not add a padding row if | |
86 // - this is the first label being added, or | |
87 // - a bullet item is being added and the last label was also a bullet item. | |
88 bool skip_padding = first_label || (is_bullet && last_label_was_bullet); | |
89 if (!skip_padding) | |
90 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | |
91 | |
92 layout->StartRow(0, is_bullet ? kBulletColumnSetId : kMainColumSetId); | |
93 if (is_bullet) { | |
94 views::Label* bullet = new views::Label(base::string16(kBulletPoint)); | |
95 layout->AddView(bullet); | |
96 } | |
97 layout->AddView(label); | |
98 | |
99 last_label_was_bullet = is_bullet; | |
100 first_label = false; | |
101 } | |
102 } | |
103 | |
104 // Creates a view that displays two types of labels: multiline labels | |
105 // representing whole paragraphs or indented labels that are start with a bullet | |
106 // point. | |
107 // | |
108 // A vertical padding of size |top_vertical_space| is added before the labels. | |
109 views::View* CreateLabelView(int top_vertical_space, | |
110 const std::vector<LabelInfo>& labels) { | |
111 views::View* label_view = new views::View(); | |
112 views::GridLayout* layout = new views::GridLayout(label_view); | |
113 layout->SetInsets(0, views::kButtonHEdgeMarginNew, 0, | |
114 views::kButtonHEdgeMarginNew); | |
115 | |
116 label_view->SetLayoutManager(layout); | |
117 | |
118 views::ColumnSet* main_column_set = layout->AddColumnSet(kMainColumSetId); | |
119 main_column_set->AddColumn(views::GridLayout::FILL, | |
120 views::GridLayout::LEADING, | |
121 /*resize_percent=*/1, views::GridLayout::USE_PREF, | |
122 /*fixed_width=*/0, | |
123 /*min_width=*/0); | |
124 | |
125 views::ColumnSet* bullet_column_set_ = | |
126 layout->AddColumnSet(kBulletColumnSetId); | |
127 bullet_column_set_->AddPaddingColumn( | |
128 /*resize_percent=*/0, views::kUnrelatedControlLargeHorizontalSpacing); | |
129 bullet_column_set_->AddColumn( | |
130 views::GridLayout::FILL, views::GridLayout::LEADING, | |
131 /*resize_percent=*/0, views::GridLayout::USE_PREF, | |
132 /*fixed_width=*/0, | |
133 /*min_width=*/0); | |
134 bullet_column_set_->AddPaddingColumn(/*resize_percent=*/0, | |
135 kBulletColumnWidth); | |
136 bullet_column_set_->AddColumn( | |
137 views::GridLayout::FILL, views::GridLayout::LEADING, | |
138 /*resize_percent=*/1, views::GridLayout::USE_PREF, | |
139 /*fixed_width=*/0, | |
140 /*min_width=*/0); | |
141 | |
142 if (top_vertical_space > 0) | |
143 layout->AddPaddingRow(/*vertical_resize=*/0, top_vertical_space); | |
144 | |
145 AddLabelsToLabelView(label_view, layout, labels); | |
146 | |
147 layout->AddPaddingRow(/*vertical_resize=*/0, | |
148 views::kUnrelatedControlLargeHorizontalSpacing); | |
149 return label_view; | |
150 } | |
151 | |
152 } // namespace | |
153 | |
154 //////////////////////////////////////////////////////////////////////////////// | |
155 // SRTPromptDialog | |
156 | |
157 SRTPromptDialog::SRTPromptDialog(safe_browsing::SRTPromptController* controller) | |
158 : browser_(nullptr), | |
159 controller_(controller), | |
160 interaction_done_(false), | |
161 details_view_(nullptr), | |
162 details_button_(nullptr) { | |
163 DCHECK(controller_); | |
164 | |
165 SetLayoutManager(new views::BoxLayout( | |
166 /*orientation=*/views::BoxLayout::kVertical, | |
167 /*inside_border_horizontal_spacing=*/0, | |
168 /*inside_border_vertical_spacing=*/views::kPanelVertMargin, | |
169 /*between_child_spacing=*/0)); | |
170 | |
171 AddChildView(CreateLabelView(0, controller_->GetMainText())); | |
172 AddChildView(new views::Separator()); | |
173 | |
174 // The details section starts off empty and will be populated when the user | |
175 // clicks the button to expand the details section. Its child views are | |
176 // removed when the section is closed. | |
177 details_view_ = new views::View(); | |
sky
2017/04/06 16:01:02
move to member initializer?
alito
2017/04/06 17:35:37
Done.
| |
178 details_view_->SetLayoutManager(new views::FillLayout()); | |
179 details_view_->SetVisible(false); | |
180 AddChildView(details_view_); | |
181 | |
182 details_button_ = | |
183 new views::LabelButton(this, controller_->GetShowDetailsLabel()); | |
184 details_button_->SetEnabledTextColors(GetDetailsButtonColor()); | |
185 UpdateDetailsButton(); | |
186 AddChildView(CreateViewWithInsets( | |
187 details_button_, views::kPanelVertMargin, views::kButtonHEdgeMarginNew, | |
188 views::kPanelVertMargin, views::kButtonHEdgeMarginNew)); | |
189 AddChildView(new views::Separator()); | |
190 } | |
191 | |
192 SRTPromptDialog::~SRTPromptDialog() { | |
193 // Make sure the controller is correctly notified in case the dialog widget is | |
194 // closed by some other means than the dialog buttons. | |
195 if (!interaction_done_) | |
196 controller_->Cancel(); | |
197 } | |
198 | |
199 void SRTPromptDialog::Show(Browser* browser) { | |
200 DCHECK(browser); | |
201 DCHECK(!browser_); | |
202 | |
203 browser_ = browser; | |
204 constrained_window::CreateBrowserModalDialogViews( | |
205 this, browser_->window()->GetNativeWindow()) | |
206 ->Show(); | |
207 controller_->DialogShown(); | |
208 } | |
209 | |
210 // DialogModel overrides. | |
211 | |
212 bool SRTPromptDialog::ShouldDefaultButtonBeBlue() const { | |
213 return true; | |
214 } | |
215 | |
216 // WidgetDelegate overrides. | |
217 | |
218 ui::ModalType SRTPromptDialog::GetModalType() const { | |
219 return ui::MODAL_TYPE_WINDOW; | |
220 } | |
221 | |
222 base::string16 SRTPromptDialog::GetWindowTitle() const { | |
223 return controller_->GetWindowTitle(); | |
224 } | |
225 | |
226 // DialogDelegate overrides. | |
227 | |
228 base::string16 SRTPromptDialog::GetDialogButtonLabel( | |
229 ui::DialogButton button) const { | |
230 DCHECK(button == ui::DIALOG_BUTTON_OK || button == ui::DIALOG_BUTTON_CANCEL); | |
231 | |
232 if (button == ui::DIALOG_BUTTON_OK) | |
233 return controller_->GetAcceptButtonLabel(); | |
234 return DialogDelegate::GetDialogButtonLabel(button); | |
235 } | |
236 | |
237 bool SRTPromptDialog::Accept() { | |
238 if (!interaction_done_) { | |
239 interaction_done_ = true; | |
240 controller_->Accept(); | |
241 } | |
242 return true; | |
243 } | |
244 | |
245 bool SRTPromptDialog::Cancel() { | |
246 if (!interaction_done_) { | |
247 interaction_done_ = true; | |
248 controller_->Cancel(); | |
249 } | |
250 return true; | |
251 } | |
252 | |
253 // View overrides. | |
254 | |
255 gfx::Size SRTPromptDialog::GetPreferredSize() const { | |
256 return gfx::Size(kDialogWidth, GetHeightForWidth(kDialogWidth)); | |
257 } | |
258 | |
259 // views::ButtonListener overrides. | |
260 | |
261 void SRTPromptDialog::ButtonPressed(views::Button* sender, | |
262 const ui::Event& event) { | |
263 DCHECK_EQ(sender, details_button_); | |
264 DCHECK(browser_); | |
265 | |
266 details_view_->SetVisible(!details_view_->visible()); | |
267 if (details_view_->visible()) { | |
268 // Populate the details view adding the main message view inside a scroll | |
269 // view. | |
270 views::View* label_view = | |
271 CreateLabelView(views::kUnrelatedControlLargeHorizontalSpacing, | |
272 controller_->GetDetailsText()); | |
273 views::ScrollView* scroll_view = new views::ScrollView(); | |
274 scroll_view->ClipHeightTo(/*min_height=*/0, kDetailsSectionMaxHeight); | |
275 scroll_view->SetContents(label_view); | |
276 details_view_->AddChildView(scroll_view); | |
277 } else { | |
278 details_view_->RemoveAllChildViews(/*delete_children=*/true); | |
279 } | |
280 | |
281 UpdateDetailsButton(); | |
282 | |
283 ChromeWebModalDialogManagerDelegate* manager = browser_; | |
284 constrained_window::UpdateWidgetModalDialogPosition( | |
285 GetWidget(), manager->GetWebContentsModalDialogHost()); | |
286 } | |
287 | |
288 SkColor SRTPromptDialog::GetDetailsButtonColor() { | |
289 return GetNativeTheme()->GetSystemColor( | |
290 ui::NativeTheme::kColorId_LinkEnabled); | |
291 } | |
292 | |
293 void SRTPromptDialog::UpdateDetailsButton() { | |
294 details_button_->SetText(details_view_->visible() | |
295 ? controller_->GetHideDetailsLabel() | |
296 : controller_->GetShowDetailsLabel()); | |
297 details_button_->SetImage( | |
298 views::Button::STATE_NORMAL, | |
299 details_view_->visible() | |
300 ? gfx::CreateVectorIcon(kCaretUpIcon, GetDetailsButtonColor()) | |
301 : gfx::CreateVectorIcon(kCaretDownIcon, GetDetailsButtonColor())); | |
302 } | |
OLD | NEW |