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 25using 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. 34class 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 118LoginHandler* 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