autofill_external_delegate.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright 2013 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 "components/autofill/core/browser/autofill_external_delegate.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "components/autofill/core/browser/autocomplete_history_manager.h"
9#include "components/autofill/core/browser/autofill_driver.h"
10#include "components/autofill/core/browser/autofill_manager.h"
11#include "components/autofill/core/browser/popup_item_ids.h"
12#include "grit/component_strings.h"
13#include "ui/base/l10n/l10n_util.h"
14
15namespace autofill {
16
17AutofillExternalDelegate::AutofillExternalDelegate(
18    AutofillManager* manager,
19    AutofillDriver* driver)
20    : manager_(manager),
21      driver_(driver),
22      password_manager_(driver),
23      query_id_(0),
24      display_warning_if_disabled_(false),
25      has_suggestion_(false),
26      has_shown_popup_for_current_edit_(false),
27      weak_ptr_factory_(this) {
28  DCHECK(manager);
29}
30
31AutofillExternalDelegate::~AutofillExternalDelegate() {}
32
33void AutofillExternalDelegate::OnQuery(int query_id,
34                                       const FormData& form,
35                                       const FormFieldData& field,
36                                       const gfx::RectF& element_bounds,
37                                       bool display_warning_if_disabled) {
38  query_form_ = form;
39  query_field_ = field;
40  display_warning_if_disabled_ = display_warning_if_disabled;
41  query_id_ = query_id;
42  element_bounds_ = element_bounds;
43}
44
45void AutofillExternalDelegate::OnSuggestionsReturned(
46    int query_id,
47    const std::vector<base::string16>& suggested_values,
48    const std::vector<base::string16>& suggested_labels,
49    const std::vector<base::string16>& suggested_icons,
50    const std::vector<int>& suggested_unique_ids) {
51  if (query_id != query_id_)
52    return;
53
54  std::vector<base::string16> values(suggested_values);
55  std::vector<base::string16> labels(suggested_labels);
56  std::vector<base::string16> icons(suggested_icons);
57  std::vector<int> ids(suggested_unique_ids);
58
59  // Add or hide warnings as appropriate.
60  ApplyAutofillWarnings(&values, &labels, &icons, &ids);
61
62  // Add a separator to go between the values and menu items.
63  values.push_back(base::string16());
64  labels.push_back(base::string16());
65  icons.push_back(base::string16());
66  ids.push_back(POPUP_ITEM_ID_SEPARATOR);
67
68  // Only include "Autofill Options" special menu item if we have Autofill
69  // suggestions.
70  has_suggestion_ = false;
71  for (size_t i = 0; i < ids.size(); ++i) {
72    if (ids[i] > 0) {
73      has_suggestion_ = true;
74      break;
75    }
76  }
77
78  if (has_suggestion_)
79    ApplyAutofillOptions(&values, &labels, &icons, &ids);
80
81  // Remove the separator if it is the last element.
82  DCHECK_GT(ids.size(), 0U);
83  if (ids.back() == POPUP_ITEM_ID_SEPARATOR) {
84    values.pop_back();
85    labels.pop_back();
86    icons.pop_back();
87    ids.pop_back();
88  }
89
90  // If anything else is added to modify the values after inserting the data
91  // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be
92  // updated to match.
93  InsertDataListValues(&values, &labels, &icons, &ids);
94
95  if (values.empty()) {
96    // No suggestions, any popup currently showing is obsolete.
97    manager_->delegate()->HideAutofillPopup();
98    return;
99  }
100
101  // Send to display.
102  if (query_field_.is_focusable) {
103    manager_->delegate()->ShowAutofillPopup(
104        element_bounds_,
105        query_field_.text_direction,
106        values,
107        labels,
108        icons,
109        ids,
110        GetWeakPtr());
111  }
112}
113
114void AutofillExternalDelegate::OnShowPasswordSuggestions(
115    const std::vector<base::string16>& suggestions,
116    const std::vector<base::string16>& realms,
117    const FormFieldData& field,
118    const gfx::RectF& element_bounds) {
119  query_field_ = field;
120  element_bounds_ = element_bounds;
121
122  if (suggestions.empty()) {
123    manager_->delegate()->HideAutofillPopup();
124    return;
125  }
126
127  std::vector<base::string16> empty(suggestions.size());
128  std::vector<int> password_ids(suggestions.size(),
129                                POPUP_ITEM_ID_PASSWORD_ENTRY);
130  manager_->delegate()->ShowAutofillPopup(
131      element_bounds_,
132      query_field_.text_direction,
133      suggestions,
134      realms,
135      empty,
136      password_ids,
137      GetWeakPtr());
138}
139
140void AutofillExternalDelegate::SetCurrentDataListValues(
141    const std::vector<base::string16>& data_list_values,
142    const std::vector<base::string16>& data_list_labels) {
143  data_list_values_ = data_list_values;
144  data_list_labels_ = data_list_labels;
145
146  manager_->delegate()->UpdateAutofillPopupDataListValues(
147      data_list_values,
148      data_list_labels);
149}
150
151void AutofillExternalDelegate::OnPopupShown() {
152  manager_->DidShowSuggestions(
153      has_suggestion_ && !has_shown_popup_for_current_edit_);
154  has_shown_popup_for_current_edit_ |= has_suggestion_;
155}
156
157void AutofillExternalDelegate::OnPopupHidden() {
158}
159
160void AutofillExternalDelegate::DidSelectSuggestion(
161    const base::string16& value,
162    int identifier) {
163  ClearPreviewedForm();
164
165  // Only preview the data if it is a profile.
166  if (identifier > 0)
167    FillAutofillFormData(identifier, true);
168  else if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)
169    driver_->RendererShouldPreviewFieldWithValue(value);
170}
171
172void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
173                                                   int identifier) {
174  if (identifier == POPUP_ITEM_ID_AUTOFILL_OPTIONS) {
175    // User selected 'Autofill Options'.
176    manager_->ShowAutofillSettings();
177  } else if (identifier == POPUP_ITEM_ID_CLEAR_FORM) {
178    // User selected 'Clear form'.
179    driver_->RendererShouldClearFilledForm();
180  } else if (identifier == POPUP_ITEM_ID_PASSWORD_ENTRY) {
181    bool success = password_manager_.DidAcceptAutofillSuggestion(
182        query_field_, value);
183    DCHECK(success);
184  } else if (identifier == POPUP_ITEM_ID_DATALIST_ENTRY) {
185    driver_->RendererShouldAcceptDataListSuggestion(value);
186  } else if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
187    // User selected an Autocomplete, so we fill directly.
188    driver_->RendererShouldFillFieldWithValue(value);
189  } else {
190    FillAutofillFormData(identifier, false);
191  }
192
193  manager_->delegate()->HideAutofillPopup();
194}
195
196void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
197                                                int identifier) {
198  if (identifier > 0)
199    manager_->RemoveAutofillProfileOrCreditCard(identifier);
200  else
201    manager_->RemoveAutocompleteEntry(query_field_.name, value);
202}
203
204void AutofillExternalDelegate::DidEndTextFieldEditing() {
205  manager_->delegate()->HideAutofillPopup();
206
207  has_shown_popup_for_current_edit_ = false;
208}
209
210void AutofillExternalDelegate::ClearPreviewedForm() {
211  driver_->RendererShouldClearPreviewedForm();
212}
213
214void AutofillExternalDelegate::Reset() {
215  manager_->delegate()->HideAutofillPopup();
216
217  password_manager_.Reset();
218}
219
220void AutofillExternalDelegate::AddPasswordFormMapping(
221      const FormFieldData& username_field,
222      const PasswordFormFillData& fill_data) {
223  password_manager_.AddPasswordFormMapping(username_field, fill_data);
224}
225
226base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
227  return weak_ptr_factory_.GetWeakPtr();
228}
229
230void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
231                                                    bool is_preview) {
232  // If the selected element is a warning we don't want to do anything.
233  if (unique_id == POPUP_ITEM_ID_WARNING_MESSAGE)
234    return;
235
236  AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
237      AutofillDriver::FORM_DATA_ACTION_PREVIEW :
238      AutofillDriver::FORM_DATA_ACTION_FILL;
239
240  DCHECK(driver_->RendererIsAvailable());
241  // Fill the values for the whole form.
242  manager_->FillOrPreviewForm(renderer_action,
243                              query_id_,
244                              query_form_,
245                              query_field_,
246                              unique_id);
247}
248
249void AutofillExternalDelegate::ApplyAutofillWarnings(
250    std::vector<base::string16>* values,
251    std::vector<base::string16>* labels,
252    std::vector<base::string16>* icons,
253    std::vector<int>* unique_ids) {
254  if (!query_field_.should_autocomplete) {
255    // Autofill is disabled.  If there were some profile or credit card
256    // suggestions to show, show a warning instead.  Otherwise, clear out the
257    // list of suggestions.
258    if (!unique_ids->empty() && (*unique_ids)[0] > 0) {
259      // If autofill is disabled and we had suggestions, show a warning instead.
260      values->assign(
261          1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
262      labels->assign(1, base::string16());
263      icons->assign(1, base::string16());
264      unique_ids->assign(1, POPUP_ITEM_ID_WARNING_MESSAGE);
265    } else {
266      values->clear();
267      labels->clear();
268      icons->clear();
269      unique_ids->clear();
270    }
271  } else if (unique_ids->size() > 1 &&
272             (*unique_ids)[0] == POPUP_ITEM_ID_WARNING_MESSAGE) {
273    // If we received a warning instead of suggestions from autofill but regular
274    // suggestions from autocomplete, don't show the autofill warning.
275    values->erase(values->begin());
276    labels->erase(labels->begin());
277    icons->erase(icons->begin());
278    unique_ids->erase(unique_ids->begin());
279  }
280
281  // If we were about to show a warning and we shouldn't, don't.
282  if (!unique_ids->empty() &&
283      (*unique_ids)[0] == POPUP_ITEM_ID_WARNING_MESSAGE &&
284      !display_warning_if_disabled_) {
285    values->clear();
286    labels->clear();
287    icons->clear();
288    unique_ids->clear();
289  }
290}
291
292void AutofillExternalDelegate::ApplyAutofillOptions(
293    std::vector<base::string16>* values,
294    std::vector<base::string16>* labels,
295    std::vector<base::string16>* icons,
296    std::vector<int>* unique_ids) {
297  // The form has been auto-filled, so give the user the chance to clear the
298  // form.  Append the 'Clear form' menu item.
299  if (query_field_.is_autofilled) {
300    values->push_back(
301        l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
302    labels->push_back(base::string16());
303    icons->push_back(base::string16());
304    unique_ids->push_back(POPUP_ITEM_ID_CLEAR_FORM);
305  }
306
307  // Append the 'Chrome Autofill options' menu item;
308  values->push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
309  labels->push_back(base::string16());
310  icons->push_back(base::string16());
311  unique_ids->push_back(POPUP_ITEM_ID_AUTOFILL_OPTIONS);
312}
313
314void AutofillExternalDelegate::InsertDataListValues(
315    std::vector<base::string16>* values,
316    std::vector<base::string16>* labels,
317    std::vector<base::string16>* icons,
318    std::vector<int>* unique_ids) {
319  if (data_list_values_.empty())
320    return;
321
322  // Insert the separator between the datalist and Autofill values (if there
323  // are any).
324  if (!values->empty()) {
325    values->insert(values->begin(), base::string16());
326    labels->insert(labels->begin(), base::string16());
327    icons->insert(icons->begin(), base::string16());
328    unique_ids->insert(unique_ids->begin(), POPUP_ITEM_ID_SEPARATOR);
329  }
330
331  // Insert the datalist elements.
332  values->insert(values->begin(),
333                 data_list_values_.begin(),
334                 data_list_values_.end());
335  labels->insert(labels->begin(),
336                 data_list_labels_.begin(),
337                 data_list_labels_.end());
338
339  // Set the values that all datalist elements share.
340  icons->insert(icons->begin(),
341                data_list_values_.size(),
342                base::string16());
343  unique_ids->insert(unique_ids->begin(),
344                     data_list_values_.size(),
345                     POPUP_ITEM_ID_DATALIST_ENTRY);
346}
347
348}  // namespace autofill
349