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