aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPConnectionControllerDelegate.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2012-10-06 11:48:15 +0000
committerrowanbeentje <rowan@beent.je>2012-10-06 11:48:15 +0000
commitecb5c70566d1303288e4faf170bda40672a799e1 (patch)
tree2882fa5fd6f25eed9c754e810785f5834225b95f /Source/SPConnectionControllerDelegate.m
parentada181f6fe5b010a5ab56030d16b35e92e58af10 (diff)
downloadsequelpro-ecb5c70566d1303288e4faf170bda40672a799e1.tar.gz
sequelpro-ecb5c70566d1303288e4faf170bda40672a799e1.tar.bz2
sequelpro-ecb5c70566d1303288e4faf170bda40672a799e1.zip
Change the connection screen interface, particularly relating to favourite editing on the connection screen (Issue #1339, Issue #1440):
- No longer save changes made to connection favourites as soon as the interface is updated - Alter the interfaace if favourites are editing, offering to save the changes either to the old connection favourite or to a new favourite - Add a "Test connection" button to verify changes before saving - Add a "Quick Connect" entry to the top of the connection view's favourites list so a blank form is always available - Use a custom highlight when editing favourites to show the favourite has changed but is still linked - Reduce the margin on the left-hand side of the connection favourites list to increase the available space - Alter favourite name generation, making it less aggressive when generating names from partial details (eg creating names of just "@") and removing the user - Alter key icon usage to correctly update the button appearance if an SSL or SSH key is selected
Diffstat (limited to 'Source/SPConnectionControllerDelegate.m')
-rw-r--r--Source/SPConnectionControllerDelegate.m220
1 files changed, 136 insertions, 84 deletions
diff --git a/Source/SPConnectionControllerDelegate.m b/Source/SPConnectionControllerDelegate.m
index 30b602cd..e18c43ab 100644
--- a/Source/SPConnectionControllerDelegate.m
+++ b/Source/SPConnectionControllerDelegate.m
@@ -43,19 +43,27 @@
#endif
static NSString *SPDatabaseImage = @"database-small";
+static NSString *SPQuickConnectImage = @"quick-connect-icon.pdf";
+static NSString *SPQuickConnectImageWhite = @"quick-connect-icon-white.pdf";
@interface SPConnectionController ()
+// Privately redeclare as read/write to get the synthesized setter
+@property (readwrite, assign) BOOL isEditingConnection;
+
- (void)_checkHost;
- (void)_sortFavorites;
- (void)_favoriteTypeDidChange;
- (void)_reloadFavoritesViewData;
-- (void)_updateFavoritePasswordsFromField:(NSControl *)control;
- (NSString *)_stripInvalidCharactersFromString:(NSString *)subject;
+- (void)_startEditingConnection;
+- (void)_stopEditingConnection;
- (void)_setNodeIsExpanded:(BOOL)expanded fromNotification:(NSNotification *)notification;
+- (NSString *)_generateNameForConnection;
+
@end
@implementation SPConnectionController (SPConnectionControllerDelegate)
@@ -88,25 +96,27 @@ static NSString *SPDatabaseImage = @"database-small";
return ([[(SPTreeNode *)item parentNode] parentNode] == nil);
}
+- (void)outlineViewSelectionIsChanging:(NSNotification *)notification
+{
+ if (isEditingConnection) {
+ [self _stopEditingConnection];
+ [[notification object] setNeedsDisplay:YES];
+ }
+}
+
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
-{
+{
NSInteger selected = [favoritesOutlineView numberOfSelectedRows];
-
- if (selected == 1) {
- SPTreeNode *node = [self selectedFavoriteNode];
-
- [self updateFavoriteSelection:self];
+ if (isEditingConnection) {
+ [self _stopEditingConnection];
+ [[notification object] setNeedsDisplay:YES];
+ }
- if (![node isGroup]) {
- [addToFavoritesButton setEnabled:NO];
+ if (selected == 1) {
+ [self updateFavoriteSelection:self];
- favoriteNameFieldWasTouched = YES;
- }
- else {
- [addToFavoritesButton setEnabled:YES];
- }
-
+ favoriteNameFieldWasAutogenerated = NO;
[connectionResizeContainer setHidden:NO];
[connectionInstructionsTextField setStringValue:NSLocalizedString(@"Enter connection details below, or choose a favorite", @"enter connection details label")];
}
@@ -116,17 +126,58 @@ static NSString *SPDatabaseImage = @"database-small";
}
}
+- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ if (item == quickConnectItem) {
+ return (NSCell *)quickConnectCell;
+ }
+
+ return [tableColumn dataCellForRow:[outlineView rowForItem:item]];
+}
+
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
SPTreeNode *node = (SPTreeNode *)item;
-
+
+ // Draw entries with the small system font by default
[(SPTableTextFieldCell *)cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- [(SPTableTextFieldCell *)cell setImage:(![[node parentNode] parentNode]) ? nil : (![node isGroup]) ? [NSImage imageNamed:SPDatabaseImage] : folderImage];
+
+ // Set an image as appropriate; the quick connect image for that entry, no image for other
+ // top-level items, the folder image for group nodes, or the database image for other nodes.
+ if (![[node parentNode] parentNode]) {
+ if (node == quickConnectItem) {
+ if ([outlineView rowForItem:item] == [outlineView selectedRow]) {
+ [(SPTableTextFieldCell *)cell setImage:[NSImage imageNamed:SPQuickConnectImageWhite]];
+ } else {
+ [(SPTableTextFieldCell *)cell setImage:[NSImage imageNamed:SPQuickConnectImage]];
+ }
+ } else {
+ [(SPTableTextFieldCell *)cell setImage:nil];
+ }
+ } else {
+ if ([node isGroup]) {
+ [(SPTableTextFieldCell *)cell setImage:folderImage];
+ } else {
+ [(SPTableTextFieldCell *)cell setImage:[NSImage imageNamed:SPDatabaseImage]];
+ }
+ }
+
+ // If a favourite item is being edited, draw the text in bold to show state
+ if (isEditingConnection && ![node isGroup] && [outlineView rowForItem:item] == [outlineView selectedRow]) {
+ NSMutableAttributedString *editedCellString = [[cell attributedStringValue] mutableCopy];
+ [editedCellString addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithDeviceWhite:0.25f alpha:1.f] range:NSMakeRange(0, [editedCellString length])];
+ [cell setAttributedStringValue:editedCellString];
+ [editedCellString release];
+ }
}
- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
- return ([[item parentNode] parentNode]) ? 17 : 22;
+ if (item == quickConnectItem) {
+ return 24.f;
+ }
+
+ return ([[item parentNode] parentNode]) ? 17.f : 22.f;
}
- (NSString *)outlineView:(NSOutlineView *)outlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tableColumn item:(id)item mouseLocation:(NSPoint)mouseLocation
@@ -170,8 +221,18 @@ static NSString *SPDatabaseImage = @"database-small";
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
-{
- return ([[item parentNode] parentNode] != nil);
+{
+
+ // If this is a top level item, only allow the "Quick Connect" item to be selectable
+ if (![[item parentNode] parentNode]) {
+ if (item == quickConnectItem) {
+ return YES;
+ }
+ return NO;
+ }
+
+ // Otherwise allow all items to be selectable
+ return YES;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldShowOutlineCellForItem:(id)item
@@ -184,6 +245,11 @@ static NSString *SPDatabaseImage = @"database-small";
return ([[item parentNode] parentNode] != nil);
}
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ return (item != quickConnectItem);
+}
+
- (void)outlineViewItemDidCollapse:(NSNotification *)notification
{
[self _setNodeIsExpanded:NO fromNotification:notification];
@@ -210,12 +276,12 @@ static NSString *SPDatabaseImage = @"database-small";
}
// If the user is in the process of changing a node's name, trigger a save and prevent dragging.
- if (isEditing) {
+ if (isEditingItemName) {
[favoritesController saveFavorites];
[self _reloadFavoritesViewData];
- isEditing = NO;
+ isEditingItemName = NO;
return NO;
}
@@ -350,77 +416,60 @@ static NSString *SPDatabaseImage = @"database-small";
#ifndef SP_REFACTOR
/**
- * 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 did not
- * change the 'name' field or delete that field it will be set to user@host automatically.
+ * React to control text changes in the connection interface
*/
- (void)controlTextDidChange:(NSNotification *)notification
{
id field = [notification object];
-
+
+ // If a 'name' field was edited, and is now of zero length, trigger a replacement
+ // with a standard suggestion
if (((field == standardNameField) || (field == socketNameField) || (field == sshNameField)) && [self selectedFavoriteNode]) {
-
- favoriteNameFieldWasTouched = YES;
-
- NSString *favoriteName = [self _stripInvalidCharactersFromString:[field stringValue]];
-
- BOOL nameFieldIsEmpty = [favoriteName length] == 0;
-
- switch (previousType)
- {
- case SPTCPIPConnection:
- if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && (field == standardUserField || field == standardSQLHostField))) {
- [standardNameField setStringValue:[NSString stringWithFormat:@"%@@%@", [standardUserField stringValue], [standardSQLHostField stringValue]]];
- }
-
- break;
- case SPSocketConnection:
- if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && field == socketUserField)) {
- [socketNameField setStringValue:[NSString stringWithFormat:@"%@@localhost", [socketUserField stringValue]]];
- }
-
- break;
- case SPSSHTunnelConnection:
- if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && (field == sshUserField || field == sshSQLHostField))) {
- [sshNameField setStringValue:[NSString stringWithFormat:@"%@@%@", [sshUserField stringValue], [sshSQLHostField stringValue]]];
- }
-
- break;
+ if (![[self _stripInvalidCharactersFromString:[field stringValue]] length]) {
+ [self controlTextDidEndEditing:notification];
}
-
- // Trigger KVO update
- [self setName:favoriteName];
-
- // If name field is empty enable user@host update
- if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO;
+ }
+
+ [self _startEditingConnection];
+
+ if (favoriteNameFieldWasAutogenerated) {
+ [self setName:[self _generateNameForConnection]];
}
}
/**
- * When a host field finishes editing, ensure that it hasn't been set to "localhost"
- * to ensure that socket connections don't inadvertently occur.
+ * React to the end of control text changes in the connection interface.
*/
- (void)controlTextDidEndEditing:(NSNotification *)notification
{
- if ([notification object] == standardSQLHostField || [notification object] == sshSQLHostField) {
- [self _checkHost];
+ id field = [notification object];
+
+ // Handle updates to the 'name' field of the selected favourite. The favourite name should
+ // have leading or trailing spaces removed at the end of editing, and if it's left empty,
+ // should have a default name set.
+ if (((field == standardNameField) || (field == socketNameField) || (field == sshNameField)) && [self selectedFavoriteNode]) {
+
+ NSString *favoriteName = [self _stripInvalidCharactersFromString:[field stringValue]];
+
+ if (![favoriteName length]) {
+ favoriteName = [self _generateNameForConnection];
+ if (favoriteName) {
+ [self setName:favoriteName];
+ }
+
+ // Enable user@host update in reaction to other UI changes
+ favoriteNameFieldWasAutogenerated = YES;
+ } else if (![[field stringValue] isEqualToString:[self name]]) {
+ favoriteNameFieldWasAutogenerated = NO;
+ [self setName:favoriteName];
+ }
}
-}
-/**
- * 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 sync with favorites, but only if a favorite
- // is selected, meaning we're editing an existing one, not a new one.
- if (((id)control != (id)favoritesOutlineView) && ([self selectedFavoriteNode])) {
- [self _updateFavoritePasswordsFromField:control];
+ // When a host field finishes editing, ensure that it hasn't been set to "localhost" to
+ // ensure that socket connections don't inadvertently occur.
+ if (field == standardSQLHostField || field == sshSQLHostField) {
+ [self _checkHost];
}
-
- // Proceed with editing
- return YES;
}
#endif
@@ -442,19 +491,18 @@ static NSString *SPDatabaseImage = @"database-small";
NSInteger selectedTabView = [tabView indexOfTabViewItem:tabViewItem];
if (selectedTabView == previousType) return;
-
+
[self resizeTabViewToConnectionType:selectedTabView animating:YES];
// Update the host as appropriate
if ((selectedTabView != SPSocketConnection) && [[self host] isEqualToString:@"localhost"]) {
[self setHost:@""];
}
-
+
previousType = selectedTabView;
-
- // Enable the add to favorites button
- [addToFavoritesButton setEnabled:YES];
-
+
+ [self _startEditingConnection];
+
[self _favoriteTypeDidChange];
}
@@ -510,7 +558,11 @@ static NSString *SPDatabaseImage = @"database-small";
SPTreeNode *node = [self selectedFavoriteNode];
NSInteger selectedRows = [favoritesOutlineView numberOfSelectedRows];
-
+
+ if (node == quickConnectItem) {
+ return NO;
+ }
+
if ((action == @selector(sortFavorites:)) || (action == @selector(reverseSortFavorites:))) {
if ([[favoritesRoot allChildLeafs] count] < 2) return NO;