Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / login_prompt_gtk.cc
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/login/login_prompt.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/strings/string16.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/tab_contents/tab_util.h"
12 #include "chrome/browser/ui/gtk/constrained_window_gtk.h"
13 #include "chrome/browser/ui/gtk/gtk_util.h"
14 #include "components/password_manager/core/browser/login_model.h"
15 #include "components/password_manager/core/browser/password_manager.h"
16 #include "components/web_modal/web_contents_modal_dialog_manager.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_contents_delegate.h"
20 #include "grit/generated_resources.h"
21 #include "net/url_request/url_request.h"
22 #include "ui/base/gtk/gtk_hig_constants.h"
23 #include "ui/base/gtk/gtk_signal.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/gfx/gtk_compat.h"
26 #include "ui/gfx/scoped_gobject.h"
27
28 using autofill::PasswordForm;
29 using content::BrowserThread;
30 using content::WebContents;
31 using web_modal::WebContentsModalDialogManager;
32
33 // ----------------------------------------------------------------------------
34 // LoginHandlerGtk
35
36 // This class simply forwards the authentication from the LoginView (on
37 // the UI thread) to the net::URLRequest (on the I/O thread).
38 // This class uses ref counting to ensure that it lives until all InvokeLaters
39 // have been called.
40 class LoginHandlerGtk : public LoginHandler {
41  public:
42   LoginHandlerGtk(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
43       : LoginHandler(auth_info, request),
44         username_entry_(NULL),
45         password_entry_(NULL),
46         ok_(NULL),
47         dialog_(NULL) {
48   }
49
50   // LoginModelObserver implementation.
51   virtual void OnAutofillDataAvailable(
52       const base::string16& username,
53       const base::string16& password) OVERRIDE {
54     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
55
56     // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly
57     // new and not always in our GTK version.
58     if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) {
59       gtk_entry_set_text(GTK_ENTRY(username_entry_),
60                          base::UTF16ToUTF8(username).c_str());
61       gtk_entry_set_text(GTK_ENTRY(password_entry_),
62                          base::UTF16ToUTF8(password).c_str());
63       gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1);
64     }
65   }
66   virtual void OnLoginModelDestroying() OVERRIDE {}
67
68   // LoginHandler:
69   virtual void BuildViewForPasswordManager(
70       PasswordManager* manager,
71       const base::string16& explanation) OVERRIDE {
72     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
73
74     root_.reset(gtk_vbox_new(FALSE, ui::kContentAreaBorder));
75     g_object_ref_sink(root_.get());
76     g_signal_connect(root_.get(), "destroy", G_CALLBACK(OnDestroyThunk), this);
77
78     GtkWidget* label = gtk_label_new(base::UTF16ToUTF8(explanation).c_str());
79     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
80     gtk_box_pack_start(GTK_BOX(root_.get()), label, FALSE, FALSE, 0);
81
82     username_entry_ = gtk_entry_new();
83     gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
84
85     password_entry_ = gtk_entry_new();
86     gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
87     gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
88
89     GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL,
90         l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_USERNAME_FIELD).c_str(),
91         username_entry_,
92         l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_PASSWORD_FIELD).c_str(),
93         password_entry_,
94         NULL);
95     gtk_box_pack_start(GTK_BOX(root_.get()), table, FALSE, FALSE, 0);
96
97     GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
98     gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0);
99
100     ok_ = gtk_button_new_from_stock(GTK_STOCK_OK);
101     gtk_button_set_label(
102         GTK_BUTTON(ok_),
103         l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL).c_str());
104     g_signal_connect(ok_, "clicked", G_CALLBACK(OnOKClickedThunk), this);
105     gtk_box_pack_end(GTK_BOX(hbox), ok_, FALSE, FALSE, 0);
106
107     GtkWidget* cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
108     g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelClickedThunk), this);
109     gtk_box_pack_end(GTK_BOX(hbox), cancel, FALSE, FALSE, 0);
110
111     g_signal_connect(root_.get(), "hierarchy-changed",
112                      G_CALLBACK(OnPromptHierarchyChangedThunk), this);
113
114     SetModel(manager);
115
116     // Scary thread safety note: This can potentially be called *after* SetAuth
117     // or CancelAuth (say, if the request was cancelled before the UI thread got
118     // control).  However, that's OK since any UI interaction in those functions
119     // will occur via an InvokeLater on the UI thread, which is guaranteed
120     // to happen after this is called (since this was InvokeLater'd first).
121     WebContents* requesting_contents = GetWebContentsForLogin();
122     DCHECK(requesting_contents);
123
124     dialog_ = CreateWebContentsModalDialogGtk(root_.get(), username_entry_);
125
126     WebContentsModalDialogManager* web_contents_modal_dialog_manager =
127         WebContentsModalDialogManager::FromWebContents(requesting_contents);
128     web_contents_modal_dialog_manager->ShowDialog(dialog_);
129
130     NotifyAuthNeeded();
131   }
132
133   virtual void CloseDialog() OVERRIDE {
134     // The hosting dialog may have been freed.
135     if (dialog_)
136       gtk_widget_destroy(dialog_);
137   }
138
139  protected:
140   virtual ~LoginHandlerGtk() {
141   }
142
143  private:
144   friend class LoginPrompt;
145
146   CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnOKClicked);
147   CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnCancelClicked);
148   CHROMEGTK_CALLBACK_1(LoginHandlerGtk, void, OnPromptHierarchyChanged,
149                        GtkWidget*);
150   CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnDestroy);
151
152   // The GtkWidgets that form our visual hierarchy:
153   // The root container we pass to our parent.
154   ui::ScopedGObject<GtkWidget>::Type root_;
155
156   // GtkEntry widgets that the user types into.
157   GtkWidget* username_entry_;
158   GtkWidget* password_entry_;
159   GtkWidget* ok_;
160
161   GtkWidget* dialog_;
162
163   DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk);
164 };
165
166 void LoginHandlerGtk::OnOKClicked(GtkWidget* sender) {
167   SetAuth(
168       base::UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
169       base::UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
170 }
171
172 void LoginHandlerGtk::OnCancelClicked(GtkWidget* sender) {
173   CancelAuth();
174 }
175
176 void LoginHandlerGtk::OnPromptHierarchyChanged(GtkWidget* sender,
177                                                GtkWidget* previous_toplevel) {
178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
179
180   if (!gtk_widget_is_toplevel(gtk_widget_get_toplevel(ok_)))
181     return;
182
183   // Now that we have attached ourself to the window, we can make our OK
184   // button the default action and mess with the focus.
185   gtk_widget_set_can_default(ok_, TRUE);
186   gtk_widget_grab_default(ok_);
187 }
188
189 // static
190 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
191                                    net::URLRequest* request) {
192   return new LoginHandlerGtk(auth_info, request);
193 }
194
195 void LoginHandlerGtk::OnDestroy(GtkWidget* widget) {
196   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
197
198   // The web contents modal dialog is going to delete itself; clear our pointer.
199   dialog_ = NULL;
200   SetModel(NULL);
201
202   ReleaseSoon();
203 }