SelectIdentityController.m [plain text]
/*
* Copyright 2008 Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*/
#import "SelectIdentityController.h"
#import "IPCClient.h"
#import "KerberosFormatters.h"
@implementation SelectIdentityController
@synthesize associatedClient;
// ---------------------------------------------------------------------------
- (id) init
{
return [self initWithWindowNibName: @"SelectIdentity"];
}
// ---------------------------------------------------------------------------
- (void) dealloc
{
[identityOptionsController removeObserver:self forKeyPath:identity_string_keypath];
[refreshTimer release];
[identities release];
[super dealloc];
}
// ---------------------------------------------------------------------------
- (void) awakeFromNib
{
NSString *key = nil;
NSString *message = nil;
[[self window] center];
[[self window] setLevel:NSModalPanelWindowLevel];
longTimeFormatter.displaySeconds = NO;
longTimeFormatter.displayShortFormat = NO;
[identityTableView setDoubleAction:@selector(select:)];
identities = [[Identities alloc] init];
[identitiesController setContent:identities];
refreshTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(timedRefresh:) userInfo:nil repeats:true];
[kerberosIconImageView setBadgePath:associatedClient.path];
if ([associatedClient.name isEqualToString:[[NSBundle mainBundle] bundlePath]]) {
key = @"SelectIdentityRequest";
message = NSLocalizedStringFromTable(key, @"SelectIdentity", NULL);
}
else {
key = @"SelectIdentityApplicationRequest";
message = [NSString stringWithFormat:
NSLocalizedStringFromTable(key, @"SelectIdentity", NULL),
associatedClient.name];
}
[headerTextField setStringValue:message];
optionsBoxHeight = [ticketOptionsBox frame].size.height + [ticketOptionsBox frame].origin.y - [ticketOptionsToggleButton frame].origin.y - [ticketOptionsToggleButton frame].size.height;
[self toggleOptionsVisibility:nil];
[identityOptionsController addObserver:self
forKeyPath:identity_string_keypath
options:NSKeyValueObservingOptionNew
context:NULL];
}
- (void) observeValueForKeyPath:(NSString *) keyPath ofObject: (id) object change: (NSDictionary *) change context:(void *) context
{
if (object == identityOptionsController && [keyPath isEqualToString:identity_string_keypath]) {
BOOL enabled = [KIMUtilities validateIdentity:[identityOptionsController valueForKeyPath:identity_string_keypath]];
[identityOptionsController setValue:[NSNumber numberWithBool:enabled]
forKeyPath:@"content.canClickOK"];
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
// ---------------------------------------------------------------------------
- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
{
NSRect newFrame = [window frame];
CGFloat oldHeight = [[identityTableScrollView contentView] frame].size.height;
CGFloat newHeight = [identityTableView numberOfRows] *
([identityTableView rowHeight] + [identityTableView intercellSpacing].height);
CGFloat yDelta = newHeight - oldHeight;
newFrame.origin.y -= yDelta;
newFrame.size.height += yDelta;
return newFrame;
}
// ---------------------------------------------------------------------------
- (void) setContent: (NSMutableDictionary *) newContent
{
[self window]; // wake up the nib connections
[glueController setContent:newContent];
}
// ---------------------------------------------------------------------------
- (IBAction) newIdentity: (id) sender
{
identityOptionsController.content = [[[glueController valueForKeyPath:@"content.hints.options"]
mutableCopy] autorelease];
[self showOptions:@"new"];
}
// ---------------------------------------------------------------------------
- (IBAction) addToFavorites: (id) sender
{
Identity *anIdentity = [identityArrayController.selectedObjects lastObject];
identityOptionsController.content = nil;
anIdentity.favorite = TRUE;
[self saveOptions];
}
// ---------------------------------------------------------------------------
- (IBAction) removeFromFavorites: (id) sender
{
Identity *anIdentity = [identityArrayController.selectedObjects lastObject];
identityOptionsController.content = nil;
anIdentity.favorite = FALSE;
[self saveOptions];
}
// ---------------------------------------------------------------------------
- (IBAction) changePassword: (id) sender
{
Identity *selectedIdentity = nil;
// ignore double-click on header
if ([sender respondsToSelector:@selector(clickedRow)] && [sender clickedRow] < 0) {
return;
}
selectedIdentity = [[identityArrayController selectedObjects] lastObject];
[associatedClient didSelectIdentity: selectedIdentity.identity
options: [identityOptionsController valueForKeyPath:@"content.options"]
wantsChangePassword: YES];
}
// ---------------------------------------------------------------------------
- (IBAction) select: (id) sender
{
Identity *selectedIdentity = nil;
// ignore double-click on header
if ([sender respondsToSelector:@selector(clickedRow)] && [sender clickedRow] < 0) {
return;
}
selectedIdentity = [[identityArrayController selectedObjects] lastObject];
[associatedClient didSelectIdentity: selectedIdentity.identity
options: [identityOptionsController content]
wantsChangePassword: NO];
}
// ---------------------------------------------------------------------------
- (IBAction) cancel: (id) sender
{
[associatedClient didCancel];
}
// ---------------------------------------------------------------------------
- (IBAction) editOptions: (id) sender
{
Identity *anIdentity = [identityArrayController.selectedObjects lastObject];
anIdentity.favorite = TRUE;
[identityOptionsController setContent:anIdentity.options];
[self showOptions:@"edit"];
}
// ---------------------------------------------------------------------------
- (IBAction) cancelOptions: (id) sender
{
identityOptionsController.content = nil;
[NSApp endSheet:ticketOptionsWindow returnCode:NSUserCancelledError];
// dump changed settings
[identities reload];
}
// ---------------------------------------------------------------------------
- (IBAction) doneOptions: (id) sender
{
// Identity *anIdentity = identityOptionsController.content;
[NSApp endSheet: ticketOptionsWindow];
}
// ---------------------------------------------------------------------------
- (IBAction) checkboxDidChange: (id) sender
{
if ([[identityOptionsController valueForKeyPath:uses_default_options_keypath] boolValue]) {
// merge defaults onto current options
NSMutableDictionary *currentOptions = [identityOptionsController content];
NSDictionary *defaultOptions = [KIMUtilities dictionaryForKimOptions:NULL];
NSLog(@"using default ticket options");
[currentOptions addEntriesFromDictionary:defaultOptions];
// update the sliders, since their values aren't bound
[validLifetimeSlider setDoubleValue:[[identityOptionsController valueForKeyPath:valid_lifetime_keypath] doubleValue]];
[renewableLifetimeSlider setDoubleValue:[[identityOptionsController valueForKeyPath:renewal_lifetime_keypath] doubleValue]];
}
}
// ---------------------------------------------------------------------------
- (IBAction) sliderDidChange: (id) sender
{
NSInteger increment = 0;
NSInteger newValue = 0;
NSString *keyPath = nil;
if ([sender isEqual:validLifetimeSlider]) {
increment = VALID_LIFETIME_INCREMENT;
keyPath = valid_lifetime_keypath;
}
else if ([sender isEqual:renewableLifetimeSlider]) {
increment = RENEWABLE_LIFETIME_INCREMENT;
keyPath = renewal_lifetime_keypath;
}
if (increment > 0) {
newValue = ([sender integerValue] / increment) * increment;
[identityOptionsController setValue:[NSNumber numberWithInteger:
(newValue < increment) ? increment : newValue]
forKeyPath:keyPath];
}
}
// ---------------------------------------------------------------------------
- (void) showOptions: (NSString *) contextInfo
{
Identity *anIdentity = [[identityArrayController selectedObjects] lastObject];
BOOL isIdentityNameNotEditable = (!anIdentity.hasCCache || [contextInfo isEqualToString:@"new"]);
NSString *identityString = ([contextInfo isEqualToString:@"new"]) ? @"" : anIdentity.identity;
[identityOptionsController setValue:identityString
forKeyPath:identity_string_keypath];
[identityOptionsController setValue:[NSNumber numberWithInteger:[KIMUtilities minValidLifetime]]
forKeyPath:min_valid_keypath];
[identityOptionsController setValue:[NSNumber numberWithInteger:[KIMUtilities maxValidLifetime]]
forKeyPath:max_valid_keypath];
[identityOptionsController setValue:[NSNumber numberWithInteger:[KIMUtilities minRenewableLifetime]]
forKeyPath:min_renewable_keypath];
[identityOptionsController setValue:[NSNumber numberWithInteger:[KIMUtilities maxRenewableLifetime]]
forKeyPath:max_renewable_keypath];
[identityOptionsController setValue:[NSNumber numberWithBool:!isIdentityNameNotEditable]
forKeyPath:@"content.hasCCache"];
[validLifetimeSlider setIntegerValue:
[[identityOptionsController valueForKeyPath:valid_lifetime_keypath] integerValue]];
[renewableLifetimeSlider setIntegerValue:
[[identityOptionsController valueForKeyPath:renewal_lifetime_keypath] integerValue]];
[self sliderDidChange:validLifetimeSlider];
[self sliderDidChange:renewableLifetimeSlider];
[NSApp beginSheet: ticketOptionsWindow
modalForWindow: [self window]
modalDelegate: self
didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
contextInfo: contextInfo];
}
// ---------------------------------------------------------------------------
- (void) didEndSheet: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo
{
kim_error err = KIM_NO_ERROR;
if (returnCode != NSUserCancelledError) {
if ([(NSString *)contextInfo isEqualToString:@"new"]) {
Identity *newIdentity = [[Identity alloc]
initWithIdentity:[identityOptionsController valueForKeyPath:identity_string_keypath]
options:identityOptionsController.content];
newIdentity.favorite = YES;
err = [identities addIdentity:newIdentity];
if (err) {
NSLog(@" }
[newIdentity release];
[self saveOptions];
}
else if ([(NSString *)contextInfo isEqualToString:@"edit"]) {
Identity *editedIdentity = [[identityArrayController selectedObjects] lastObject];
editedIdentity.favorite = YES;
editedIdentity.identity = [identityOptionsController valueForKeyPath:identity_string_keypath];
editedIdentity.options = identityOptionsController.content;
[self saveOptions];
}
} else {
[identityOptionsController setContent:nil];
}
[sheet orderOut:self];
}
// ---------------------------------------------------------------------------
- (void) saveOptions
{
// attempt to preserve the selection
Identity *anIdentity = [[identityArrayController selectedObjects] lastObject];
NSUInteger a, b, c;
a = [identityArrayController.content indexOfObject: anIdentity];
b = NSNotFound;
[identities synchronizePreferences];
/*
* select same object as before if it's still in the array
* if not, select same index as before or end of array, whichever is less
*/
b = [identityArrayController.content indexOfObject:anIdentity];
c = [identityArrayController.content count] - 1;
[identityArrayController setSelectionIndex: (b == NSNotFound) ? (a > c) ? c : a : b];
}
// ---------------------------------------------------------------------------
- (IBAction) toggleOptionsVisibility: (id) sender
{
NSRect newFrame = [NSWindow contentRectForFrameRect:[ticketOptionsWindow frame] styleMask:[ticketOptionsWindow styleMask]];
CGFloat newHeight;
if ([ticketOptionsBox isHidden]) {
newHeight = newFrame.size.height + optionsBoxHeight;
newFrame.origin.y += newFrame.size.height;
newFrame.origin.y -= newHeight;
newFrame.size.height = newHeight;
newFrame = [NSWindow frameRectForContentRect:newFrame styleMask:[ticketOptionsWindow styleMask]];
[ticketOptionsWindow setFrame:newFrame display:YES animate:YES];
[ticketOptionsBox setHidden:NO];
[sender setTitle:NSLocalizedStringFromTable(@"SelectIdentityHideOptions", @"SelectIdentity", NULL)];
}
else {
newHeight = newFrame.size.height - optionsBoxHeight;
newFrame.origin.y += newFrame.size.height;
newFrame.origin.y -= newHeight;
newFrame.size.height = newHeight;
newFrame = [NSWindow frameRectForContentRect:newFrame styleMask:[ticketOptionsWindow styleMask]];
[ticketOptionsBox setHidden:YES];
[ticketOptionsWindow setFrame:newFrame display:YES animate:YES];
[sender setTitle:NSLocalizedStringFromTable(@"SelectIdentityShowOptions", @"SelectIdentity", NULL)];
}
}
// ---------------------------------------------------------------------------
- (void) timedRefresh:(NSTimer *)timer
{
// refetch data to update expiration times
[identityArrayController rearrangeObjects];
}
@end