diff options
Diffstat (limited to 'Source/SPFavoritesPreferencePane.m')
-rw-r--r-- | Source/SPFavoritesPreferencePane.m | 928 |
1 files changed, 0 insertions, 928 deletions
diff --git a/Source/SPFavoritesPreferencePane.m b/Source/SPFavoritesPreferencePane.m deleted file mode 100644 index 159e8687..00000000 --- a/Source/SPFavoritesPreferencePane.m +++ /dev/null @@ -1,928 +0,0 @@ -// -// $Id$ -// -// SPFavoritesPreferencePane.m -// sequel-pro -// -// Created by Stuart Connolly (stuconnolly.com) on October 31, 2010 -// Copyright (c) 2010 Stuart Connolly. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// More info at <http://code.google.com/p/sequel-pro/> - -#import "SPFavoritesPreferencePane.h" -#import "SPFavoriteTextFieldCell.h" -#import "SPPreferenceController.h" -#import "SPKeychain.h" -#import <BWToolkitFramework/BWToolkitFramework.h> -#import "SPGeneralPreferencePane.h" - -@interface SPFavoritesPreferencePane (PrivateAPI) - -- (void)_sortFavorites; -- (void)_updateFavoritePasswordsFromField:(NSControl *)passwordControl; - -@end - -@interface NSSavePanel (NSSavePanel_unpublishedUntilSnowLeopardAPI) -- (void)setShowsHiddenFiles:(BOOL)flag; -@end - -@implementation SPFavoritesPreferencePane - -#pragma mark - -#pragma mark Intialisation - -/** - * Init. - */ -- (id)init -{ - if ((self = [super init])) { - - keychain = [[SPKeychain alloc] init]; - - favoriteType = 0; - reverseFavoritesSort = NO; - favoriteNameFieldWasTouched = YES; - - previousSortItem = SPFavoritesSortNameItem; - } - - return self; -} - -/** - * Initialise the UI, specifically the favourites table view and sort the favourites if required. - */ -- (void)awakeFromNib -{ - // Set sort items - currentSortItem = [prefs integerForKey:SPFavoritesSortedBy]; - reverseFavoritesSort = [prefs boolForKey:SPFavoritesSortedInReverse]; - - // Replace column's NSTextFieldCell with custom SWProfileTextFieldCell - [[[favoritesTableView tableColumns] objectAtIndex:0] setDataCell:tableCell]; - - [favoritesTableView registerForDraggedTypes:[NSArray arrayWithObject:SPFavoritesPasteboardDragType]]; - - [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; - [favoritesTableView reloadData]; - - [tableCell setImage:[NSImage imageNamed:@"database"]]; - - // Set the button bar delegate - [splitViewButtonBar setSplitViewDelegate:self]; - - // Hide the tabs on the favorites tab view - left visible in IB for easy use - [favoritesTabView setTabViewType:NSNoTabsNoBorder]; - - // Sort favorites if a sort type has been selected - if (currentSortItem != SPFavoritesSortUnsorted) [self _sortFavorites]; -} - -#pragma mark - -#pragma mark IBAction methods - -/** - * Adds a new connection favorite. - */ -- (IBAction)addFavorite:(id)sender -{ - NSNumber *favoriteid = [NSNumber numberWithInteger:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]]; - - // Create default favorite - NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:NSLocalizedString(@"New Favorite", @"new favorite name"), [NSNumber numberWithInteger:0], @"", @"", @"", @"", [NSNumber numberWithInt:NSOffState], [NSNumber numberWithInt:NSOffState], [NSNumber numberWithInt:NSOffState], [NSNumber numberWithInt:NSOffState], @"", @"", @"", [NSNumber numberWithInt:NSOffState], @"", @"", favoriteid, nil] - forKeys:[NSArray arrayWithObjects:@"name", @"type", @"host", @"socket", @"user", @"port", @"useSSL", @"sslKeyFileLocationEnabled", @"sslCertificateFileLocationEnabled", @"sslCACertFileLocationEnabled", @"database", @"sshHost", @"sshUser", @"sshKeyLocationEnabled", @"sshKeyLocation", @"sshPort", @"id", nil]]; - - [favoritesController addObject:favorite]; - [favoritesController setSelectedObjects:[NSArray arrayWithObject:favorite]]; - - [favoritesTableView reloadData]; - [favoritesTableView scrollRowToVisible:[favoritesTableView selectedRow]]; - - [[(SPPreferenceController *)[[[self view] window] delegate] generalPreferencePane] updateDefaultFavoritePopup]; - - favoriteNameFieldWasTouched = NO; - - [[[self view] window] makeFirstResponder:favoriteHostTextField]; -} - -/** - * Removes the selected connection favorite. - */ -- (IBAction)removeFavorite:(id)sender -{ - if ([favoritesTableView numberOfSelectedRows] == 1) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Delete favorite '%@'?", @"delete database message"), [favoritesController valueForKeyPath:@"selection.name"]] - defaultButton:NSLocalizedString(@"Delete", @"delete button") - alternateButton:NSLocalizedString(@"Cancel", @"cancel button") - otherButton:nil - informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete the favorite '%@'? This operation cannot be undone.", @"delete database informative message"), [favoritesController valueForKeyPath:@"selection.name"]]]; - - NSArray *buttons = [alert buttons]; - - // Change the alert's cancel button to have the key equivalent of return - [[buttons objectAtIndex:0] setKeyEquivalent:@"d"]; - [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask]; - [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - - [alert beginSheetModalForWindow:[[self view] window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeFavorite"]; - } -} - -/** - * Duplicates the selected connection favorite. - */ -- (IBAction)duplicateFavorite:(id)sender -{ - if ([favoritesTableView numberOfSelectedRows] == 1) { - - NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithDictionary:[[favoritesController arrangedObjects] objectAtIndex:[favoritesTableView selectedRow]]]; - NSNumber *favoriteid = [NSNumber numberWithInteger:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]]; - NSInteger duplicatedFavoriteType = [[favorite objectForKey:@"type"] integerValue]; - - // Select the keychain passwords for duplication - NSString *keychainName = [keychain nameForFavoriteName:[favorite objectForKey:@"name"] id:[favorite objectForKey:@"id"]]; - NSString *keychainAccount = [keychain accountForUser:[favorite objectForKey:@"user"] host:((duplicatedFavoriteType == SPSocketConnection)?@"localhost":[favorite objectForKey:@"host"]) database:[favorite objectForKey:@"database"]]; - NSString *password = [keychain getPasswordForName:keychainName account:keychainAccount]; - NSString *keychainSSHName = [keychain nameForSSHForFavoriteName:[favorite objectForKey:@"name"] id:[favorite objectForKey:@"id"]]; - NSString *keychainSSHAccount = [keychain accountForSSHUser:[favorite objectForKey:@"sshUser"] sshHost:[favorite objectForKey:@"sshHost"]]; - NSString *sshPassword = [keychain getPasswordForName:keychainSSHName account:keychainSSHAccount]; - - // Update the unique ID - [favorite setObject:favoriteid forKey:@"id"]; - - // Alter the name for clarity - [favorite setObject:[NSString stringWithFormat:NSLocalizedString(@"%@ Copy", @"Initial favourite name after duplicating a previous favourite"), [favorite objectForKey:@"name"]] forKey:@"name"]; - - // Create new keychain items if appropriate - if (password && [password length]) { - keychainName = [keychain nameForFavoriteName:[favorite objectForKey:@"name"] id:[favorite objectForKey:@"id"]]; - [keychain addPassword:password forName:keychainName account:keychainAccount]; - } - - if (sshPassword && [sshPassword length]) { - keychainSSHName = [keychain nameForSSHForFavoriteName:[favorite objectForKey:@"name"] id:[favorite objectForKey:@"id"]]; - [keychain addPassword:sshPassword forName:keychainSSHName account:keychainSSHAccount]; - } - - password = nil, sshPassword = nil; - - [favoritesController addObject:favorite]; - [favoritesController setSelectedObjects:[NSArray arrayWithObject:favorite]]; - - [favoritesTableView reloadData]; - [favoritesTableView scrollRowToVisible:[favoritesTableView selectedRow]]; - - [[(SPPreferenceController *)[[[self view] window] delegate] generalPreferencePane] updateDefaultFavoritePopup]; - - [[[self view] window] makeFirstResponder:favoriteNameTextField]; - } -} - -/** - * Sorts the favorites table view based on the selected sort by item - */ -- (IBAction)sortFavorites:(id)sender -{ - previousSortItem = currentSortItem; - currentSortItem = [[sender menu] indexOfItem:sender]; - - [prefs setInteger:currentSortItem forKey:SPFavoritesSortedBy]; - - // Perform sorting - [self _sortFavorites]; - - if ((NSInteger)previousSortItem > -1) [[[sender menu] itemAtIndex:previousSortItem] setState:NSOffState]; - - [[[sender menu] itemAtIndex:currentSortItem] setState:NSOnState]; -} - -/** - * Reverses the favorites table view sorting based on the selected criteria - */ -- (IBAction)reverseFavoritesSortOrder:(id)sender -{ - reverseFavoritesSort = (![sender state]); - - [prefs setBool:reverseFavoritesSort forKey:SPFavoritesSortedInReverse]; - - // Perform re-sorting - [self _sortFavorites]; - - [sender setState:reverseFavoritesSort]; -} - -/** - * Makes the selected favorite the default. - */ -- (IBAction)makeSelectedFavoriteDefault:(id)sender -{ - // Minus 2 from index to account for the 'Last Used' and separator items - [prefs setInteger:[favoritesTableView selectedRow] forKey:SPDefaultFavorite]; - - [favoritesTableView reloadData]; - - [[(SPPreferenceController *)[[[self view] window] delegate] generalPreferencePane] updateDefaultFavoritePopup]; -} - -/** - * Update the favorite host when the type changes. - */ -- (IBAction)favoriteTypeDidChange:(id)sender -{ - // If not socket and host is localhost, clear. - if (([sender indexOfSelectedItem] != 1) && [[favoritesController valueForKeyPath:@"selection.host"] isEqualToString:@"localhost"]) - { - [favoritesController setValue:@"" forKeyPath:@"selection.host"]; - } - - favoriteType = [sender indexOfSelectedItem]; - - // Update the name for a new added favorite if not touched by the user - if(!favoriteNameFieldWasTouched) { - [favoriteNameTextField setStringValue:[NSString stringWithFormat:@"%@@%@", - ([favoritesController valueForKeyPath:@"selection.user"]) ? [favoritesController valueForKeyPath:@"selection.user"] : @"", - (([sender indexOfSelectedItem] == 1) ? @"localhost" : - (([favoritesController valueForKeyPath:@"selection.host"]) ? [favoritesController valueForKeyPath:@"selection.host"] : @"")) - ]]; - - [favoritesController setValue:[favoriteNameTextField stringValue] forKeyPath:@"selection.name"]; - } - - // Request a password refresh to keep keychain references in synch with the favorites - [self _updateFavoritePasswordsFromField:nil]; -} - -/** - * Opens the SSH/SSL key selection window, ready to select a key file. - */ -- (IBAction)chooseKeyLocation:(id)sender -{ - NSString *directoryPath = nil; - NSString *filePath = nil; - NSArray *permittedFileTypes = nil; - keySelectionPanel = [NSOpenPanel openPanel]; - [keySelectionPanel setShowsHiddenFiles:[prefs boolForKey:SPHiddenKeyFileVisibilityKey]]; - - // Switch details by sender. - // First, SSH keys: - if (sender == sshSSHKeyButton) { - - // If the custom key location is currently disabled - after the button - // action - leave it disabled and return without showing the sheet. - if (![favoritesController valueForKeyPath:@"selection.sshKeyLocationEnabled"]) { - return; - } - - // Otherwise open a panel at the last or default location - NSString *sshKeyLocation = [favoritesController valueForKeyPath:@"selection.sshKeyLocation"]; - if (sshKeyLocation && [sshKeyLocation length]) { - filePath = [sshKeyLocation lastPathComponent]; - directoryPath = [sshKeyLocation stringByDeletingLastPathComponent]; - } - - permittedFileTypes = [NSArray arrayWithObjects:@"pem", @"", nil]; - - [keySelectionPanel setAccessoryView:sshKeyLocationHelp]; - - // SSL key file location: - } - else if (sender == standardSSLKeyFileButton || sender == socketSSLKeyFileButton) { - if ([sender state] == NSOffState) { - [favoritesController setValue:nil forKeyPath:@"selection.sslKeyFileLocation"]; - return; - } - - permittedFileTypes = [NSArray arrayWithObjects:@"pem", @"key", @"", nil]; - [keySelectionPanel setAccessoryView:sslKeyFileLocationHelp]; - - // SSL certificate file location: - } - else if (sender == standardSSLCertificateButton || sender == socketSSLCertificateButton) { - if ([sender state] == NSOffState) { - [favoritesController setValue:nil forKeyPath:@"selection.sslCertificateFileLocation"]; - return; - } - - permittedFileTypes = [NSArray arrayWithObjects:@"pem", @"cert", @"crt", @"", nil]; - [keySelectionPanel setAccessoryView:sslCertificateLocationHelp]; - - // SSL CA certificate file location: - } - else if (sender == standardSSLCACertButton || sender == socketSSLCACertButton) { - if ([sender state] == NSOffState) { - [favoritesController setValue:nil forKeyPath:@"selection.sslCACertFileLocation"]; - return; - } - - permittedFileTypes = [NSArray arrayWithObjects:@"pem", @"cert", @"crt", @"", nil]; - [keySelectionPanel setAccessoryView:sslCACertLocationHelp]; - } - - [keySelectionPanel beginSheetForDirectory:directoryPath - file:filePath - types:permittedFileTypes - modalForWindow:[[self view] window] - modalDelegate:self - didEndSelector:@selector(chooseKeyLocationSheetDidEnd:returnCode:contextInfo:) - contextInfo:sender]; -} - -/** - * Toggle hidden file visiblity in response to accessory view changes - */ -- (IBAction)updateKeyLocationFileVisibility:(id)sender -{ - [keySelectionPanel setShowsHiddenFiles:[prefs boolForKey:SPHiddenKeyFileVisibilityKey]]; -} - -#pragma mark - -#pragma mark Public API - -/** - * Selects the specified favorite(s) in the favorites list. - */ -- (void)selectFavorites:(NSArray *)favorites -{ - [favoritesController setSelectedObjects:favorites]; - [favoritesTableView scrollRowToVisible:[favoritesController selectionIndex]]; -} - -#pragma mark - -#pragma mark TableView datasource methods - -- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView -{ - return [[favoritesController arrangedObjects] count]; -} - -- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex -{ - return [[[favoritesController arrangedObjects] objectAtIndex:rowIndex] objectForKey:[tableColumn identifier]]; -} - -#pragma mark - -#pragma mark TableView drag & drop delegate methods - -- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rows toPasteboard:(NSPasteboard*)pboard -{ - if ([rows count] == 1) { - [pboard declareTypes:[NSArray arrayWithObject:SPFavoritesPasteboardDragType] owner:nil]; - [pboard setString:[[NSNumber numberWithInteger:[rows firstIndex]] stringValue] forType:SPFavoritesPasteboardDragType]; - - return YES; - } - else { - return NO; - } -} - -- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation -{ - NSInteger originalRow; - NSArray *pboardTypes = [[info draggingPasteboard] types]; - - if (([pboardTypes count] > 1) && (row != -1)) { - if (([pboardTypes containsObject:SPFavoritesPasteboardDragType]) && (operation == NSTableViewDropAbove)) { - originalRow = [[[info draggingPasteboard] stringForType:SPFavoritesPasteboardDragType] integerValue]; - - if ((row != originalRow) && (row != (originalRow + 1))) { - return NSDragOperationMove; - } - } - } - - return NSDragOperationNone; -} - -- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation -{ - NSInteger originalRow; - NSInteger destinationRow; - NSInteger lastFavoriteIndexCached; - NSMutableDictionary *draggedRow; - - // Disable all automatic sorting - currentSortItem = -1; - reverseFavoritesSort = NO; - - [prefs setInteger:currentSortItem forKey:SPFavoritesSortedBy]; - [prefs setBool:NO forKey:SPFavoritesSortedInReverse]; - - // Remove sort descriptors - [favoritesController setSortDescriptors:[NSArray array]]; - - // Uncheck sort by menu items - for (NSMenuItem *menuItem in [[favoritesSortByMenuItem submenu] itemArray]) - { - [menuItem setState:NSOffState]; - } - - originalRow = [[[info draggingPasteboard] stringForType:SPFavoritesPasteboardDragType] integerValue]; - destinationRow = row; - - if (destinationRow > originalRow) { - destinationRow--; - } - - draggedRow = [NSMutableDictionary dictionaryWithDictionary:[[favoritesController arrangedObjects] objectAtIndex:originalRow]]; - - // Before deleting this favorite, we need to save the current index. - // because removeObjectAtArrangedObjectIndex will set prefs LastFavoriteIndex to 0 - lastFavoriteIndexCached = [prefs integerForKey:SPLastFavoriteIndex]; - - [favoritesController removeObjectAtArrangedObjectIndex:originalRow]; - [favoritesController insertObject:draggedRow atArrangedObjectIndex:destinationRow]; - - [favoritesTableView reloadData]; - [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:destinationRow] byExtendingSelection:NO]; - - // Update default favorite to take on new value - if (lastFavoriteIndexCached == originalRow) { - [prefs setInteger:destinationRow forKey:SPLastFavoriteIndex]; - } - - // Update default favorite to take on new value - if ([prefs integerForKey:SPDefaultFavorite] == originalRow) { - [prefs setInteger:destinationRow forKey:SPDefaultFavorite]; - } - - [[(SPPreferenceController *)[[[self view] window] delegate] generalPreferencePane] updateDefaultFavoritePopup]; - - return YES; -} - -#pragma mark - -#pragma mark TableView delegate methods - -- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)index -{ - if ([cell isKindOfClass:[SPFavoriteTextFieldCell class]]) { - [cell setFavoriteName:[[[favoritesController arrangedObjects] objectAtIndex:index] objectForKey:@"name"]]; - - if ([[[[favoritesController arrangedObjects] objectAtIndex:index] objectForKey:@"type"] integerValue] == SPSocketConnection) { - [cell setFavoriteHost:@"localhost"]; - } - else { - [cell setFavoriteHost:[[[favoritesController arrangedObjects] objectAtIndex:index] objectForKey:@"host"]]; - } - } -} - -- (void)tableViewSelectionDidChange:(NSNotification *)notification -{ - if ([[favoritesTableView selectedRowIndexes] count] > 0) { - [favoritesController setSelectionIndexes:[favoritesTableView selectedRowIndexes]]; - } - - // If no selection is present, blank the password fields (which can't use bindings) - if ([[favoritesTableView selectedRowIndexes] count] == 0) { - [standardPasswordField setStringValue:@""]; - [socketPasswordField setStringValue:@""]; - [sshSQLPasswordField setStringValue:@""]; - [sshPasswordField setStringValue:@""]; - - return; - } - - // Keep a copy of the favorite as it currently stands - if (currentFavorite) [currentFavorite release]; - - currentFavorite = [[[favoritesController selectedObjects] objectAtIndex:0] copy]; - - // Retrieve and set the password. - NSString *keychainName = [keychain nameForFavoriteName:[currentFavorite objectForKey:@"name"] id:[currentFavorite objectForKey:@"id"]]; - NSString *keychainAccount = [keychain accountForUser:[currentFavorite objectForKey:@"user"] host:(([[currentFavorite objectForKey:@"type"] integerValue] == SPSocketConnection)?@"localhost":[currentFavorite objectForKey:@"host"]) database:[currentFavorite objectForKey:@"database"]]; - NSString *passwordValue = [keychain getPasswordForName:keychainName account:keychainAccount]; - - [standardPasswordField setStringValue:passwordValue?passwordValue:@""]; - [socketPasswordField setStringValue:passwordValue?passwordValue:@""]; - [sshSQLPasswordField setStringValue:passwordValue?passwordValue:@""]; - - // Retrieve the SSH keychain password if appropriate. - NSString *keychainSSHName = [keychain nameForSSHForFavoriteName:[currentFavorite objectForKey:@"name"] id:[currentFavorite objectForKey:@"id"]]; - NSString *keychainSSHAccount = [keychain accountForSSHUser:[currentFavorite objectForKey:@"sshUser"] sshHost:[currentFavorite objectForKey:@"sshHost"]]; - NSString *sshPasswordValue = [keychain getPasswordForName:keychainSSHName account:keychainSSHAccount]; - [sshPasswordField setStringValue:sshPasswordValue?sshPasswordValue:@""]; - - favoriteNameFieldWasTouched = YES; -} - -#pragma mark - -#pragma mark TextField delegate methods and type change action - -/** - * Trap editing end notifications and use them to update the keychain password - * appropriately when name, host, user, password or database changes. - */ -- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor -{ - // Request a password refresh to keep keychain references in synch with favorites - [self _updateFavoritePasswordsFromField:control]; - - // Proceed with editing - return YES; -} - -/** - * Trap and control the 'name' field of the selected favorite. If the user pressed - * 'Add Favorite' the 'name' field is set to "New Favorite". If the user do not - * change the 'name' field or delete that field it will be set to user@host automatically. - */ -- (void)controlTextDidChange:(NSNotification *)notification -{ - id field = [notification object]; - - BOOL nameFieldIsEmpty = ([[favoritesController valueForKeyPath:@"selection.name"] isEqualToString:@""] || - [[favoriteNameTextField stringValue] isEqualToString:@""]); - - switch (favoriteType) - { - case 0: - if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && (field == favoriteUserTextField || field == favoriteHostTextField))) { - [favoriteNameTextField setStringValue:[NSString stringWithFormat:@"%@@%@", [favoriteUserTextField stringValue], [favoriteHostTextField stringValue]]]; - [favoritesController setValue:[favoriteNameTextField stringValue] forKeyPath:@"selection.name"]; - [prefs synchronize]; - - // if name field is empty enable user@host update - if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO; - } - break; - case 1: - if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && field == favoriteUserTextFieldSocket)) { - [favoriteNameTextField setStringValue:[NSString stringWithFormat:@"%@@localhost", [favoriteUserTextFieldSocket stringValue]]]; - [favoritesController setValue:[favoriteNameTextField stringValue] forKeyPath:@"selection.name"]; - [prefs synchronize]; - - // if name field is empty enable user@host update - if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO; - } - break; - case 2: - if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && (field == favoriteUserTextFieldSSH || field == favoriteHostTextFieldSSH))) { - [favoriteNameTextField setStringValue:[NSString stringWithFormat:@"%@@%@", [favoriteUserTextFieldSSH stringValue], [favoriteHostTextFieldSSH stringValue]]]; - [favoritesController setValue:[favoriteNameTextField stringValue] forKeyPath:@"selection.name"]; - [prefs synchronize]; - - // if name field is empty enable user@host update - if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO; - } - break; - default: - break; - } - - if (field == favoriteNameTextField) favoriteNameFieldWasTouched = YES; -} - -#pragma mark - -#pragma mark SplitView delegate methods - -- (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset -{ - return (proposedMax - 220); -} - -- (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset -{ - return (proposedMin + 94); -} - -#pragma mark - -#pragma mark Other - -/** - * Menu item validation; - */ -- (BOOL)validateMenuItem:(NSMenuItem *)menuItem -{ - SEL action = [menuItem action]; - - if ((action == @selector(removeFavorite:)) || (action == @selector(duplicateFavorite:))) { - return ([favoritesTableView numberOfSelectedRows] > 0); - } - - if (action == @selector(makeSelectedFavoriteDefault:)) { - return ([favoritesTableView numberOfSelectedRows] == 1); - } - - if ((action == @selector(sortFavorites:)) || (action == @selector(reverseFavoritesSortOrder:))) { - - // Loop all the items in the sort by menu only checking the currently selected one - for (NSMenuItem *item in [[menuItem menu] itemArray]) - { - [item setState:([[menuItem menu] indexOfItem:item] == currentSortItem)]; - } - - // Check or uncheck the reverse sort item - if (action == @selector(reverseFavoritesSortOrder:)) { - [menuItem setState:reverseFavoritesSort]; - } - - return [[[[[self view] window] toolbar] selectedItemIdentifier] isEqualToString:SPPreferenceToolbarFavorites]; - } - - return YES; -} - -/** - * Called after closing the SSH/SSL key selection sheet. - */ -- (void)chooseKeyLocationSheetDidEnd:(NSOpenPanel *)openPanel returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo -{ - NSString *abbreviatedFileName = [[[openPanel URL] path] stringByAbbreviatingWithTildeInPath]; - - // SSH key file selection - if (contextInfo == sshSSHKeyButton) { - if (returnCode == NSCancelButton) { - [favoritesController setValue:[NSNumber numberWithInt:NSOffState] forKeyPath:@"selection.sshKeyLocationEnabled"]; - return; - } - - [favoritesController setValue:abbreviatedFileName forKeyPath:@"selection.sshKeyLocation"]; - - // SSL key file selection - } - else if (contextInfo == standardSSLKeyFileButton || contextInfo == socketSSLKeyFileButton) { - if (returnCode == NSCancelButton) { - [favoritesController setValue:[NSNumber numberWithInt:NSOffState] forKeyPath:@"selection.sslKeyFileLocationEnabled"]; - [favoritesController setValue:nil forKeyPath:@"selection.sslKeyFileLocation"]; - return; - } - - [favoritesController setValue:abbreviatedFileName forKeyPath:@"selection.sslKeyFileLocation"]; - - // SSL certificate file selection - } - else if (contextInfo == standardSSLCertificateButton || contextInfo == socketSSLCertificateButton) { - if (returnCode == NSCancelButton) { - [favoritesController setValue:[NSNumber numberWithInt:NSOffState] forKeyPath:@"selection.sslCertificateFileLocationEnabled"]; - [favoritesController setValue:nil forKeyPath:@"selection.sslCertificateFileLocation"]; - return; - } - - [favoritesController setValue:abbreviatedFileName forKeyPath:@"selection.sslCertificateFileLocation"]; - - // SSL CA certificate file selection - } - else if (contextInfo == standardSSLCACertButton || contextInfo == socketSSLCACertButton) { - if (returnCode == NSCancelButton) { - [favoritesController setValue:[NSNumber numberWithInt:NSOffState] forKeyPath:@"selection.sslCACertFileLocationEnabled"]; - [favoritesController setValue:nil forKeyPath:@"selection.sslCACertFileLocation"]; - return; - } - - [favoritesController setValue:abbreviatedFileName forKeyPath:@"selection.sslCACertFileLocation"]; - } -} - -- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo -{ - // Order out current sheet to suppress overlapping of sheets - if ([sheet respondsToSelector:@selector(orderOut:)]) { - [sheet orderOut:nil]; - } - else if ([sheet respondsToSelector:@selector(window)]) { - [[sheet window] orderOut:nil]; - } - - // Remove the current favorite - if ([contextInfo isEqualToString:@"removeFavorite"]) { - if (returnCode == NSAlertDefaultReturn) { - - // Get selected favorite's details - NSString *name = [favoritesController valueForKeyPath:@"selection.name"]; - NSString *user = [favoritesController valueForKeyPath:@"selection.user"]; - NSString *host = [favoritesController valueForKeyPath:@"selection.host"]; - NSString *database = [favoritesController valueForKeyPath:@"selection.database"]; - NSString *sshUser = [favoritesController valueForKeyPath:@"selection.sshUser"]; - NSString *sshHost = [favoritesController valueForKeyPath:@"selection.sshHost"]; - NSString *favoriteid = [favoritesController valueForKeyPath:@"selection.id"]; - NSInteger type = [[favoritesController valueForKeyPath:@"selection.type"] integerValue]; - - // Remove passwords from the Keychain - [keychain deletePasswordForName:[keychain nameForFavoriteName:name id:favoriteid] - account:[keychain accountForUser:user host:((type == SPSocketConnection)?@"localhost":host) database:database]]; - [keychain deletePasswordForName:[keychain nameForSSHForFavoriteName:name id:favoriteid] - account:[keychain accountForSSHUser:sshUser sshHost:sshHost]]; - - // Reset last used favorite - if ([favoritesTableView selectedRow] == [prefs integerForKey:SPLastFavoriteIndex]) { - [prefs setInteger:0 forKey:SPLastFavoriteIndex]; - } - - // Reset default favorite - if ([favoritesTableView selectedRow] == [prefs integerForKey:SPDefaultFavorite]) { - [prefs setInteger:[prefs integerForKey:SPLastFavoriteIndex] forKey:SPDefaultFavorite]; - } - - [favoritesController removeObjectAtArrangedObjectIndex:[favoritesTableView selectedRow]]; - - [favoritesTableView reloadData]; - - [[(SPPreferenceController *)[[[self view] window] delegate] generalPreferencePane] updateDefaultFavoritePopup]; - } - } -} - -#pragma mark - -#pragma mark Preference pane protocol methods - -- (NSView *)preferencePaneView -{ - return [self view]; -} - -- (NSImage *)preferencePaneIcon -{ - return [NSImage imageNamed:@"toolbar-preferences-favorites"]; -} - -- (NSString *)preferencePaneName -{ - return NSLocalizedString(@"Favorites", @"favorites label"); -} - -- (NSString *)preferencePaneIdentifier -{ - return SPPreferenceToolbarFavorites; -} - -- (NSString *)preferencePaneToolTip -{ - return NSLocalizedString(@"Favorite Preferences", @"favorites preference pane tooltip"); -} - -- (BOOL)preferencePaneAllowsResizing -{ - return YES; -} - -#pragma mark - -#pragma mark Private API - -/** - * Sorts the connection favorites based on the selected criteria. - */ -- (void)_sortFavorites -{ - NSString *sortKey = SPFavoriteNameKey; - - switch (currentSortItem) - { - case SPFavoritesSortNameItem: - sortKey = SPFavoriteNameKey; - break; - case SPFavoritesSortHostItem: - sortKey = SPFavoriteHostKey; - break; - case SPFavoritesSortTypeItem: - sortKey = SPFavoriteTypeKey; - break; - default: - return; - } - - NSSortDescriptor *sortDescriptor = nil; - - if (currentSortItem == SPFavoritesSortTypeItem) { - sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:sortKey ascending:(!reverseFavoritesSort)] autorelease]; - } - else { - sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:sortKey ascending:(!reverseFavoritesSort) selector:@selector(caseInsensitiveCompare:)] autorelease]; - } - - [favoritesController setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; - - [favoritesTableView reloadData]; - - [[(SPPreferenceController *)[[[self view] window] delegate] generalPreferencePane] updateDefaultFavoritePopup]; -} - -/** - * Check all fields used in the keychain names against the old values for that - * favorite, and update the keychain names to match if necessary. - * If an (optional) recognised password field is supplied, that field is assumed - * to have changed and is used to supply the new value. - */ -- (void)_updateFavoritePasswordsFromField:(NSControl *)passwordControl -{ - if (!currentFavorite) return; - - NSString *passwordValue; - NSString *oldKeychainName, *newKeychainName; - NSString *oldKeychainAccount, *newKeychainAccount; - NSString *oldHostnameForPassword = ([[currentFavorite objectForKey:@"type"] integerValue] == SPSocketConnection) ? @"localhost" : [currentFavorite objectForKey:@"host"]; - NSString *newHostnameForPassword = ([[favoritesController valueForKeyPath:@"selection.type"] integerValue] == SPSocketConnection) ? @"localhost" : [favoritesController valueForKeyPath:@"selection.host"]; - - // SQL passwords are indexed by name, host, user and database. If any of these - // have changed, or a standard password field has, alter the keychain item to match. - if (![[currentFavorite objectForKey:@"name"] isEqualToString:[favoritesController valueForKeyPath:@"selection.name"]] - || ![oldHostnameForPassword isEqualToString:newHostnameForPassword] - || ![[currentFavorite objectForKey:@"user"] isEqualToString:[favoritesController valueForKeyPath:@"selection.user"]] - || ![[currentFavorite objectForKey:@"database"] isEqualToString:[favoritesController valueForKeyPath:@"selection.database"]] - || passwordControl == standardPasswordField || passwordControl == socketPasswordField || passwordControl == sshSQLPasswordField) - { - - // Determine the correct password field to read the password from, defaulting to standard - if (passwordControl == socketPasswordField) { - passwordValue = [socketPasswordField stringValue]; - } - else if (passwordControl == sshSQLPasswordField) { - passwordValue = [sshSQLPasswordField stringValue]; - } - else { - passwordValue = [standardPasswordField stringValue]; - } - - // Get the old keychain name and account strings - oldKeychainName = [keychain nameForFavoriteName:[currentFavorite objectForKey:@"name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - oldKeychainAccount = [keychain accountForUser:[currentFavorite objectForKey:@"user"] host:oldHostnameForPassword database:[currentFavorite objectForKey:@"database"]]; - - // If there's no new password, remove the old item from the keychain - if (![passwordValue length]) { - [keychain deletePasswordForName:oldKeychainName account:oldKeychainAccount]; - - // Otherwise, set up the new keychain name and account strings and create or edit the item - } else { - newKeychainName = [keychain nameForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - newKeychainAccount = [keychain accountForUser:[favoritesController valueForKeyPath:@"selection.user"] host:newHostnameForPassword database:[favoritesController valueForKeyPath:@"selection.database"]]; - if ([keychain passwordExistsForName:oldKeychainName account:oldKeychainAccount]) { - [keychain updateItemWithName:oldKeychainName account:oldKeychainAccount toName:newKeychainName account:newKeychainAccount password:passwordValue]; - } else { - [keychain addPassword:passwordValue forName:newKeychainName account:newKeychainAccount]; - } - - } - - // Synch password changes - [standardPasswordField setStringValue:passwordValue]; - [socketPasswordField setStringValue:passwordValue]; - [sshSQLPasswordField setStringValue:passwordValue]; - - passwordValue = @""; - } - - // If SSH account/password details have changed, update the keychain to match - if (![[currentFavorite objectForKey:@"name"] isEqualToString:[favoritesController valueForKeyPath:@"selection.name"]] - || ![[currentFavorite objectForKey:@"sshHost"] isEqualToString:[favoritesController valueForKeyPath:@"selection.sshHost"]] - || ![[currentFavorite objectForKey:@"sshUser"] isEqualToString:[favoritesController valueForKeyPath:@"selection.sshUser"]] - || passwordControl == sshPasswordField) { - - // Get the old keychain name and account strings - oldKeychainName = [keychain nameForSSHForFavoriteName:[currentFavorite objectForKey:@"name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - oldKeychainAccount = [keychain accountForSSHUser:[currentFavorite objectForKey:@"sshUser"] sshHost:[currentFavorite objectForKey:@"sshHost"]]; - - // If there's no new password, delete the keychain item - if (![[sshPasswordField stringValue] length]) { - [keychain deletePasswordForName:oldKeychainName account:oldKeychainAccount]; - - - // Otherwise, set up the new keychain name and account strings and create or update the keychain item - } else { - newKeychainName = [keychain nameForSSHForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - newKeychainAccount = [keychain accountForSSHUser:[favoritesController valueForKeyPath:@"selection.sshUser"] sshHost:[favoritesController valueForKeyPath:@"selection.sshHost"]]; - if ([keychain passwordExistsForName:oldKeychainName account:oldKeychainAccount]) { - [keychain updateItemWithName:oldKeychainName account:oldKeychainAccount toName:newKeychainName account:newKeychainAccount password:[sshPasswordField stringValue]]; - } else { - [keychain addPassword:[sshPasswordField stringValue] forName:newKeychainName account:newKeychainAccount]; - } - } - } - - // Update the current favorite - if (currentFavorite) [currentFavorite release], currentFavorite = nil; - - if ([[favoritesTableView selectedRowIndexes] count] > 0) - currentFavorite = [[[favoritesController selectedObjects] objectAtIndex:0] copy]; -} - -#pragma mark - - -- (void)dealloc -{ - [keychain release], keychain = nil; - - if (currentFavorite) [currentFavorite release], currentFavorite = nil; - - [super dealloc]; -} - -@end |