Home | History | Annotate | Download | only in gtk
      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