autofill_external_delegate.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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
160bool AutofillExternalDelegate::ShouldRepostEvent(const ui::MouseEvent& event) {
161  NOTREACHED();
162  return true;
163}
164
165void AutofillExternalDelegate::DidSelectSuggestion(
166    const base::string16& value,
167    int identifier) {
168  ClearPreviewedForm();
169
170  // Only preview the data if it is a profile.
171  if (identifier > 0)
172    FillAutofillFormData(identifier, true);
173  else if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)
174    driver_->RendererShouldPreviewFieldWithValue(value);
175}
176
177void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
178                                                   int identifier) {
179  if (identifier == POPUP_ITEM_ID_AUTOFILL_OPTIONS) {
180    // User selected 'Autofill Options'.
181    manager_->ShowAutofillSettings();
182  } else if (identifier == POPUP_ITEM_ID_CLEAR_FORM) {
183    // User selected 'Clear form'.
184    driver_->RendererShouldClearFilledForm();
185  } else if (identifier == POPUP_ITEM_ID_PASSWORD_ENTRY) {
186    bool success = password_manager_.DidAcceptAutofillSuggestion(
187        query_field_, value);
188    DCHECK(success);
189  } else if (identifier == POPUP_ITEM_ID_DATALIST_ENTRY) {
190    driver_->RendererShouldAcceptDataListSuggestion(value);
191  } else if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
192    // User selected an Autocomplete, so we fill directly.
193    driver_->RendererShouldFillFieldWithValue(value);
194  } else {
195    FillAutofillFormData(identifier, false);
196  }
197
198  manager_->delegate()->HideAutofillPopup();
199}
200
201void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
202                                                int identifier) {
203  if (identifier > 0)
204    manager_->RemoveAutofillProfileOrCreditCard(identifier);
205  else
206    manager_->RemoveAutocompleteEntry(query_field_.name, value);
207}
208
209void AutofillExternalDelegate::DidEndTextFieldEditing() {
210  manager_->delegate()->HideAutofillPopup();
211
212  has_shown_popup_for_current_edit_ = false;
213}
214
215void AutofillExternalDelegate::ClearPreviewedForm() {
216  driver_->RendererShouldClearPreviewedForm();
217}
218
219void AutofillExternalDelegate::Reset() {
220  manager_->delegate()->HideAutofillPopup();
221
222  password_manager_.Reset();
223}
224
225void AutofillExternalDelegate::AddPasswordFormMapping(
226      const FormFieldData& username_field,
227      const PasswordFormFillData& fill_data) {
228  password_manager_.AddPasswordFormMapping(username_field, fill_data);
229}
230
231base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
232  return weak_ptr_factory_.GetWeakPtr();
233}
234
235void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
236                                                    bool is_preview) {
237  // If the selected element is a warning we don't want to do anything.
238  if (unique_id == POPUP_ITEM_ID_WARNING_MESSAGE)
239    return;
240
241  AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
242      AutofillDriver::FORM_DATA_ACTION_PREVIEW :
243      AutofillDriver::FORM_DATA_ACTION_FILL;
244
245  DCHECK(driver_->RendererIsAvailable());
246  // Fill the values for the whole form.
247  manager_->FillOrPreviewForm(renderer_action,
248                              query_id_,
249                              query_form_,
250                              query_field_,
251                              unique_id);
252}
253
254void AutofillExternalDelegate::ApplyAutofillWarnings(
255    std::vector<base::string16>* values,
256    std::vector<base::string16>* labels,
257    std::vector<base::string16>* icons,
258    std::vector<int>* unique_ids) {
259  if (!query_field_.should_autocomplete) {
260    // Autofill is disabled.  If there were some profile or credit card
261    // suggestions to show, show a warning instead.  Otherwise, clear out the
262    // list of suggestions.
263    if (!unique_ids->empty() && (*unique_ids)[0] > 0) {
264      // If autofill is disabled and we had suggestions, show a warning instead.
265      values->assign(
266          1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
267      labels->assign(1, base::string16());
268      icons->assign(1, base::string16());
269      unique_ids->assign(1, POPUP_ITEM_ID_WARNING_MESSAGE);
270    } else {
271      values->clear();
272      labels->clear();
273      icons->clear();
274      unique_ids->clear();
275    }
276  } else if (unique_ids->size() > 1 &&
277             (*unique_ids)[0] == POPUP_ITEM_ID_WARNING_MESSAGE) {
278    // If we received a warning instead of suggestions from autofill but regular
279    // suggestions from autocomplete, don't show the autofill warning.
280    values->erase(values->begin());
281    labels->erase(labels->begin());
282    icons->erase(icons->begin());
283    unique_ids->erase(unique_ids->begin());
284  }
285
286  // If we were about to show a warning and we shouldn't, don't.
287  if (!unique_ids->empty() &&
288      (*unique_ids)[0] == POPUP_ITEM_ID_WARNING_MESSAGE &&
289      !display_warning_if_disabled_) {
290    values->clear();
291    labels->clear();
292    icons->clear();
293    unique_ids->clear();
294  }
295}
296
297void AutofillExternalDelegate::ApplyAutofillOptions(
298    std::vector<base::string16>* values,
299    std::vector<base::string16>* labels,
300    std::vector<base::string16>* icons,
301    std::vector<int>* unique_ids) {
302  // The form has been auto-filled, so give the user the chance to clear the
303  // form.  Append the 'Clear form' menu item.
304  if (query_field_.is_autofilled) {
305    values->push_back(
306        l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
307    labels->push_back(base::string16());
308    icons->push_back(base::string16());
309    unique_ids->push_back(POPUP_ITEM_ID_CLEAR_FORM);
310  }
311
312  // Append the 'Chrome Autofill options' menu item;
313  values->push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
314  labels->push_back(base::string16());
315  icons->push_back(base::string16());
316  unique_ids->push_back(POPUP_ITEM_ID_AUTOFILL_OPTIONS);
317}
318
319void AutofillExternalDelegate::InsertDataListValues(
320    std::vector<base::string16>* values,
321    std::vector<base::string16>* labels,
322    std::vector<base::string16>* icons,
323    std::vector<int>* unique_ids) {
324  if (data_list_values_.empty())
325    return;
326
327  // Insert the separator between the datalist and Autofill values (if there
328  // are any).
329  if (!values->empty()) {
330    values->insert(values->begin(), base::string16());
331    labels->insert(labels->begin(), base::string16());
332    icons->insert(icons->begin(), base::string16());
333    unique_ids->insert(unique_ids->begin(), POPUP_ITEM_ID_SEPARATOR);
334  }
335
336  // Insert the datalist elements.
337  values->insert(values->begin(),
338                 data_list_values_.begin(),
339                 data_list_values_.end());
340  labels->insert(labels->begin(),
341                 data_list_labels_.begin(),
342                 data_list_labels_.end());
343
344  // Set the values that all datalist elements share.
345  icons->insert(icons->begin(),
346                data_list_values_.size(),
347                base::string16());
348  unique_ids->insert(unique_ids->begin(),
349                     data_list_values_.size(),
350                     POPUP_ITEM_ID_DATALIST_ENTRY);
351}
352
353}  // namespace autofill
354