1 // Copyright (c) 2012 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 "chrome/browser/ui/gtk/password_generation_bubble_gtk.h" 6 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/password_manager/password_manager.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/ui/browser.h" 11 #include "chrome/browser/ui/browser_finder.h" 12 #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" 13 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" 14 #include "chrome/browser/ui/gtk/gtk_theme_service.h" 15 #include "chrome/browser/ui/gtk/gtk_util.h" 16 #include "chrome/common/url_constants.h" 17 #include "components/autofill/core/browser/password_generator.h" 18 #include "components/autofill/core/common/autofill_messages.h" 19 #include "content/public/browser/render_view_host.h" 20 #include "content/public/browser/web_contents.h" 21 #include "content/public/browser/web_contents_view.h" 22 #include "grit/generated_resources.h" 23 #include "grit/theme_resources.h" 24 #include "ui/base/gtk/gtk_hig_constants.h" 25 #include "ui/base/l10n/l10n_util.h" 26 #include "ui/base/resource/resource_bundle.h" 27 28 using content::RenderViewHost; 29 30 namespace { 31 32 GdkPixbuf* GetImage(int resource_id) { 33 if (!resource_id) 34 return NULL; 35 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( 36 resource_id, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf(); 37 } 38 39 } // namespace 40 41 PasswordGenerationBubbleGtk::PasswordGenerationBubbleGtk( 42 const gfx::Rect& anchor_rect, 43 const content::PasswordForm& form, 44 content::WebContents* web_contents, 45 autofill::PasswordGenerator* password_generator) 46 : form_(form), 47 web_contents_(web_contents), 48 password_generator_(password_generator) { 49 // TODO(gcasto): Localize text after we have finalized the UI. 50 // crbug.com/118062 51 GtkWidget* content = gtk_vbox_new(FALSE, 5); 52 53 // We have two lines of content. The first is the title and learn more link. 54 GtkWidget* title_line = gtk_hbox_new(FALSE, 0); 55 GtkWidget* title = gtk_label_new( 56 l10n_util::GetStringUTF8(IDS_PASSWORD_GENERATION_BUBBLE_TITLE).c_str()); 57 gtk_box_pack_start(GTK_BOX(title_line), title, FALSE, FALSE, 0); 58 GtkWidget* learn_more_link = gtk_chrome_link_button_new( 59 l10n_util::GetStringUTF8(IDS_LEARN_MORE).c_str()); 60 gtk_button_set_alignment(GTK_BUTTON(learn_more_link), 0.0, 0.5); 61 gtk_box_pack_start(GTK_BOX(title_line), 62 gtk_util::IndentWidget(learn_more_link), 63 FALSE, FALSE, 0); 64 65 // The second contains the password in a text field, a regenerate button, and 66 // an accept button. 67 GtkWidget* password_line = gtk_hbox_new(FALSE, ui::kControlSpacing); 68 text_field_ = gtk_entry_new(); 69 gtk_entry_set_text(GTK_ENTRY(text_field_), 70 password_generator_->Generate().c_str()); 71 gtk_entry_set_max_length(GTK_ENTRY(text_field_), 15); 72 gtk_entry_set_icon_from_pixbuf( 73 GTK_ENTRY(text_field_), GTK_ENTRY_ICON_SECONDARY, GetImage(IDR_RELOAD)); 74 gtk_entry_set_icon_tooltip_text( 75 GTK_ENTRY(text_field_), GTK_ENTRY_ICON_SECONDARY, "Regenerate"); 76 GtkWidget* accept_button = gtk_button_new_with_label( 77 l10n_util::GetStringUTF8(IDS_PASSWORD_GENERATION_BUTTON_TEXT).c_str()); 78 gtk_box_pack_start(GTK_BOX(password_line), text_field_, TRUE, TRUE, 0); 79 gtk_box_pack_start(GTK_BOX(password_line), accept_button, TRUE, TRUE, 0); 80 81 gtk_container_set_border_width(GTK_CONTAINER(content), 82 ui::kContentAreaBorder); 83 gtk_box_pack_start(GTK_BOX(content), title_line, TRUE, TRUE, 0); 84 gtk_box_pack_start(GTK_BOX(content), password_line, TRUE, TRUE, 0); 85 86 // Set initial focus to the text field containing the generated password. 87 gtk_widget_grab_focus(text_field_); 88 89 GtkThemeService* theme_service = GtkThemeService::GetFrom( 90 Profile::FromBrowserContext(web_contents->GetBrowserContext())); 91 92 bubble_ = BubbleGtk::Show(web_contents->GetView()->GetContentNativeView(), 93 &anchor_rect, 94 content, 95 BubbleGtk::ANCHOR_TOP_LEFT, 96 BubbleGtk::MATCH_SYSTEM_THEME | 97 BubbleGtk::POPUP_WINDOW | 98 BubbleGtk::GRAB_INPUT, 99 theme_service, 100 this); // delegate 101 102 g_signal_connect(content, "destroy", 103 G_CALLBACK(&OnDestroyThunk), this); 104 g_signal_connect(accept_button, "clicked", 105 G_CALLBACK(&OnAcceptClickedThunk), this); 106 g_signal_connect(text_field_, "icon-press", 107 G_CALLBACK(&OnRegenerateClickedThunk), this); 108 g_signal_connect(text_field_, "changed", 109 G_CALLBACK(&OnPasswordEditedThunk), this); 110 g_signal_connect(learn_more_link, "clicked", 111 G_CALLBACK(OnLearnMoreLinkClickedThunk), this); 112 } 113 114 PasswordGenerationBubbleGtk::~PasswordGenerationBubbleGtk() {} 115 116 void PasswordGenerationBubbleGtk::BubbleClosing(BubbleGtk* bubble, 117 bool closed_by_escape) { 118 autofill::password_generation::LogUserActions(actions_); 119 } 120 121 void PasswordGenerationBubbleGtk::OnDestroy(GtkWidget* widget) { 122 // We are self deleting, we have a destroy signal setup to catch when we are 123 // destroyed (via the BubbleGtk being destroyed), and delete ourself. 124 delete this; 125 } 126 127 void PasswordGenerationBubbleGtk::OnAcceptClicked(GtkWidget* widget) { 128 actions_.password_accepted = true; 129 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost(); 130 render_view_host->Send(new AutofillMsg_GeneratedPasswordAccepted( 131 render_view_host->GetRoutingID(), 132 UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(text_field_))))); 133 PasswordManager::FromWebContents(web_contents_)-> 134 SetFormHasGeneratedPassword(form_); 135 bubble_->Close(); 136 } 137 138 void PasswordGenerationBubbleGtk::OnRegenerateClicked( 139 GtkWidget* widget, 140 GtkEntryIconPosition icon_pos, 141 GdkEvent* event) { 142 gtk_entry_set_text(GTK_ENTRY(text_field_), 143 password_generator_->Generate().c_str()); 144 actions_.password_regenerated = true; 145 } 146 147 void PasswordGenerationBubbleGtk::OnPasswordEdited(GtkWidget* widget) { 148 actions_.password_edited = true; 149 } 150 151 void PasswordGenerationBubbleGtk::OnLearnMoreLinkClicked(GtkButton* button) { 152 actions_.learn_more_visited = true; 153 Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); 154 content::OpenURLParams params( 155 GURL(chrome::kAutoPasswordGenerationLearnMoreURL), content::Referrer(), 156 NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, false); 157 browser->OpenURL(params); 158 bubble_->Close(); 159 } 160