// // $Id$ // // SPConnectionControllerInitializer.m // sequel-pro // // Created by Stuart Connolly (stuconnolly.com) on January 22, 2012. // Copyright (c) 2012 Stuart Connolly. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // More info at <http://code.google.com/p/sequel-pro/> #import "SPConnectionControllerInitializer.h" #import "SPKeychain.h" #import "SPFavoritesController.h" #import "SPFavoriteTextFieldCell.h" #import "SPTreeNode.h" #import "SPFavoriteNode.h" #import "SPGroupNode.h" #import "SPDatabaseViewController.h" #import "SPSplitView.h" #import "SPFavoriteColorSupport.h" #import "SPColorSelectorView.h" #ifndef SP_CODA static NSString *SPConnectionViewNibName = @"ConnectionView"; #endif @interface SPConnectionController () - (void)_processFavoritesDataChange; - (void)_reloadFavoritesViewData; - (void)_selectNode:(SPTreeNode *)node; - (void)_scrollToSelectedNode; - (void)_documentWillClose:(NSNotification *)notification; - (SPTreeNode *)_favoriteNodeForFavoriteID:(NSInteger)favoriteID; - (void)scrollViewFrameChanged:(NSNotification *)aNotification; @end @interface SPConnectionController (SPConnectionControllerInitializer_Private_API) - (void)_restoreOutlineViewStateNode:(SPTreeNode *)node; @end @implementation SPConnectionController (SPConnectionControllerInitializer) /** * Initialise the connection controller, linking it to the parent document and setting up the parent window. */ - (id)initWithDocument:(SPDatabaseDocument *)document { if ((self = [super init])) { // Weak reference dbDocument = document; #ifndef SP_CODA databaseConnectionSuperview = [dbDocument databaseView]; databaseConnectionView = [dbDocument valueForKey:@"contentViewSplitter"]; #endif // Keychain references connectionKeychainID = nil; connectionKeychainItemName = nil; connectionKeychainItemAccount = nil; connectionSSHKeychainItemName = nil; connectionSSHKeychainItemAccount = nil; initComplete = NO; isEditingItemName = NO; isConnecting = NO; isTestingConnection = NO; sshTunnel = nil; mySQLConnection = nil; cancellingConnection = NO; favoriteNameFieldWasAutogenerated = NO; [self loadNib]; NSArray *colorList = [[SPFavoriteColorSupport sharedInstance] userColorList]; [sshColorField setColorList:colorList]; [sshColorField bind:@"selectedTag" toObject:self withKeyPath:@"colorIndex" options:nil]; [standardColorField setColorList:colorList]; [standardColorField bind:@"selectedTag" toObject:self withKeyPath:@"colorIndex" options:nil]; [socketColorField setColorList:colorList]; [socketColorField bind:@"selectedTag" toObject:self withKeyPath:@"colorIndex" options:nil]; [self registerForNotifications]; #ifndef SP_CODA // Hide the main view and position and display the connection view [databaseConnectionView setHidden:YES]; [connectionView setFrame:[databaseConnectionView frame]]; [databaseConnectionSuperview addSubview:connectionView]; // Set up the splitview [connectionSplitView setMinSize:80.f ofSubviewAtIndex:0]; [connectionSplitView setMinSize:445.f ofSubviewAtIndex:1]; // Generic folder image for use in the outline view's groups folderImage = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)] retain]; [folderImage setSize:NSMakeSize(16, 16)]; // Set up a keychain instance and preferences reference, and create the initial favorites list keychain = [[SPKeychain alloc] init]; prefs = [[NSUserDefaults standardUserDefaults] retain]; // Create a reference to the favorites controller, forcing the data to be loaded from disk // and the tree to be constructed. favoritesController = [SPFavoritesController sharedFavoritesController]; // Tree references favoritesRoot = [favoritesController favoritesTree]; currentFavorite = nil; // Create the "Quick Connect" placeholder group quickConnectItem = [[SPTreeNode treeNodeWithRepresentedObject:[SPGroupNode groupNodeWithName:[NSLocalizedString(@"Quick Connect", @"Quick connect item label") uppercaseString]]] retain]; [quickConnectItem setIsGroup:YES]; // Create a NSOutlineView cell for the Quick Connect group quickConnectCell = [[SPFavoriteTextFieldCell alloc] init]; [quickConnectCell setDrawsDividerUnderCell:YES]; [quickConnectCell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; // Update the UI [self _reloadFavoritesViewData]; [self setUpFavoritesOutlineView]; [self _restoreOutlineViewStateNode:favoritesRoot]; // Set up the selected favourite, and scroll after a small delay to fix animation delay on Lion [self setUpSelectedConnectionFavorite]; if ([favoritesOutlineView selectedRow] != -1) { [self performSelector:@selector(_scrollToSelectedNode) withObject:nil afterDelay:0.0]; } // Set sort items currentSortItem = (SPFavoritesSortItem)[prefs integerForKey:SPFavoritesSortedBy]; reverseFavoritesSort = [prefs boolForKey:SPFavoritesSortedInReverse]; #endif initComplete = YES; } return self; } /** * Loads the connection controllers UI nib. */ - (void)loadNib { #ifndef SP_CODA // Load the connection nib, keeping references to the top-level objects for later release nibObjectsToRelease = [[NSMutableArray alloc] init]; NSArray *connectionViewTopLevelObjects = nil; NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:SPConnectionViewNibName bundle:[NSBundle mainBundle]]; [nibLoader instantiateNibWithOwner:self topLevelObjects:&connectionViewTopLevelObjects]; [nibObjectsToRelease addObjectsFromArray:connectionViewTopLevelObjects]; [nibLoader release]; #endif } /** * Registers for various notifications. */ - (void)registerForNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_documentWillClose:) name:SPDocumentWillCloseNotification object:dbDocument]; #ifndef SP_CODA [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollViewFrameChanged:) name:NSViewFrameDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_processFavoritesDataChange:) name:SPConnectionFavoritesChangedNotification object:nil]; // Registered to be notified of changes to connection information [self addObserver:self forKeyPath:SPFavoriteTypeKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteNameKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteHostKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteUserKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteColorIndexKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteDatabaseKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSocketKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoritePortKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteUseSSLKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSHHostKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSHUserKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSHPortKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSHKeyLocationEnabledKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSHKeyLocationKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSLKeyFileLocationEnabledKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSLKeyFileLocationKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSLCertificateFileLocationEnabledKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSLCertificateFileLocationKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSLCACertFileLocationEnabledKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; [self addObserver:self forKeyPath:SPFavoriteSSLCACertFileLocationKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; #endif } /** * Performs any set up necessary for the favorities outline view. */ - (void)setUpFavoritesOutlineView { // Register double click action for the favorites outline view (double click favorite to connect) [favoritesOutlineView setTarget:self]; [favoritesOutlineView setDoubleAction:@selector(nodeDoubleClicked:)]; // Register drag types for the favorites outline view [favoritesOutlineView registerForDraggedTypes:[NSArray arrayWithObject:SPFavoritesPasteboardDragType]]; [favoritesOutlineView setDraggingSourceOperationMask:NSDragOperationMove forLocal:YES]; } /** * Sets up the selected connection favorite according to the user's preferences. */ - (void)setUpSelectedConnectionFavorite { #ifndef SP_CODA SPTreeNode *favorite = [self _favoriteNodeForFavoriteID:[prefs integerForKey:[prefs boolForKey:SPSelectLastFavoriteUsed] ? SPLastFavoriteID : SPDefaultFavorite]]; if (favorite) { if (favorite == quickConnectItem) { [self _selectNode:favorite]; } else { NSNumber *typeNumber = [[[favorite representedObject] nodeFavorite] objectForKey:SPFavoriteTypeKey]; previousType = typeNumber ? [typeNumber integerValue] : SPTCPIPConnection; [self _selectNode:favorite]; [self resizeTabViewToConnectionType:[[[[favorite representedObject] nodeFavorite] objectForKey:SPFavoriteTypeKey] integerValue] animating:NO]; } [self _scrollToSelectedNode]; } else { previousType = SPTCPIPConnection; [self resizeTabViewToConnectionType:SPTCPIPConnection animating:NO]; } #endif } #pragma mark - #pragma mark Private API /** * Responds to notifications that the favorites root has changed, * and updates the interface to match. */ - (void)_processFavoritesDataChange:(NSNotification *)aNotification { #ifndef SP_CODA // Check the supplied notification for the sender; if the sender // was this object, ignore it if ([aNotification object] == self) return; NSArray *selectedFavoriteNodes = [self selectedFavoriteNodes]; [self _reloadFavoritesViewData]; NSMutableIndexSet *selectionIndexes = [NSMutableIndexSet indexSet]; for (SPTreeNode *eachNode in selectedFavoriteNodes) { NSInteger anIndex = [favoritesOutlineView rowForItem:eachNode]; if (anIndex == -1) continue; [selectionIndexes addIndex:anIndex]; } [favoritesOutlineView selectRowIndexes:selectionIndexes byExtendingSelection:NO]; #endif } /** * Restores the outline views group nodes expansion state. * * @param node The node to traverse */ #ifndef SP_CODA - (void)_restoreOutlineViewStateNode:(SPTreeNode *)node { if ([node isGroup]) { if ([[node representedObject] nodeIsExpanded]) { [favoritesOutlineView expandItem:node]; } else { [favoritesOutlineView collapseItem:node]; } for (SPTreeNode *childNode in [node childNodes]) { if ([childNode isGroup]) { [self _restoreOutlineViewStateNode:childNode]; } } } } #endif @end