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