blob: a211af64ba08d89e4f59551222a09ffa56e410c7 [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/login_prompt.h"
#import "chrome/browser/login_prompt_mac.h"
#include "app/l10n_util.h"
#include "base/mac_util.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/cocoa/constrained_window_mac.h"
#include "chrome/browser/login_model.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "net/url_request/url_request.h"
#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
using webkit_glue::PasswordForm;
// ----------------------------------------------------------------------------
// LoginHandlerMac
// This class simply forwards the authentication from the LoginView (on
// the UI thread) to the URLRequest (on the I/O thread).
// This class uses ref counting to ensure that it lives until all InvokeLaters
// have been called.
class LoginHandlerMac : public LoginHandler,
public ConstrainedWindowMacDelegateCustomSheet {
public:
LoginHandlerMac(net::AuthChallengeInfo* auth_info, URLRequest* request)
: LoginHandler(auth_info, request),
sheet_controller_(nil) {
}
virtual ~LoginHandlerMac() {
}
// LoginModelObserver implementation.
virtual void OnAutofillDataAvailable(const std::wstring& username,
const std::wstring& password) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
[sheet_controller_ autofillLogin:base::SysWideToNSString(username)
password:base::SysWideToNSString(password)];
}
// LoginHandler:
virtual void BuildViewForPasswordManager(PasswordManager* manager,
std::wstring explanation) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// Load nib here instead of in constructor.
sheet_controller_ = [[[LoginHandlerSheet alloc]
initWithLoginHandler:this] autorelease];
init([sheet_controller_ window], sheet_controller_,
@selector(sheetDidEnd:returnCode:contextInfo:));
SetModel(manager);
[sheet_controller_ setExplanation:base::SysWideToNSString(explanation)];
// Scary thread safety note: This can potentially be called *after* SetAuth
// or CancelAuth (say, if the request was cancelled before the UI thread got
// control). However, that's OK since any UI interaction in those functions
// will occur via an InvokeLater on the UI thread, which is guaranteed
// to happen after this is called (since this was InvokeLater'd first).
SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
NotifyAuthNeeded();
}
// Overridden from ConstrainedWindowMacDelegate:
virtual void DeleteDelegate() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// The constrained window is going to delete itself; clear our pointer.
SetDialog(NULL);
SetModel(NULL);
// Close sheet if it's still open, as required by
// ConstrainedWindowMacDelegate.
if (is_sheet_open())
[NSApp endSheet:sheet()];
ReleaseSoon();
}
void OnLoginPressed(const std::wstring& username,
const std::wstring& password) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
SetAuth(username, password);
}
void OnCancelPressed() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
CancelAuth();
}
private:
friend class LoginPrompt;
// The Cocoa controller of the GUI.
LoginHandlerSheet* sheet_controller_;
DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
};
// static
LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
URLRequest* request) {
return new LoginHandlerMac(auth_info, request);
}
// ----------------------------------------------------------------------------
// LoginHandlerSheet
@implementation LoginHandlerSheet
- (id)initWithLoginHandler:(LoginHandlerMac*)handler {
NSString* nibPath =
[mac_util::MainAppBundle() pathForResource:@"HttpAuthLoginSheet"
ofType:@"nib"];
if ((self = [super initWithWindowNibPath:nibPath
owner:self])) {
handler_ = handler;
}
return self;
}
- (void)dealloc {
// The buttons could be in a modal loop, so disconnect them so they cannot
// call back to us after we're dead.
[loginButton_ setTarget:nil];
[cancelButton_ setTarget:nil];
[super dealloc];
}
- (IBAction)loginPressed:(id)sender {
using base::SysNSStringToWide;
[NSApp endSheet:[self window]];
handler_->OnLoginPressed(SysNSStringToWide([nameField_ stringValue]),
SysNSStringToWide([passwordField_ stringValue]));
}
- (IBAction)cancelPressed:(id)sender {
[NSApp endSheet:[self window]];
handler_->OnCancelPressed();
}
- (void)sheetDidEnd:(NSWindow*)sheet
returnCode:(int)returnCode
contextInfo:(void *)contextInfo {
[sheet orderOut:self];
// Also called when user navigates to another page while the sheet is open.
}
- (void)autofillLogin:(NSString*)login password:(NSString*)password {
if ([[nameField_ stringValue] length] == 0) {
[nameField_ setStringValue:login];
[passwordField_ setStringValue:password];
[nameField_ selectText:self];
}
}
- (void)setExplanation:(NSString*)explanation {
// Put in the text.
[explanationField_ setStringValue:explanation];
// Resize the TextField.
CGFloat explanationShift =
[GTMUILocalizerAndLayoutTweaker
sizeToFitFixedWidthTextField:explanationField_];
// Resize the window (no shifting needed due to window layout).
NSSize windowDelta = NSMakeSize(0, explanationShift);
[GTMUILocalizerAndLayoutTweaker
resizeWindowWithoutAutoResizingSubViews:[self window]
delta:windowDelta];
}
@end