Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: chrome/browser/ui/views/payments/editor_view_controller.cc

Issue 2881643002: Focus first invalid field of payment request editor (Closed)
Patch Set: Rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 21 matching lines...) Expand all
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 base::string16 EditorViewController::GetSecondaryButtonLabel() { 143 base::string16 EditorViewController::GetSecondaryButtonLabel() {
142 return l10n_util::GetStringUTF16(IDS_PAYMENTS_CANCEL_PAYMENT); 144 return l10n_util::GetStringUTF16(IDS_PAYMENTS_CANCEL_PAYMENT);
143 } 145 }
144 146
145 void EditorViewController::UpdateEditorView() { 147 void EditorViewController::UpdateEditorView() {
146 UpdateContentView(); 148 UpdateContentView();
147 // TODO(crbug.com/704254): Find how to update the parent view bounds so that
148 // the vertical scrollbar size gets updated.
149 dialog()->EditorViewUpdated(); 149 dialog()->EditorViewUpdated();
150 } 150 }
151 151
152 void EditorViewController::ButtonPressed(views::Button* sender, 152 void EditorViewController::ButtonPressed(views::Button* sender,
153 const ui::Event& event) { 153 const ui::Event& event) {
154 switch (sender->tag()) { 154 switch (sender->tag()) {
155 case static_cast<int>(EditorViewControllerTags::SAVE_BUTTON): 155 case static_cast<int>(EditorViewControllerTags::SAVE_BUTTON):
156 if (ValidateModelAndSave()) { 156 if (ValidateModelAndSave()) {
157 switch (back_navigation_type_) { 157 switch (back_navigation_type_) {
158 case BackNavigationType::kOneStep: 158 case BackNavigationType::kOneStep:
(...skipping 23 matching lines...) Expand all
182 } 182 }
183 183
184 void EditorViewController::OnPerformAction(views::Combobox* sender) { 184 void EditorViewController::OnPerformAction(views::Combobox* sender) {
185 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged(); 185 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged();
186 } 186 }
187 187
188 std::unique_ptr<views::View> EditorViewController::CreateEditorView() { 188 std::unique_ptr<views::View> EditorViewController::CreateEditorView() {
189 std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>(); 189 std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>();
190 text_fields_.clear(); 190 text_fields_.clear();
191 comboboxes_.clear(); 191 comboboxes_.clear();
192 first_field_view_ = nullptr;
192 193
193 // The editor view is padded horizontally. 194 // The editor view is padded horizontally.
194 editor_view->SetBorder(views::CreateEmptyBorder( 195 editor_view->SetBorder(views::CreateEmptyBorder(
195 0, payments::kPaymentRequestRowHorizontalInsets, 0, 196 0, payments::kPaymentRequestRowHorizontalInsets, 0,
196 payments::kPaymentRequestRowHorizontalInsets)); 197 payments::kPaymentRequestRowHorizontalInsets));
197 198
198 // All views have fixed size except the Field which stretches. The fixed 199 // All views have fixed size except the Field which stretches. The fixed
199 // padding at the end is computed so that Field views have a minimum of 200 // padding at the end is computed so that Field views have a minimum of
200 // 176/272dp (short/long fields) as per spec. 201 // 176/272dp (short/long fields) as per spec.
201 // ___________________________________________________________________________ 202 // ___________________________________________________________________________
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 required_field->SetEnabled(false); 274 required_field->SetEnabled(false);
274 275
275 views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(2); 276 views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(2);
276 required_field_columns->AddColumn(views::GridLayout::LEADING, 277 required_field_columns->AddColumn(views::GridLayout::LEADING,
277 views::GridLayout::CENTER, 1, 278 views::GridLayout::CENTER, 1,
278 views::GridLayout::USE_PREF, 0, 0); 279 views::GridLayout::USE_PREF, 0, 0);
279 editor_layout->StartRow(0, 2); 280 editor_layout->StartRow(0, 2);
280 editor_layout->AddView(required_field.release()); 281 editor_layout->AddView(required_field.release());
281 282
282 editor_view->SetLayoutManager(editor_layout.release()); 283 editor_view->SetLayoutManager(editor_layout.release());
284 views::View* potential_first_field_view = nullptr;
anthonyvd 2017/05/12 14:19:44 I'm confused: we seem to be creating the fields bo
MAD 2017/05/18 16:01:44 Oups, yes, merge fluke... Sorry about that... :-(
285 for (const auto& field : GetFieldDefinitions()) {
286 views::View* focusable_field = CreateInputField(
287 static_cast<views::GridLayout*>(editor_view->GetLayoutManager()),
288 field);
289 if (!potential_first_field_view)
290 potential_first_field_view = focusable_field;
291 }
292
293 if (!first_field_view_)
294 first_field_view_ = potential_first_field_view;
283 295
284 return editor_view; 296 return editor_view;
285 } 297 }
286 298
287 // Each input field is a 4-quadrant grid. 299 // Each input field is a 4-quadrant grid.
288 // +----------------------------------------------------------+ 300 // +----------------------------------------------------------+
289 // | Field Label | Input field (textfield/combobox) | 301 // | Field Label | Input field (textfield/combobox) |
290 // |_______________________|__________________________________| 302 // |_______________________|__________________________________|
291 // | (empty) | Error label | 303 // | (empty) | Error label |
292 // +----------------------------------------------------------+ 304 // +----------------------------------------------------------+
293 void EditorViewController::CreateInputField(views::GridLayout* layout, 305 views::View* EditorViewController::CreateInputField(views::GridLayout* layout,
294 const EditorField& field) { 306 const EditorField& field) {
295 int column_set = 307 int column_set =
296 field.length_hint == EditorField::LengthHint::HINT_SHORT ? 0 : 1; 308 field.length_hint == EditorField::LengthHint::HINT_SHORT ? 0 : 1;
297 309
298 // This is the top padding for every row. 310 // This is the top padding for every row.
299 constexpr int kInputRowSpacing = 6; 311 constexpr int kInputRowSpacing = 6;
300 layout->StartRowWithPadding(0, column_set, 0, kInputRowSpacing); 312 layout->StartRowWithPadding(0, column_set, 0, kInputRowSpacing);
301 313
302 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( 314 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
303 field.required ? field.label + base::ASCIIToUTF16("*") : field.label); 315 field.required ? field.label + base::ASCIIToUTF16("*") : field.label);
304 316
305 label->SetMultiLine(true); 317 label->SetMultiLine(true);
306 layout->AddView(label.release()); 318 layout->AddView(label.release());
307 319
320 views::View* focusable_field = nullptr;
321
308 constexpr int kInputFieldHeight = 28; 322 constexpr int kInputFieldHeight = 28;
309 if (field.control_type == EditorField::ControlType::TEXTFIELD) { 323 if (field.control_type == EditorField::ControlType::TEXTFIELD) {
310 ValidatingTextfield* text_field = 324 ValidatingTextfield* text_field =
311 new ValidatingTextfield(CreateValidationDelegate(field)); 325 new ValidatingTextfield(CreateValidationDelegate(field));
312 text_field->SetText(GetInitialValueForType(field.type)); 326 text_field->SetText(GetInitialValueForType(field.type));
313 text_field->set_controller(this); 327 text_field->set_controller(this);
314 // Using autofill field type as a view ID (for testing). 328 // Using autofill field type as a view ID (for testing).
315 text_field->set_id(static_cast<int>(field.type)); 329 text_field->set_id(static_cast<int>(field.type));
316 text_fields_.insert(std::make_pair(text_field, field)); 330 text_fields_.insert(std::make_pair(text_field, field));
317 331 focusable_field = text_field;
318 // TODO(crbug.com/718582): Make the initial focus the first incomplete/empty 332 if (!first_field_view_) {
319 // field. 333 text_field->Validate(/*display_error=*/false);
320 if (!first_field_view_) 334 if (text_field->invalid()) {
321 first_field_view_ = text_field; 335 first_field_view_ = text_field;
336 }
337 }
322 338
323 // |text_field| will now be owned by |row|. 339 // |text_field| will now be owned by |row|.
324 layout->AddView(text_field, 1, 1, views::GridLayout::FILL, 340 layout->AddView(text_field, 1, 1, views::GridLayout::FILL,
325 views::GridLayout::FILL, 0, kInputFieldHeight); 341 views::GridLayout::FILL, 0, kInputFieldHeight);
326 } else if (field.control_type == EditorField::ControlType::COMBOBOX) { 342 } else if (field.control_type == EditorField::ControlType::COMBOBOX) {
327 ValidatingCombobox* combobox = new ValidatingCombobox( 343 ValidatingCombobox* combobox = new ValidatingCombobox(
328 GetComboboxModelForType(field.type), CreateValidationDelegate(field)); 344 GetComboboxModelForType(field.type), CreateValidationDelegate(field));
329 base::string16 initial_value = GetInitialValueForType(field.type); 345 base::string16 initial_value = GetInitialValueForType(field.type);
330 if (!initial_value.empty()) 346 if (!initial_value.empty())
331 combobox->SelectValue(initial_value); 347 combobox->SelectValue(initial_value);
332 // Using autofill field type as a view ID. 348 // Using autofill field type as a view ID.
333 combobox->set_id(static_cast<int>(field.type)); 349 combobox->set_id(static_cast<int>(field.type));
334 combobox->set_listener(this); 350 combobox->set_listener(this);
335 comboboxes_.insert(std::make_pair(combobox, field)); 351 comboboxes_.insert(std::make_pair(combobox, field));
336 352 focusable_field = combobox;
337 if (!first_field_view_) 353 if (!first_field_view_) {
338 first_field_view_ = combobox; 354 combobox->Validate(/*display_error=*/false);
355 if (combobox->invalid()) {
356 first_field_view_ = combobox;
357 }
358 }
339 359
340 // |combobox| will now be owned by |row|. 360 // |combobox| will now be owned by |row|.
341 layout->AddView(combobox, 1, 1, views::GridLayout::FILL, 361 layout->AddView(combobox, 1, 1, views::GridLayout::FILL,
342 views::GridLayout::FILL, 0, kInputFieldHeight); 362 views::GridLayout::FILL, 0, kInputFieldHeight);
343 } else { 363 } else {
344 // Custom field view will now be owned by |row|. And it must be valid since 364 // Custom field view will now be owned by |row|. And it must be valid since
345 // the derived class specified a custom view for this field. 365 // the derived class specified a custom view for this field.
346 std::unique_ptr<views::View> field_view = CreateCustomFieldView(field.type); 366 std::unique_ptr<views::View> field_view =
367 CreateCustomFieldView(field.type, &focusable_field);
347 DCHECK(field_view); 368 DCHECK(field_view);
348 layout->AddView(field_view.release()); 369 layout->AddView(field_view.release());
349 } 370 }
350 371
351 // If an extra view needs to go alongside the input field view, add it to the 372 // If an extra view needs to go alongside the input field view, add it to the
352 // last column. 373 // last column.
353 std::unique_ptr<views::View> extra_view = CreateExtraViewForField(field.type); 374 std::unique_ptr<views::View> extra_view = CreateExtraViewForField(field.type);
354 if (extra_view) 375 if (extra_view)
355 layout->AddView(extra_view.release()); 376 layout->AddView(extra_view.release());
356 377
357 layout->StartRow(0, column_set); 378 layout->StartRow(0, column_set);
358 layout->SkipColumns(1); 379 layout->SkipColumns(1);
359 std::unique_ptr<views::View> error_label_view = 380 std::unique_ptr<views::View> error_label_view =
360 base::MakeUnique<views::View>(); 381 base::MakeUnique<views::View>();
361 error_label_view->SetLayoutManager(new views::FillLayout); 382 error_label_view->SetLayoutManager(new views::FillLayout);
362 error_labels_[field] = error_label_view.get(); 383 error_labels_[field] = error_label_view.get();
363 layout->AddView(error_label_view.release()); 384 layout->AddView(error_label_view.release());
364 385
365 // Bottom padding for the row. 386 // Bottom padding for the row.
366 layout->AddPaddingRow(0, kInputRowSpacing); 387 layout->AddPaddingRow(0, kInputRowSpacing);
388 return focusable_field;
367 } 389 }
368 390
369 int EditorViewController::ComputeWidestExtraViewWidth( 391 int EditorViewController::ComputeWidestExtraViewWidth(
370 EditorField::LengthHint size) { 392 EditorField::LengthHint size) {
371 int widest_column_width = 0; 393 int widest_column_width = 0;
372 394
373 for (const auto& field : GetFieldDefinitions()) { 395 for (const auto& field : GetFieldDefinitions()) {
374 if (field.length_hint != size) 396 if (field.length_hint != size)
375 continue; 397 continue;
376 398
377 std::unique_ptr<views::View> extra_view = 399 std::unique_ptr<views::View> extra_view =
378 CreateExtraViewForField(field.type); 400 CreateExtraViewForField(field.type);
379 if (!extra_view) 401 if (!extra_view)
380 continue; 402 continue;
381 widest_column_width = 403 widest_column_width =
382 std::max(extra_view->GetPreferredSize().width(), widest_column_width); 404 std::max(extra_view->GetPreferredSize().width(), widest_column_width);
383 } 405 }
384 return widest_column_width; 406 return widest_column_width;
385 } 407 }
386 408
387 } // namespace payments 409 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698