Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / login_prompt_cocoa.mm
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 #import "chrome/browser/ui/cocoa/login_prompt_cocoa.h"
6
7 #include "base/mac/bundle_locations.h"
8 #include "base/mac/mac_util.h"
9 #include "base/mac/scoped_nsobject.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/tab_contents/tab_util.h"
15 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
16 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
17 #include "chrome/browser/ui/login/login_prompt.h"
18 #include "components/password_manager/core/browser/login_model.h"
19 #include "components/password_manager/core/browser/password_manager.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/web_contents.h"
22 #include "grit/generated_resources.h"
23 #include "net/url_request/url_request.h"
24 #include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
25 #include "ui/base/l10n/l10n_util.h"
26
27 using autofill::PasswordForm;
28 using content::BrowserThread;
29 using content::WebContents;
30
31 // ----------------------------------------------------------------------------
32 // LoginHandlerMac
33
34 // This class simply forwards the authentication from the LoginView (on
35 // the UI thread) to the net::URLRequest (on the I/O thread).
36 // This class uses ref counting to ensure that it lives until all InvokeLaters
37 // have been called.
38 class LoginHandlerMac : public LoginHandler,
39                         public ConstrainedWindowMacDelegate {
40  public:
41   LoginHandlerMac(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
42       : LoginHandler(auth_info, request) {
43   }
44
45   // LoginModelObserver implementation.
46   virtual void OnAutofillDataAvailable(
47       const base::string16& username,
48       const base::string16& password) OVERRIDE {
49     DCHECK_CURRENTLY_ON(BrowserThread::UI);
50
51     [sheet_controller_ autofillLogin:base::SysUTF16ToNSString(username)
52                             password:base::SysUTF16ToNSString(password)];
53   }
54   virtual void OnLoginModelDestroying() OVERRIDE {}
55
56   // LoginHandler:
57   virtual void BuildViewForPasswordManager(
58       password_manager::PasswordManager* manager,
59       const base::string16& explanation) OVERRIDE {
60     DCHECK_CURRENTLY_ON(BrowserThread::UI);
61
62     sheet_controller_.reset(
63         [[LoginHandlerSheet alloc] initWithLoginHandler:this]);
64
65     SetModel(manager);
66
67     [sheet_controller_ setExplanation:base::SysUTF16ToNSString(explanation)];
68
69     // Scary thread safety note: This can potentially be called *after* SetAuth
70     // or CancelAuth (say, if the request was cancelled before the UI thread got
71     // control).  However, that's OK since any UI interaction in those functions
72     // will occur via an InvokeLater on the UI thread, which is guaranteed
73     // to happen after this is called (since this was InvokeLater'd first).
74     WebContents* requesting_contents = GetWebContentsForLogin();
75     DCHECK(requesting_contents);
76
77     base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
78         [[CustomConstrainedWindowSheet alloc]
79             initWithCustomWindow:[sheet_controller_ window]]);
80     constrained_window_.reset(new ConstrainedWindowMac(
81         this, requesting_contents, sheet));
82
83     NotifyAuthNeeded();
84   }
85
86   virtual void CloseDialog() OVERRIDE {
87     // The hosting dialog may have been freed.
88     if (constrained_window_)
89       constrained_window_->CloseWebContentsModalDialog();
90   }
91
92   // Overridden from ConstrainedWindowMacDelegate:
93   virtual void OnConstrainedWindowClosed(
94       ConstrainedWindowMac* window) OVERRIDE {
95     DCHECK_CURRENTLY_ON(BrowserThread::UI);
96     SetModel(NULL);
97     ReleaseSoon();
98
99     constrained_window_.reset();
100     sheet_controller_.reset();
101   }
102
103   void OnLoginPressed(const base::string16& username,
104                       const base::string16& password) {
105     DCHECK_CURRENTLY_ON(BrowserThread::UI);
106     SetAuth(username, password);
107   }
108
109   void OnCancelPressed() {
110     DCHECK_CURRENTLY_ON(BrowserThread::UI);
111     CancelAuth();
112   }
113
114  private:
115   friend class LoginPrompt;
116
117   virtual ~LoginHandlerMac() {
118     // This class will be deleted on a non UI thread. Ensure that the UI members
119     // have already been deleted.
120     CHECK(!constrained_window_.get());
121     CHECK(!sheet_controller_.get());
122   }
123
124   // The Cocoa controller of the GUI.
125   base::scoped_nsobject<LoginHandlerSheet> sheet_controller_;
126
127   scoped_ptr<ConstrainedWindowMac> constrained_window_;
128
129   DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
130 };
131
132 // static
133 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
134                                    net::URLRequest* request) {
135   return new LoginHandlerMac(auth_info, request);
136 }
137
138 // ----------------------------------------------------------------------------
139 // LoginHandlerSheet
140
141 @implementation LoginHandlerSheet
142
143 - (id)initWithLoginHandler:(LoginHandlerMac*)handler {
144   NSString* nibPath =
145       [base::mac::FrameworkBundle() pathForResource:@"HttpAuthLoginSheet"
146                                              ofType:@"nib"];
147   if ((self = [super initWithWindowNibPath:nibPath
148                                      owner:self])) {
149     handler_ = handler;
150     // Force the nib to load so that all outlets are initialized.
151     [self window];
152   }
153   return self;
154 }
155
156 - (void)dealloc {
157   // The buttons could be in a modal loop, so disconnect them so they cannot
158   // call back to us after we're dead.
159   [loginButton_ setTarget:nil];
160   [cancelButton_ setTarget:nil];
161   [super dealloc];
162 }
163
164 - (IBAction)loginPressed:(id)sender {
165   handler_->OnLoginPressed(
166       base::SysNSStringToUTF16([nameField_ stringValue]),
167       base::SysNSStringToUTF16([passwordField_ stringValue]));
168 }
169
170 - (IBAction)cancelPressed:(id)sender {
171   handler_->OnCancelPressed();
172 }
173
174 - (void)autofillLogin:(NSString*)login password:(NSString*)password {
175   if ([[nameField_ stringValue] length] == 0) {
176     [nameField_ setStringValue:login];
177     [passwordField_ setStringValue:password];
178     [nameField_ selectText:self];
179   }
180 }
181
182 - (void)setExplanation:(NSString*)explanation {
183   // Put in the text.
184   [explanationField_ setStringValue:explanation];
185
186   // Resize the text field.
187   CGFloat windowDelta = [GTMUILocalizerAndLayoutTweaker
188        sizeToFitFixedWidthTextField:explanationField_];
189
190   NSRect newFrame = [[self window] frame];
191   newFrame.size.height += windowDelta;
192   [[self window] setFrame:newFrame display:NO];
193 }
194
195 @end