// // SPPreferenceController.m // sequel-pro // // Created by Stuart Connolly (stuconnolly.com) on Dec 10, 2008 // Modified by Ben Perry (benperry.com.au) on Mar 28, 2009 // // 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 #import "SPPreferenceController.h" #import "SPWindowAdditions.h" #import "SPFavoriteTextFieldCell.h" #import "KeyChain.h" #define FAVORITES_PB_DRAG_TYPE @"SequelProPreferencesPasteboard" #define PREFERENCE_TOOLBAR_GENERAL @"Preference Toolbar General" #define PREFERENCE_TOOLBAR_TABLES @"Preference Toolbar Tables" #define PREFERENCE_TOOLBAR_FAVORITES @"Preference Toolbar Favorites" #define PREFERENCE_TOOLBAR_NOTIFICATIONS @"Preference Toolbar Notifications" #define PREFERENCE_TOOLBAR_AUTOUPDATE @"Preference Toolbar Auto Update" #define PREFERENCE_TOOLBAR_NETWORK @"Preference Toolbar Network" #pragma mark - @interface SPPreferenceController (PrivateAPI) - (void)_setupToolbar; - (void)_resizeWindowForContentView:(NSView *)view; - (void)_updateDefaultFavoritePopup; @end #pragma mark - @implementation SPPreferenceController // ------------------------------------------------------------------------------- // init // ------------------------------------------------------------------------------- - (id)init { return [super initWithWindowNibName:@"Preferences"]; } // ------------------------------------------------------------------------------- // windowDidLoad // ------------------------------------------------------------------------------- - (void)windowDidLoad { [self _setupToolbar]; prefs = [NSUserDefaults standardUserDefaults]; keychain = [[KeyChain alloc] init]; SPFavoriteTextFieldCell *tableCell = [[[SPFavoriteTextFieldCell alloc] init] autorelease]; [tableCell setImage:[NSImage imageNamed:@"database"]]; // Replace column's NSTextFieldCell with custom SWProfileTextFieldCell [[[favoritesTableView tableColumns] objectAtIndex:0] setDataCell:tableCell]; [favoritesTableView registerForDraggedTypes:[NSArray arrayWithObject:FAVORITES_PB_DRAG_TYPE]]; [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; [favoritesTableView reloadData]; [self _updateDefaultFavoritePopup]; } #pragma mark - #pragma mark IBAction methods // ------------------------------------------------------------------------------- // addFavorite: // ------------------------------------------------------------------------------- - (IBAction)addFavorite:(id)sender { // Create default favorite NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"New Favorite", @"", @"", @"", @"", @"", nil] forKeys:[NSArray arrayWithObjects:@"name", @"host", @"socket", @"user", @"port", @"database", nil]]; [favoritesController addObject:favorite]; [favoritesTableView reloadData]; [self _updateDefaultFavoritePopup]; } // ------------------------------------------------------------------------------- // removeFavorite: // ------------------------------------------------------------------------------- - (IBAction)removeFavorite:(id)sender { if ([favoritesTableView numberOfSelectedRows] == 1) { // 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"]; // Remove passwords from the Keychain [keychain deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@", name] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; [keychain deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro SSHTunnel : %@", name] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; // Reset last used favorite if ([favoritesTableView selectedRow] == [prefs integerForKey:@"LastFavoriteIndex"]) { [prefs setInteger:0 forKey:@"LastFavoriteIndex"]; } // Reset default favorite if ([favoritesTableView selectedRow] == [prefs integerForKey:@"DefaultFavorite"]) { [prefs setInteger:[prefs integerForKey:@"LastFavoriteIndex"] forKey:@"DefaultFavorite"]; } [favoritesController removeObjectAtArrangedObjectIndex:[favoritesTableView selectedRow]]; [favoritesTableView reloadData]; [self _updateDefaultFavoritePopup]; } } // ------------------------------------------------------------------------------- // duplicateFavorite: // ------------------------------------------------------------------------------- - (IBAction)duplicateFavorite:(id)sender { if ([favoritesTableView numberOfSelectedRows] == 1) { NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithDictionary:[[favoritesController arrangedObjects] objectAtIndex:[favoritesTableView selectedRow]]]; [favoritesController addObject:favorite]; [favoritesTableView reloadData]; [self _updateDefaultFavoritePopup]; } } // ------------------------------------------------------------------------------- // saveFavorite: // ------------------------------------------------------------------------------- - (IBAction)saveFavorite:(id)sender { } // ------------------------------------------------------------------------------- // updateDefaultFavorite: // ------------------------------------------------------------------------------- - (IBAction)updateDefaultFavorite:(id)sender { if ([defaultFavoritePopup indexOfSelectedItem] == 0) { [prefs setBool:YES forKey:@"SelectLastFavoriteUsed"]; } else { [prefs setBool:NO forKey:@"SelectLastFavoriteUsed"]; // Minus 2 from index to account for the "Last Used" and separator items [prefs setInteger:[defaultFavoritePopup indexOfSelectedItem]-2 forKey:@"DefaultFavorite"]; } } #pragma mark - #pragma mark Toolbar item IBAction methods // ------------------------------------------------------------------------------- // displayGeneralPreferences: // ------------------------------------------------------------------------------- - (IBAction)displayGeneralPreferences:(id)sender { [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_GENERAL]; [self _resizeWindowForContentView:generalView]; } // ------------------------------------------------------------------------------- // displayTablePreferences: // ------------------------------------------------------------------------------- - (IBAction)displayTablePreferences:(id)sender { [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_TABLES]; [self _resizeWindowForContentView:tablesView]; } // ------------------------------------------------------------------------------- // displayFavoritePreferences: // ------------------------------------------------------------------------------- - (IBAction)displayFavoritePreferences:(id)sender { [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_FAVORITES]; [self _resizeWindowForContentView:favoritesView]; // Set the default favorite popup back to preference if (sender == [defaultFavoritePopup lastItem]) { if (![prefs boolForKey:@"SelectLastFavoriteUsed"]) { [defaultFavoritePopup selectItemAtIndex:[prefs integerForKey:@"DefaultFavorite"]+2]; } else { [defaultFavoritePopup selectItemAtIndex:0]; } } } // ------------------------------------------------------------------------------- // displayNotificationPreferences: // ------------------------------------------------------------------------------- - (IBAction)displayNotificationPreferences:(id)sender { [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_NOTIFICATIONS]; [self _resizeWindowForContentView:notificationsView]; } // ------------------------------------------------------------------------------- // displayAutoUpdatePreferences: // ------------------------------------------------------------------------------- - (IBAction)displayAutoUpdatePreferences:(id)sender { [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_AUTOUPDATE]; [self _resizeWindowForContentView:autoUpdateView]; } // ------------------------------------------------------------------------------- // displayNetworkPreferences: // ------------------------------------------------------------------------------- - (IBAction)displayNetworkPreferences:(id)sender { [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_NETWORK]; [self _resizeWindowForContentView:networkView]; } #pragma mark - #pragma mark TableView datasource methods // ------------------------------------------------------------------------------- // numberOfRowsInTableView: // ------------------------------------------------------------------------------- - (int)numberOfRowsInTableView:(NSTableView *)aTableView { return [[favoritesController arrangedObjects] count]; } // ------------------------------------------------------------------------------- // tableView:objectValueForTableColumn:row: // ------------------------------------------------------------------------------- - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { return [[[favoritesController arrangedObjects] objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]]; } #pragma mark - #pragma mark TableView drag & drop datasource methods // ------------------------------------------------------------------------------- // tableView:writeRows:toPasteboard: // ------------------------------------------------------------------------------- - (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray *)rows toPasteboard:(NSPasteboard *)pboard { int originalRow; NSArray *pboardTypes; if ([rows count] == 1) { pboardTypes = [NSArray arrayWithObject:FAVORITES_PB_DRAG_TYPE]; originalRow = [[rows objectAtIndex:0] intValue]; [pboard declareTypes:pboardTypes owner:nil]; [pboard setString:[[NSNumber numberWithInt:originalRow] stringValue] forType:FAVORITES_PB_DRAG_TYPE]; return YES; } else { return NO; } } // ------------------------------------------------------------------------------- // tableView:validateDrop:proposedRow:proposedDropOperation: // ------------------------------------------------------------------------------- - (NSDragOperation)tableView:(NSTableView *)tv validateDrop:(id )info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation { int originalRow; NSArray *pboardTypes = [[info draggingPasteboard] types]; if (([pboardTypes count] > 1) && (row != -1)) { if (([pboardTypes containsObject:FAVORITES_PB_DRAG_TYPE]) && (operation == NSTableViewDropAbove)) { originalRow = [[[info draggingPasteboard] stringForType:FAVORITES_PB_DRAG_TYPE] intValue]; if ((row != originalRow) && (row != (originalRow + 1))) { return NSDragOperationMove; } } } return NSDragOperationNone; } // ------------------------------------------------------------------------------- // tableView:acceptDrop:row:dropOperation: // ------------------------------------------------------------------------------- - (BOOL)tableView:(NSTableView *)tv acceptDrop:(id )info row:(int)row dropOperation:(NSTableViewDropOperation)operation { int originalRow; int destinationRow; NSMutableDictionary *draggedRow; originalRow = [[[info draggingPasteboard] stringForType:FAVORITES_PB_DRAG_TYPE] intValue]; destinationRow = row; if (destinationRow > originalRow) { destinationRow--; } draggedRow = [NSMutableDictionary dictionaryWithDictionary:[[favoritesController arrangedObjects] objectAtIndex:originalRow]]; [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 ([prefs integerForKey:@"LastFavoriteIndex"] == originalRow) { [prefs setInteger:destinationRow forKey:@"LastFavoriteIndex"]; } // Update default favorite to take on new value if ([prefs integerForKey:@"DefaultFavorite"] == originalRow) { [prefs setInteger:destinationRow forKey:@"DefaultFavorite"]; } [self _updateDefaultFavoritePopup]; return YES; } #pragma mark - #pragma mark TableView delegate methods // ------------------------------------------------------------------------------- // tableView:willDisplayCell:forTableColumn:row: // ------------------------------------------------------------------------------- - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)index { if ([cell isKindOfClass:[SPFavoriteTextFieldCell class]]) { [cell setFavoriteName:[[[favoritesController arrangedObjects] objectAtIndex:index] objectForKey:@"name"]]; [cell setFavoriteHost:[[[favoritesController arrangedObjects] objectAtIndex:index] objectForKey:@"host"]]; } } // ------------------------------------------------------------------------------- // tableViewSelectionDidChange: // ------------------------------------------------------------------------------- - (void)tableViewSelectionDidChange:(NSNotification *)notification { if ([[favoritesTableView selectedRowIndexes] count] > 0) { [favoritesController setSelectionIndexes:[favoritesTableView selectedRowIndexes]]; } NSString *keychainName = [NSString stringWithFormat:@"Sequel Pro : %@", [favoritesController valueForKeyPath:@"selection.name"]]; NSString *keychainAccount = [NSString stringWithFormat:@"%@@%@/%@", [favoritesController valueForKeyPath:@"selection.user"], [favoritesController valueForKeyPath:@"selection.host"], [favoritesController valueForKeyPath:@"selection.database"]]; [passwordField setStringValue:[keychain getPasswordForName:keychainName account:keychainAccount]]; } #pragma mark - #pragma mark Toolbar delegate methods // ------------------------------------------------------------------------------- // toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: // ------------------------------------------------------------------------------- - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag { if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_GENERAL]) { return generalItem; } else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_TABLES]) { return tablesItem; } else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_FAVORITES]) { return favoritesItem; } else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_NOTIFICATIONS]) { return notificationsItem; } else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_AUTOUPDATE]) { return autoUpdateItem; } else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_NETWORK]) { return networkItem; } return [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier] autorelease]; } // ------------------------------------------------------------------------------- // toolbarAllowedItemIdentifiers: // ------------------------------------------------------------------------------- - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar { return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, nil]; } // ------------------------------------------------------------------------------- // toolbarDefaultItemIdentifiers: // ------------------------------------------------------------------------------- - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar { return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, nil]; } // ------------------------------------------------------------------------------- // toolbarSelectableItemIdentifiers: // ------------------------------------------------------------------------------- - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar { return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, nil]; } // ------------------------------------------------------------------------------- // dealloc // ------------------------------------------------------------------------------- - (void)dealloc { [keychain release], keychain = nil; [super dealloc]; } @end #pragma mark - @implementation SPPreferenceController (PrivateAPI) // ------------------------------------------------------------------------------- // _setupToolbar // // Constructs the preferences' window toolbar. // ------------------------------------------------------------------------------- - (void)_setupToolbar { toolbar = [[[NSToolbar alloc] initWithIdentifier:@"Preference Toolbar"] autorelease]; // General preferences generalItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_GENERAL]; [generalItem setLabel:NSLocalizedString(@"General", @"")]; [generalItem setImage:[NSImage imageNamed:@"toolbar-preferences-general"]]; [generalItem setTarget:self]; [generalItem setAction:@selector(displayGeneralPreferences:)]; // Table preferences tablesItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_TABLES]; [tablesItem setLabel:NSLocalizedString(@"Tables", @"")]; [tablesItem setImage:[NSImage imageNamed:@"toolbar-preferences-tables"]]; [tablesItem setTarget:self]; [tablesItem setAction:@selector(displayTablePreferences:)]; // Favorite preferences favoritesItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_FAVORITES]; [favoritesItem setLabel:NSLocalizedString(@"Favorites", @"")]; [favoritesItem setImage:[NSImage imageNamed:@"toolbar-preferences-favorites"]]; [favoritesItem setTarget:self]; [favoritesItem setAction:@selector(displayFavoritePreferences:)]; // Notification preferences notificationsItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_NOTIFICATIONS]; [notificationsItem setLabel:NSLocalizedString(@"Notifications", @"")]; [notificationsItem setImage:[NSImage imageNamed:@"toolbar-preferences-notifications"]]; [notificationsItem setTarget:self]; [notificationsItem setAction:@selector(displayNotificationPreferences:)]; // AutoUpdate preferences autoUpdateItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_AUTOUPDATE]; [autoUpdateItem setLabel:NSLocalizedString(@"Auto Update", @"")]; [autoUpdateItem setImage:[NSImage imageNamed:@"toolbar-preferences-autoupdate"]]; [autoUpdateItem setTarget:self]; [autoUpdateItem setAction:@selector(displayAutoUpdatePreferences:)]; // Network preferences networkItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_NETWORK]; [networkItem setLabel:NSLocalizedString(@"Network", @"")]; [networkItem setImage:[NSImage imageNamed:@"toolbar-preferences-network"]]; [networkItem setTarget:self]; [networkItem setAction:@selector(displayNetworkPreferences:)]; [toolbar setDelegate:self]; [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_GENERAL]; [toolbar setAllowsUserCustomization:NO]; [preferencesWindow setToolbar:toolbar]; [preferencesWindow setShowsToolbarButton:NO]; [self displayGeneralPreferences:nil]; } // ------------------------------------------------------------------------------- // _resizeWindowForContentView: // // Resizes the window to the size of the supplied view. // ------------------------------------------------------------------------------- - (void)_resizeWindowForContentView:(NSView *)view { // remove all current views NSEnumerator *en = [[[preferencesWindow contentView] subviews] objectEnumerator]; NSView *subview; while (subview = [en nextObject]) { [subview removeFromSuperview]; } // resize window [preferencesWindow resizeForContentView:view titleBarVisible:YES]; // add view [[preferencesWindow contentView] addSubview:view]; [view setFrameOrigin:NSMakePoint(0, 0)]; } // ------------------------------------------------------------------------------- // _updateDefaultFavoritePopup: // // Build the default favorite popup button // ------------------------------------------------------------------------------- - (void)_updateDefaultFavoritePopup; { [defaultFavoritePopup removeAllItems]; // Use the last used favorite [defaultFavoritePopup addItemWithTitle:@"Last Used"]; [[defaultFavoritePopup menu] addItem:[NSMenuItem separatorItem]]; // Load in current favorites [defaultFavoritePopup addItemsWithTitles:[[favoritesController arrangedObjects] valueForKeyPath:@"name"]]; // Add item to switch to edit favorites pane [[defaultFavoritePopup menu] addItem:[NSMenuItem separatorItem]]; [defaultFavoritePopup addItemWithTitle:@"Edit Favorites…"]; [[[defaultFavoritePopup menu] itemWithTitle:@"Edit Favorites…"] setAction:@selector(displayFavoritePreferences:)]; [[[defaultFavoritePopup menu] itemWithTitle:@"Edit Favorites…"] setTarget:self]; // Select the default favorite from prefs if (![prefs boolForKey:@"SelectLastFavoriteUsed"]) { [defaultFavoritePopup selectItemAtIndex:[prefs integerForKey:@"DefaultFavorite"] + 2]; } else { [defaultFavoritePopup selectItemAtIndex:0]; } } @end