1 // Copyright (c) 2009 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 #import "chrome/browser/ui/login/login_prompt_mac.h" 7 8 #include "base/mac/mac_util.h" 9 #include "base/string_util.h" 10 #include "base/sys_string_conversions.h" 11 #include "base/utf_string_conversions.h" 12 #include "chrome/browser/password_manager/password_manager.h" 13 #include "chrome/browser/tab_contents/tab_util.h" 14 #include "chrome/browser/ui/cocoa/constrained_window_mac.h" 15 #include "chrome/browser/ui/login/login_model.h" 16 #include "content/browser/browser_thread.h" 17 #include "content/browser/renderer_host/resource_dispatcher_host.h" 18 #include "content/browser/tab_contents/navigation_controller.h" 19 #include "content/browser/tab_contents/tab_contents.h" 20 #include "grit/generated_resources.h" 21 #include "net/url_request/url_request.h" 22 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" 23 #include "ui/base/l10n/l10n_util.h" 24 25 using webkit_glue::PasswordForm; 26 27 // ---------------------------------------------------------------------------- 28 // LoginHandlerMac 29 30 // This class simply forwards the authentication from the LoginView (on 31 // the UI thread) to the net::URLRequest (on the I/O thread). 32 // This class uses ref counting to ensure that it lives until all InvokeLaters 33 // have been called. 34 class LoginHandlerMac : public LoginHandler, 35 public ConstrainedWindowMacDelegateCustomSheet { 36 public: 37 LoginHandlerMac(net::AuthChallengeInfo* auth_info, net::URLRequest* request) 38 : LoginHandler(auth_info, request), 39 sheet_controller_(nil) { 40 } 41 42 virtual ~LoginHandlerMac() { 43 } 44 45 // LoginModelObserver implementation. 46 virtual void OnAutofillDataAvailable(const std::wstring& username, 47 const std::wstring& password) { 48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 49 50 [sheet_controller_ autofillLogin:base::SysWideToNSString(username) 51 password:base::SysWideToNSString(password)]; 52 } 53 54 // LoginHandler: 55 virtual void BuildViewForPasswordManager(PasswordManager* manager, 56 const string16& explanation) { 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 58 59 // Load nib here instead of in constructor. 60 sheet_controller_ = [[[LoginHandlerSheet alloc] 61 initWithLoginHandler:this] autorelease]; 62 init([sheet_controller_ window], sheet_controller_, 63 @selector(sheetDidEnd:returnCode:contextInfo:)); 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 SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this)); 75 76 NotifyAuthNeeded(); 77 } 78 79 // Overridden from ConstrainedWindowMacDelegate: 80 virtual void DeleteDelegate() { 81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 82 83 // The constrained window is going to delete itself; clear our pointer. 84 SetDialog(NULL); 85 SetModel(NULL); 86 87 // Close sheet if it's still open, as required by 88 // ConstrainedWindowMacDelegate. 89 if (is_sheet_open()) 90 [NSApp endSheet:sheet()]; 91 92 ReleaseSoon(); 93 } 94 95 void OnLoginPressed(const string16& username, 96 const string16& password) { 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 98 99 SetAuth(username, password); 100 } 101 102 void OnCancelPressed() { 103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 104 105 CancelAuth(); 106 } 107 108 private: 109 friend class LoginPrompt; 110 111 // The Cocoa controller of the GUI. 112 LoginHandlerSheet* sheet_controller_; 113 114 DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac); 115 }; 116 117 // static 118 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info, 119 net::URLRequest* request) { 120 return new LoginHandlerMac(auth_info, request); 121 } 122 123 // ---------------------------------------------------------------------------- 124 // LoginHandlerSheet 125 126 @implementation LoginHandlerSheet 127 128 - (id)initWithLoginHandler:(LoginHandlerMac*)handler { 129 NSString* nibPath = 130 [base::mac::MainAppBundle() pathForResource:@"HttpAuthLoginSheet" 131 ofType:@"nib"]; 132 if ((self = [super initWithWindowNibPath:nibPath 133 owner:self])) { 134 handler_ = handler; 135 } 136 return self; 137 } 138 139 - (void)dealloc { 140 // The buttons could be in a modal loop, so disconnect them so they cannot 141 // call back to us after we're dead. 142 [loginButton_ setTarget:nil]; 143 [cancelButton_ setTarget:nil]; 144 [super dealloc]; 145 } 146 147 - (IBAction)loginPressed:(id)sender { 148 using base::SysNSStringToWide; 149 [NSApp endSheet:[self window]]; 150 handler_->OnLoginPressed( 151 base::SysNSStringToUTF16([nameField_ stringValue]), 152 base::SysNSStringToUTF16([passwordField_ stringValue])); 153 } 154 155 - (IBAction)cancelPressed:(id)sender { 156 [NSApp endSheet:[self window]]; 157 handler_->OnCancelPressed(); 158 } 159 160 - (void)sheetDidEnd:(NSWindow*)sheet 161 returnCode:(int)returnCode 162 contextInfo:(void *)contextInfo { 163 [sheet orderOut:self]; 164 // Also called when user navigates to another page while the sheet is open. 165 } 166 167 - (void)autofillLogin:(NSString*)login password:(NSString*)password { 168 if ([[nameField_ stringValue] length] == 0) { 169 [nameField_ setStringValue:login]; 170 [passwordField_ setStringValue:password]; 171 [nameField_ selectText:self]; 172 } 173 } 174 175 - (void)setExplanation:(NSString*)explanation { 176 // Put in the text. 177 [explanationField_ setStringValue:explanation]; 178 179 // Resize the TextField. 180 CGFloat explanationShift = 181 [GTMUILocalizerAndLayoutTweaker 182 sizeToFitFixedWidthTextField:explanationField_]; 183 184 // Resize the window (no shifting needed due to window layout). 185 NSSize windowDelta = NSMakeSize(0, explanationShift); 186 [GTMUILocalizerAndLayoutTweaker 187 resizeWindowWithoutAutoResizingSubViews:[self window] 188 delta:windowDelta]; 189 } 190 191 @end 192