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