OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/payments/editor_view_controller.h" | 5 #include "chrome/browser/ui/views/payments/editor_view_controller.h" |
6 | 6 |
7 #include <algorithm> | |
7 #include <map> | 8 #include <map> |
8 #include <memory> | 9 #include <memory> |
9 #include <utility> | 10 #include <utility> |
10 | 11 |
11 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
12 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
13 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" | 14 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" |
14 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h" | 15 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h" |
15 #include "chrome/browser/ui/views/payments/payment_request_views_util.h" | 16 #include "chrome/browser/ui/views/payments/payment_request_views_util.h" |
16 #include "chrome/browser/ui/views/payments/validating_combobox.h" | 17 #include "chrome/browser/ui/views/payments/validating_combobox.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 } | 72 } |
72 | 73 |
73 } // namespace | 74 } // namespace |
74 | 75 |
75 EditorViewController::EditorViewController( | 76 EditorViewController::EditorViewController( |
76 PaymentRequestSpec* spec, | 77 PaymentRequestSpec* spec, |
77 PaymentRequestState* state, | 78 PaymentRequestState* state, |
78 PaymentRequestDialogView* dialog, | 79 PaymentRequestDialogView* dialog, |
79 BackNavigationType back_navigation_type) | 80 BackNavigationType back_navigation_type) |
80 : PaymentRequestSheetController(spec, state, dialog), | 81 : PaymentRequestSheetController(spec, state, dialog), |
81 first_field_view_(nullptr), | 82 initial_focus_field_view_(nullptr), |
82 back_navigation_type_(back_navigation_type) {} | 83 back_navigation_type_(back_navigation_type) {} |
83 | 84 |
84 EditorViewController::~EditorViewController() {} | 85 EditorViewController::~EditorViewController() {} |
85 | 86 |
86 void EditorViewController::DisplayErrorMessageForField( | 87 void EditorViewController::DisplayErrorMessageForField( |
87 const EditorField& field, | 88 const EditorField& field, |
88 const base::string16& error_message) { | 89 const base::string16& error_message) { |
89 const auto& label_view_it = error_labels_.find(field); | 90 const auto& label_view_it = error_labels_.find(field); |
90 DCHECK(label_view_it != error_labels_.end()); | 91 DCHECK(label_view_it != error_labels_.end()); |
91 | 92 |
92 label_view_it->second->RemoveAllChildViews(/*delete_children=*/true); | 93 label_view_it->second->RemoveAllChildViews(/*delete_children=*/true); |
93 if (!error_message.empty()) { | 94 if (!error_message.empty()) { |
94 label_view_it->second->AddChildView( | 95 label_view_it->second->AddChildView( |
95 CreateErrorLabelView(error_message, field).release()); | 96 CreateErrorLabelView(error_message, field).release()); |
96 } | 97 } |
97 RelayoutPane(); | 98 RelayoutPane(); |
98 } | 99 } |
99 | 100 |
100 std::unique_ptr<views::View> EditorViewController::CreateHeaderView() { | 101 std::unique_ptr<views::View> EditorViewController::CreateHeaderView() { |
101 return nullptr; | 102 return nullptr; |
102 } | 103 } |
103 | 104 |
104 std::unique_ptr<views::View> EditorViewController::CreateCustomFieldView( | 105 std::unique_ptr<views::View> EditorViewController::CreateCustomFieldView( |
105 autofill::ServerFieldType type) { | 106 autofill::ServerFieldType type, |
107 views::View** focusable_field) { | |
106 return nullptr; | 108 return nullptr; |
107 } | 109 } |
108 | 110 |
109 std::unique_ptr<views::View> EditorViewController::CreateExtraViewForField( | 111 std::unique_ptr<views::View> EditorViewController::CreateExtraViewForField( |
110 autofill::ServerFieldType type) { | 112 autofill::ServerFieldType type) { |
111 return nullptr; | 113 return nullptr; |
112 } | 114 } |
113 | 115 |
114 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() { | 116 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() { |
115 std::unique_ptr<views::Button> button( | 117 std::unique_ptr<views::Button> button( |
(...skipping 17 matching lines...) Expand all Loading... | |
133 std::unique_ptr<views::View> header_view = CreateHeaderView(); | 135 std::unique_ptr<views::View> header_view = CreateHeaderView(); |
134 if (header_view.get()) | 136 if (header_view.get()) |
135 content_view->AddChildView(header_view.release()); | 137 content_view->AddChildView(header_view.release()); |
136 | 138 |
137 // The heart of the editor dialog: all the input fields with their labels. | 139 // The heart of the editor dialog: all the input fields with their labels. |
138 content_view->AddChildView(CreateEditorView().release()); | 140 content_view->AddChildView(CreateEditorView().release()); |
139 } | 141 } |
140 | 142 |
141 void EditorViewController::UpdateEditorView() { | 143 void EditorViewController::UpdateEditorView() { |
142 UpdateContentView(); | 144 UpdateContentView(); |
143 // TODO(crbug.com/704254): Find how to update the parent view bounds so that | 145 UpdateFocus(GetFirstFocusedView()); |
144 // the vertical scrollbar size gets updated. | |
145 dialog()->EditorViewUpdated(); | 146 dialog()->EditorViewUpdated(); |
146 } | 147 } |
147 | 148 |
148 void EditorViewController::ButtonPressed(views::Button* sender, | 149 void EditorViewController::ButtonPressed(views::Button* sender, |
149 const ui::Event& event) { | 150 const ui::Event& event) { |
150 switch (sender->tag()) { | 151 switch (sender->tag()) { |
151 case static_cast<int>(EditorViewControllerTags::SAVE_BUTTON): | 152 case static_cast<int>(EditorViewControllerTags::SAVE_BUTTON): |
152 if (ValidateModelAndSave()) { | 153 if (ValidateModelAndSave()) { |
153 switch (back_navigation_type_) { | 154 switch (back_navigation_type_) { |
154 case BackNavigationType::kOneStep: | 155 case BackNavigationType::kOneStep: |
155 dialog()->GoBack(); | 156 dialog()->GoBack(); |
156 break; | 157 break; |
157 case BackNavigationType::kPaymentSheet: | 158 case BackNavigationType::kPaymentSheet: |
158 dialog()->GoBackToPaymentSheet(); | 159 dialog()->GoBackToPaymentSheet(); |
159 break; | 160 break; |
160 } | 161 } |
161 } | 162 } |
162 break; | 163 break; |
163 default: | 164 default: |
164 PaymentRequestSheetController::ButtonPressed(sender, event); | 165 PaymentRequestSheetController::ButtonPressed(sender, event); |
165 break; | 166 break; |
166 } | 167 } |
167 } | 168 } |
168 | 169 |
169 views::View* EditorViewController::GetFirstFocusedView() { | 170 views::View* EditorViewController::GetFirstFocusedView() { |
170 if (first_field_view_) | 171 if (initial_focus_field_view_) |
171 return first_field_view_; | 172 return initial_focus_field_view_; |
172 return PaymentRequestSheetController::GetFirstFocusedView(); | 173 return PaymentRequestSheetController::GetFirstFocusedView(); |
173 } | 174 } |
174 | 175 |
175 void EditorViewController::ContentsChanged(views::Textfield* sender, | 176 void EditorViewController::ContentsChanged(views::Textfield* sender, |
176 const base::string16& new_contents) { | 177 const base::string16& new_contents) { |
177 static_cast<ValidatingTextfield*>(sender)->OnContentsChanged(); | 178 static_cast<ValidatingTextfield*>(sender)->OnContentsChanged(); |
178 } | 179 } |
179 | 180 |
180 void EditorViewController::OnPerformAction(views::Combobox* sender) { | 181 void EditorViewController::OnPerformAction(views::Combobox* sender) { |
181 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged(); | 182 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged(); |
182 } | 183 } |
183 | 184 |
184 std::unique_ptr<views::View> EditorViewController::CreateEditorView() { | 185 std::unique_ptr<views::View> EditorViewController::CreateEditorView() { |
185 std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>(); | 186 std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>(); |
186 text_fields_.clear(); | 187 text_fields_.clear(); |
187 comboboxes_.clear(); | 188 comboboxes_.clear(); |
189 initial_focus_field_view_ = nullptr; | |
188 | 190 |
189 // The editor view is padded horizontally. | 191 // The editor view is padded horizontally. |
190 editor_view->SetBorder(views::CreateEmptyBorder( | 192 editor_view->SetBorder(views::CreateEmptyBorder( |
191 0, payments::kPaymentRequestRowHorizontalInsets, 0, | 193 0, payments::kPaymentRequestRowHorizontalInsets, 0, |
192 payments::kPaymentRequestRowHorizontalInsets)); | 194 payments::kPaymentRequestRowHorizontalInsets)); |
193 | 195 |
194 // All views have fixed size except the Field which stretches. The fixed | 196 // All views have fixed size except the Field which stretches. The fixed |
195 // padding at the end is computed so that Field views have a minimum of | 197 // padding at the end is computed so that Field views have a minimum of |
196 // 176/272dp (short/long fields) as per spec. | 198 // 176/272dp (short/long fields) as per spec. |
197 // ___________________________________________________________________________ | 199 // ___________________________________________________________________________ |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 0, views::GridLayout::FIXED, long_extra_view_width, | 252 0, views::GridLayout::FIXED, long_extra_view_width, |
251 0); | 253 0); |
252 // The padding at the end is fixed, computed to make sure the long field | 254 // The padding at the end is fixed, computed to make sure the long field |
253 // maintains its minimum width. | 255 // maintains its minimum width. |
254 int long_padding = kDialogMinWidth - kLongFieldMinimumWidth - kLabelWidth - | 256 int long_padding = kDialogMinWidth - kLongFieldMinimumWidth - kLabelWidth - |
255 (2 * kPaymentRequestRowHorizontalInsets) - | 257 (2 * kPaymentRequestRowHorizontalInsets) - |
256 kLabelInputFieldHorizontalPadding - | 258 kLabelInputFieldHorizontalPadding - |
257 kFieldExtraViewHorizontalPadding - long_extra_view_width; | 259 kFieldExtraViewHorizontalPadding - long_extra_view_width; |
258 columns_long->AddPaddingColumn(0, long_padding); | 260 columns_long->AddPaddingColumn(0, long_padding); |
259 | 261 |
260 for (const auto& field : GetFieldDefinitions()) | 262 views::View* potential_first_field_view = nullptr; |
anthonyvd
2017/05/18 21:15:37
nit: first_field?
MAD
2017/05/19 13:43:51
Done.
| |
261 CreateInputField(editor_layout.get(), field); | 263 for (const auto& field : GetFieldDefinitions()) { |
264 bool valid = false; | |
265 views::View* focusable_field = | |
266 CreateInputField(editor_layout.get(), field, &valid); | |
267 if (!initial_focus_field_view_) { | |
268 if (!valid) | |
269 initial_focus_field_view_ = focusable_field; | |
270 else if (!potential_first_field_view) | |
anthonyvd
2017/05/18 21:15:37
If you pull this else if statement out of the pare
MAD
2017/05/19 13:43:51
I'm not sure I understand. The idea here is that,
anthonyvd
2017/05/19 15:11:42
Sorry I'm being unclear. The algorithm is "If at l
MAD
2017/05/19 15:35:35
Done.
| |
271 potential_first_field_view = focusable_field; | |
272 } | |
273 } | |
274 | |
275 if (!initial_focus_field_view_) | |
276 initial_focus_field_view_ = potential_first_field_view; | |
262 | 277 |
263 // Adds the "* indicates a required field" label in "disabled" grey text. | 278 // Adds the "* indicates a required field" label in "disabled" grey text. |
264 std::unique_ptr<views::Label> required_field = base::MakeUnique<views::Label>( | 279 std::unique_ptr<views::Label> required_field = base::MakeUnique<views::Label>( |
265 l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE)); | 280 l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE)); |
266 required_field->SetDisabledColor( | 281 required_field->SetDisabledColor( |
267 required_field->GetNativeTheme()->GetSystemColor( | 282 required_field->GetNativeTheme()->GetSystemColor( |
268 ui::NativeTheme::kColorId_LabelDisabledColor)); | 283 ui::NativeTheme::kColorId_LabelDisabledColor)); |
269 required_field->SetEnabled(false); | 284 required_field->SetEnabled(false); |
270 | 285 |
271 views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(2); | 286 views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(2); |
272 required_field_columns->AddColumn(views::GridLayout::LEADING, | 287 required_field_columns->AddColumn(views::GridLayout::LEADING, |
273 views::GridLayout::CENTER, 1, | 288 views::GridLayout::CENTER, 1, |
274 views::GridLayout::USE_PREF, 0, 0); | 289 views::GridLayout::USE_PREF, 0, 0); |
275 editor_layout->StartRow(0, 2); | 290 editor_layout->StartRow(0, 2); |
276 editor_layout->AddView(required_field.release()); | 291 editor_layout->AddView(required_field.release()); |
277 | 292 |
278 editor_view->SetLayoutManager(editor_layout.release()); | 293 editor_view->SetLayoutManager(editor_layout.release()); |
279 | 294 |
280 return editor_view; | 295 return editor_view; |
281 } | 296 } |
282 | 297 |
283 // Each input field is a 4-quadrant grid. | 298 // Each input field is a 4-quadrant grid. |
284 // +----------------------------------------------------------+ | 299 // +----------------------------------------------------------+ |
285 // | Field Label | Input field (textfield/combobox) | | 300 // | Field Label | Input field (textfield/combobox) | |
286 // |_______________________|__________________________________| | 301 // |_______________________|__________________________________| |
287 // | (empty) | Error label | | 302 // | (empty) | Error label | |
288 // +----------------------------------------------------------+ | 303 // +----------------------------------------------------------+ |
289 void EditorViewController::CreateInputField(views::GridLayout* layout, | 304 views::View* EditorViewController::CreateInputField(views::GridLayout* layout, |
290 const EditorField& field) { | 305 const EditorField& field, |
306 bool* valid) { | |
291 int column_set = | 307 int column_set = |
292 field.length_hint == EditorField::LengthHint::HINT_SHORT ? 0 : 1; | 308 field.length_hint == EditorField::LengthHint::HINT_SHORT ? 0 : 1; |
293 | 309 |
294 // This is the top padding for every row. | 310 // This is the top padding for every row. |
295 constexpr int kInputRowSpacing = 6; | 311 constexpr int kInputRowSpacing = 6; |
296 layout->StartRowWithPadding(0, column_set, 0, kInputRowSpacing); | 312 layout->StartRowWithPadding(0, column_set, 0, kInputRowSpacing); |
297 | 313 |
298 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( | 314 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( |
299 field.required ? field.label + base::ASCIIToUTF16("*") : field.label); | 315 field.required ? field.label + base::ASCIIToUTF16("*") : field.label); |
300 | 316 |
301 label->SetMultiLine(true); | 317 label->SetMultiLine(true); |
302 layout->AddView(label.release()); | 318 layout->AddView(label.release()); |
303 | 319 |
320 views::View* focusable_field = nullptr; | |
anthonyvd
2017/05/18 21:15:37
Since this isn't necessarily related to focus anym
MAD
2017/05/19 13:43:51
Well, it still kind of is, especially in the custo
anthonyvd
2017/05/19 15:11:42
Ah I didn't think about composite fields. Yeah tha
| |
321 | |
304 constexpr int kInputFieldHeight = 28; | 322 constexpr int kInputFieldHeight = 28; |
305 if (field.control_type == EditorField::ControlType::TEXTFIELD) { | 323 if (field.control_type == EditorField::ControlType::TEXTFIELD) { |
306 ValidatingTextfield* text_field = | 324 ValidatingTextfield* text_field = |
307 new ValidatingTextfield(CreateValidationDelegate(field)); | 325 new ValidatingTextfield(CreateValidationDelegate(field)); |
308 text_field->SetText(GetInitialValueForType(field.type)); | 326 text_field->SetText(GetInitialValueForType(field.type)); |
309 text_field->set_controller(this); | 327 text_field->set_controller(this); |
310 // Using autofill field type as a view ID (for testing). | 328 // Using autofill field type as a view ID (for testing). |
311 text_field->set_id(static_cast<int>(field.type)); | 329 text_field->set_id(static_cast<int>(field.type)); |
312 text_fields_.insert(std::make_pair(text_field, field)); | 330 text_fields_.insert(std::make_pair(text_field, field)); |
313 | 331 focusable_field = text_field; |
314 // TODO(crbug.com/718582): Make the initial focus the first incomplete/empty | 332 *valid = text_field->IsValid(); |
315 // field. | |
316 if (!first_field_view_) | |
317 first_field_view_ = text_field; | |
318 | 333 |
319 // |text_field| will now be owned by |row|. | 334 // |text_field| will now be owned by |row|. |
320 layout->AddView(text_field, 1, 1, views::GridLayout::FILL, | 335 layout->AddView(text_field, 1, 1, views::GridLayout::FILL, |
321 views::GridLayout::FILL, 0, kInputFieldHeight); | 336 views::GridLayout::FILL, 0, kInputFieldHeight); |
322 } else if (field.control_type == EditorField::ControlType::COMBOBOX) { | 337 } else if (field.control_type == EditorField::ControlType::COMBOBOX) { |
323 ValidatingCombobox* combobox = new ValidatingCombobox( | 338 ValidatingCombobox* combobox = new ValidatingCombobox( |
324 GetComboboxModelForType(field.type), CreateValidationDelegate(field)); | 339 GetComboboxModelForType(field.type), CreateValidationDelegate(field)); |
325 base::string16 initial_value = GetInitialValueForType(field.type); | 340 base::string16 initial_value = GetInitialValueForType(field.type); |
326 if (!initial_value.empty()) | 341 if (!initial_value.empty()) |
327 combobox->SelectValue(initial_value); | 342 combobox->SelectValue(initial_value); |
328 // Using autofill field type as a view ID. | 343 // Using autofill field type as a view ID. |
329 combobox->set_id(static_cast<int>(field.type)); | 344 combobox->set_id(static_cast<int>(field.type)); |
330 combobox->set_listener(this); | 345 combobox->set_listener(this); |
331 comboboxes_.insert(std::make_pair(combobox, field)); | 346 comboboxes_.insert(std::make_pair(combobox, field)); |
332 | 347 focusable_field = combobox; |
333 if (!first_field_view_) | 348 *valid = combobox->IsValid(); |
334 first_field_view_ = combobox; | |
335 | 349 |
336 // |combobox| will now be owned by |row|. | 350 // |combobox| will now be owned by |row|. |
337 layout->AddView(combobox, 1, 1, views::GridLayout::FILL, | 351 layout->AddView(combobox, 1, 1, views::GridLayout::FILL, |
338 views::GridLayout::FILL, 0, kInputFieldHeight); | 352 views::GridLayout::FILL, 0, kInputFieldHeight); |
339 } else { | 353 } else { |
340 // Custom field view will now be owned by |row|. And it must be valid since | 354 // Custom field view will now be owned by |row|. And it must be valid since |
341 // the derived class specified a custom view for this field. | 355 // the derived class specified a custom view for this field. |
342 std::unique_ptr<views::View> field_view = CreateCustomFieldView(field.type); | 356 DCHECK(!focusable_field); |
357 std::unique_ptr<views::View> field_view = | |
358 CreateCustomFieldView(field.type, &focusable_field); | |
343 DCHECK(field_view); | 359 DCHECK(field_view); |
344 layout->AddView(field_view.release()); | 360 layout->AddView(field_view.release()); |
345 } | 361 } |
346 | 362 |
347 // If an extra view needs to go alongside the input field view, add it to the | 363 // If an extra view needs to go alongside the input field view, add it to the |
348 // last column. | 364 // last column. |
349 std::unique_ptr<views::View> extra_view = CreateExtraViewForField(field.type); | 365 std::unique_ptr<views::View> extra_view = CreateExtraViewForField(field.type); |
350 if (extra_view) | 366 if (extra_view) |
351 layout->AddView(extra_view.release()); | 367 layout->AddView(extra_view.release()); |
352 | 368 |
353 layout->StartRow(0, column_set); | 369 layout->StartRow(0, column_set); |
354 layout->SkipColumns(1); | 370 layout->SkipColumns(1); |
355 std::unique_ptr<views::View> error_label_view = | 371 std::unique_ptr<views::View> error_label_view = |
356 base::MakeUnique<views::View>(); | 372 base::MakeUnique<views::View>(); |
357 error_label_view->SetLayoutManager(new views::FillLayout); | 373 error_label_view->SetLayoutManager(new views::FillLayout); |
358 error_labels_[field] = error_label_view.get(); | 374 error_labels_[field] = error_label_view.get(); |
359 layout->AddView(error_label_view.release()); | 375 layout->AddView(error_label_view.release()); |
360 | 376 |
361 // Bottom padding for the row. | 377 // Bottom padding for the row. |
362 layout->AddPaddingRow(0, kInputRowSpacing); | 378 layout->AddPaddingRow(0, kInputRowSpacing); |
379 return focusable_field; | |
363 } | 380 } |
364 | 381 |
365 int EditorViewController::ComputeWidestExtraViewWidth( | 382 int EditorViewController::ComputeWidestExtraViewWidth( |
366 EditorField::LengthHint size) { | 383 EditorField::LengthHint size) { |
367 int widest_column_width = 0; | 384 int widest_column_width = 0; |
368 | 385 |
369 for (const auto& field : GetFieldDefinitions()) { | 386 for (const auto& field : GetFieldDefinitions()) { |
370 if (field.length_hint != size) | 387 if (field.length_hint != size) |
371 continue; | 388 continue; |
372 | 389 |
373 std::unique_ptr<views::View> extra_view = | 390 std::unique_ptr<views::View> extra_view = |
374 CreateExtraViewForField(field.type); | 391 CreateExtraViewForField(field.type); |
375 if (!extra_view) | 392 if (!extra_view) |
376 continue; | 393 continue; |
377 widest_column_width = | 394 widest_column_width = |
378 std::max(extra_view->GetPreferredSize().width(), widest_column_width); | 395 std::max(extra_view->GetPreferredSize().width(), widest_column_width); |
379 } | 396 } |
380 return widest_column_width; | 397 return widest_column_width; |
381 } | 398 } |
382 | 399 |
383 } // namespace payments | 400 } // namespace payments |
OLD | NEW |