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