aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPConnectionControllerDelegate.m
diff options
context:
space:
mode:
authorstuconnolly <stuart02@gmail.com>2012-05-02 13:12:38 +0000
committerstuconnolly <stuart02@gmail.com>2012-05-02 13:12:38 +0000
commit5d87f0f50fc90c7ed47ff82b35f07b2749262132 (patch)
tree37ab959b7385c8f5aaf2d1465e1f19fbd47247c7 /Source/SPConnectionControllerDelegate.m
parentdea294a90f9bf6017986f9c950991a7fc7c9645e (diff)
parentfe555b6d511a51f3bdfb5c0a2b00a3206993076b (diff)
downloadsequelpro-5d87f0f50fc90c7ed47ff82b35f07b2749262132.tar.gz
sequelpro-5d87f0f50fc90c7ed47ff82b35f07b2749262132.tar.bz2
sequelpro-5d87f0f50fc90c7ed47ff82b35f07b2749262132.zip
Merge outline view branch into trunk.
Adds support for managing and grouping favorites into folders in the connection view and removes the associated favorites management from the preferences window. NOTE: On first launch your connection favorites will be migrated from Sequel Pro's preference file to a new file in ~/Application Support/Sequel Pro/Data. Your old favorites will remain in the preference file until removed in a future version. Outstanding known issues: - Removing a group node with no child favorites presents a warning about also removing the non-existent favorites. - Starting the application with no favorites, creating a group node then selecting, hides the connection details input. Doesn't support emoty selection. - Setting the name of a connection, adding it to the favorites and then swicthing to a different connection type, screws with the favorite name. - The preservation between launches of whether group nodes are collapsed or not is currently not supported.
Diffstat (limited to 'Source/SPConnectionControllerDelegate.m')
-rw-r--r--Source/SPConnectionControllerDelegate.m589
1 files changed, 471 insertions, 118 deletions
diff --git a/Source/SPConnectionControllerDelegate.m b/Source/SPConnectionControllerDelegate.m
index 85ddedab..352836e3 100644
--- a/Source/SPConnectionControllerDelegate.m
+++ b/Source/SPConnectionControllerDelegate.m
@@ -24,89 +24,32 @@
// More info at <http://code.google.com/p/sequel-pro/>
#import "SPConnectionControllerDelegate.h"
+#import "SPFavoritesController.h"
#import "SPTableTextFieldCell.h"
+#import "SPPreferenceController.h"
+#import "SPGeneralPreferencePane.h"
+#import "SPAppController.h"
#import "SPFavoriteNode.h"
+#import "SPGroupNode.h"
+#import "SPTreeNode.h"
-@implementation SPConnectionController (SPConnectionControllerDelegate)
+#define CELL(cell) (SPTableTextFieldCell *)cell
+
+static NSString *SPDatabaseImage = @"database-small";
+
+@interface SPConnectionController ()
+
+- (void)_checkHost;
+- (void)_sortFavorites;
+- (void)_favoriteTypeDidChange;
+- (void)_reloadFavoritesViewData;
+- (void)_updateFavoritePasswordsFromField:(NSControl *)control;
+
+- (NSString *)_stripInvalidCharactersFromString:(NSString *)subject;
-/*#pragma mark -
- #pragma mark TableView drag & drop delegate methods
-
- - (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
- {
- NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
- [pboard declareTypes:[NSArray arrayWithObject:favoritesPBoardType] owner:self];
- [pboard setData:archivedData forType:favoritesPBoardType];
- return YES;
- }
-
- - (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation
- {
- if (row == 0) return NSDragOperationNone;
- if ([info draggingSource] == aTableView)
- {
- [aTableView setDropRow:row dropOperation:NSTableViewDropAbove];
- return NSDragOperationMove;
- }
- return NSDragOperationNone;
- }
-
- - (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
- {
- BOOL acceptedDrop = NO;
-
- if ((row == 0) || ([info draggingSource] != aTableView)) return acceptedDrop;
-
- // Disable all automatic sorting
- currentSortItem = -1;
- reverseFavoritesSort = NO;
-
- [prefs setInteger:currentSortItem forKey:SPFavoritesSortedBy];
- [prefs setBool:NO forKey:SPFavoritesSortedInReverse];
-
- // Remove sort descriptors
- [favorites sortUsingDescriptors:[NSArray array]];
-
- // Uncheck sort by menu items
- for (NSMenuItem *menuItem in [[favoritesSortByMenuItem submenu] itemArray])
- {
- [menuItem setState:NSOffState];
- }
-
- NSPasteboard* pboard = [info draggingPasteboard];
- NSData* rowData = [pboard dataForType:favoritesPBoardType];
- NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];
- NSInteger dragRow = [rowIndexes firstIndex];
- NSInteger defaultConnectionRow = [prefs integerForKey:SPLastFavoriteIndex];
- if (defaultConnectionRow == dragRow)
- {
- [prefs setInteger:row forKey:SPLastFavoriteIndex];
- }
- NSMutableDictionary *draggedFavorite = [favorites objectAtIndex:dragRow];
- [favorites removeObjectAtIndex:dragRow];
- if (row > dragRow)
- {
- row--;
- }
- [favorites insertObject:draggedFavorite atIndex:row];
- [aTableView reloadData];
-
- // reset the prefs with the new order
- NSMutableArray *reorderedFavorites = [[NSMutableArray alloc] initWithArray:favorites];
- [reorderedFavorites removeObjectAtIndex:0];
- [prefs setObject:reorderedFavorites forKey:SPFavorites];
-
- [[[[NSApp delegate] preferenceController] generalPreferencePane] updateDefaultFavoritePopup];
-
- [reorderedFavorites release];
-
- [self updateFavorites];
- [aTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
-
- acceptedDrop = YES;
-
- return acceptedDrop;
- }*/
+@end
+
+@implementation SPConnectionController (SPConnectionControllerDelegate)
#pragma mark -
#pragma mark SplitView delegate methods
@@ -118,92 +61,502 @@
/**
* When the split view is resized, trigger a resize in the hidden table
- * width as well, to keep the connection view and connected view in synch.
+ * width as well, to keep the connection view and connected view in sync.
*/
-- (void)splitViewDidResizeSubviews:(NSNotification *)aNotification
+- (void)splitViewDidResizeSubviews:(NSNotification *)notification
{
[databaseConnectionView setPosition:[[[connectionSplitView subviews] objectAtIndex:0] frame].size.width ofDividerAtIndex:0];
}
#pragma mark -
-#pragma mark Outline view datasource methods
+#pragma mark Outline view delegate methods
-- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
-{
- SPFavoriteNode *node = (item == nil ? favoritesRoot : (SPFavoriteNode *)item);
+- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
+{
+ return ([[(SPTreeNode *)item parentNode] parentNode] == nil);
+}
+
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+ NSInteger selected = [favoritesOutlineView numberOfSelectedRows];
- return [[node nodeChildren] count];
+ if (selected == 1) {
+
+ SPTreeNode *node = [self selectedFavoriteNode];
+
+ if (![node isGroup]) {
+ [self updateFavoriteSelection:self];
+
+ [addToFavoritesButton setEnabled:NO];
+
+ favoriteNameFieldWasTouched = YES;
+
+ [connectionResizeContainer setHidden:NO];
+ [connectionInstructionsTextField setStringValue:NSLocalizedString(@"Enter connection details below, or choose a favorite", @"enter connection details label")];
+ }
+ else {
+ [connectionResizeContainer setHidden:YES];
+ [connectionInstructionsTextField setStringValue:NSLocalizedString(@"Please choose a favorite", @"please choose a favorite connection view label")];
+ }
+ }
+ else if (selected > 1) {
+ [connectionResizeContainer setHidden:YES];
+ [connectionInstructionsTextField setStringValue:NSLocalizedString(@"Please choose a favorite", @"please choose a favorite connection view label")];
+ }
}
-- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)anIndex ofItem:(id)item
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
- SPFavoriteNode *node = (item == nil ? favoritesRoot : (SPFavoriteNode *)item);
+ SPTreeNode *node = (SPTreeNode *)item;
+
+ [CELL(cell) setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- return NSArrayObjectAtIndex([node nodeChildren], anIndex);
+ [CELL(cell) setTextColor:([favoritesOutlineView isEnabled]) ? [NSColor blackColor] : [NSColor grayColor]];
+
+ if (![[node parentNode] parentNode]) {
+ [CELL(cell) setImage:nil];
+ }
+ else {
+ [CELL(cell) setImage:(![node isGroup]) ? [NSImage imageNamed:SPDatabaseImage] : folderImage];
+ }
}
-- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
-{
- return [(SPFavoriteNode *)item nodeIsGroup];
+- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
+{
+ return ([[item parentNode] parentNode]) ? 17 : 22;
}
-- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
+- (NSString *)outlineView:(NSOutlineView *)outlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tableColumn item:(id)item mouseLocation:(NSPoint)mouseLocation
{
- SPFavoriteNode *node = (SPFavoriteNode *)item;
+ NSString *toolTip = nil;
+
+ SPTreeNode *node = (SPTreeNode *)item;
+
+ if (![node isGroup]) {
+
+ NSString *favoriteName = [[[node representedObject] nodeFavorite] objectForKey:SPFavoriteNameKey];
+ NSString *favoriteHostname = [[[node representedObject] nodeFavorite] objectForKey:SPFavoriteHostKey];
+
+ toolTip = ([favoriteHostname length]) ? [NSString stringWithFormat:@"%@ (%@)", favoriteName, favoriteHostname] : favoriteName;
+ }
+ // Only display a tooltip for group nodes that are a child of the root node
+ else if ([[node parentNode] parentNode]) {
+ NSUInteger favCount = [[node childNodes] count];
+
+ toolTip = [NSString stringWithFormat:@"%@ - %d %@", [[node representedObject] nodeName], favCount, (favCount == 1) ? NSLocalizedString(@"favorite", @"favorite singular label") : NSLocalizedString(@"favorites", @"favorites plural label")];
+ }
- return ([node nodeIsGroup]) ? [node nodeName] : [[node nodeFavorite] objectForKey:SPFavoriteNameKey];
+ return toolTip;
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
+{
+ return ([[item parentNode] parentNode] != nil);
}
#pragma mark -
-#pragma mark Outline view delegate methods
+#pragma mark Outline view drag & drop
-- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
+- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
+{
+ // If the user is in the process of changing a node's name, trigger a save and prevent dragging.
+ if (isEditing) {
+ [favoritesController saveFavorites];
+
+ [self _reloadFavoritesViewData];
+
+ isEditing = NO;
+
+ return NO;
+ }
+
+ [pboard declareTypes:[NSArray arrayWithObject:SPFavoritesPasteboardDragType] owner:self];
+
+ BOOL result = [pboard setData:[NSData data] forType:SPFavoritesPasteboardDragType];
+
+ draggedNodes = items;
+
+ return result;
+}
+
+- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
- return [(SPFavoriteNode *)item nodeIsGroup];
+ NSDragOperation result = NSDragOperationNone;
+
+ // Prevent dropping favorites on other favorites (non-groups)
+ if ((index == NSOutlineViewDropOnItemIndex) && (![item isGroup])) return result;
+
+ if ([info draggingSource] == outlineView) {
+ [outlineView setDropItem:item dropChildIndex:index];
+
+ result = NSDragOperationMove;
+ }
+
+ return result;
}
-- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
{
- if ([favoritesTable numberOfSelectedRows] == 1) {
- [self updateFavoriteSelection:self];
+ BOOL acceptedDrop = NO;
+
+ if ((!item) || ([info draggingSource] != outlineView)) return acceptedDrop;
+
+ SPTreeNode *node = item ? item : [[[[favoritesRoot childNodes] objectAtIndex:0] childNodes] objectAtIndex:0];
- [addToFavoritesButton setEnabled:NO];
- }
+ // Disable all automatic sorting
+ currentSortItem = -1;
+ reverseFavoritesSort = NO;
+
+ [prefs setInteger:currentSortItem forKey:SPFavoritesSortedBy];
+ [prefs setBool:NO forKey:SPFavoritesSortedInReverse];
+
+ // Uncheck sort by menu items
+ for (NSMenuItem *menuItem in [[favoritesSortByMenuItem submenu] itemArray])
+ {
+ [menuItem setState:NSOffState];
+ }
+
+ NSArray *nodes = draggedNodes;
+
+ if (![nodes count]) return acceptedDrop;
+
+ if ([node isGroup]) {
+ if (index == NSOutlineViewDropOnItemIndex) {
+ index = 0;
+ }
+ }
else {
- [addToFavoritesButton setEnabled:YES];
+ if (index == NSOutlineViewDropOnItemIndex) {
+ index = 0;
+ }
}
+
+ if (![[node representedObject] nodeName]) {
+ node = [[favoritesRoot childNodes] objectAtIndex:0];
+ }
+
+ NSMutableArray *childNodeArray = [node mutableChildNodes];
+
+ for (SPTreeNode *treeNode in nodes)
+ {
+ // Remove the node from its old location
+ NSInteger oldIndex = [childNodeArray indexOfObject:treeNode];
+ NSInteger newIndex = index;
+
+ if (oldIndex != NSNotFound) {
+
+ [childNodeArray removeObjectAtIndex:oldIndex];
+
+ if (index > oldIndex) {
+ newIndex--;
+ }
+ }
+ else {
+ [[[treeNode parentNode] mutableChildNodes] removeObject:treeNode];
+ }
+
+ [childNodeArray insertObject:treeNode atIndex:newIndex];
+
+ newIndex++;
+ }
+
+ [favoritesController saveFavorites];
+
+ [self _reloadFavoritesViewData];
+
+ [[[[NSApp delegate] preferenceController] generalPreferencePane] updateDefaultFavoritePopup];
+
+ acceptedDrop = YES;
+
+ return acceptedDrop;
}
-- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
+#pragma mark -
+#pragma mark Textfield delegate methods
+
+/**
+ * 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.
+ */
+- (void)controlTextDidChange:(NSNotification *)notification
{
- [(SPTableTextFieldCell *)cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ id field = [notification object];
- if ([favoritesTable isEnabled]) {
- [(SPTableTextFieldCell *)cell setTextColor:[NSColor blackColor]];
+ if (((field == standardNameField) || (field == socketNameField) || (field == sshNameField)) && [self selectedFavoriteNode]) {
+
+ [field setStringValue:[self _stripInvalidCharactersFromString:[field stringValue]]];
+
+ favoriteNameFieldWasTouched = YES;
+
+ BOOL nameFieldIsEmpty = [[field stringValue] isEqualToString:@""];
+
+ switch (previousType)
+ {
+ case SPTCPIPConnection:
+
+ nameFieldIsEmpty = (nameFieldIsEmpty || [[standardNameField stringValue] isEqualToString:@""]);
+
+ if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && (field == standardUserField || field == standardSQLHostField))) {
+ [standardNameField setStringValue:[NSString stringWithFormat:@"%@@%@", [standardUserField stringValue], [standardSQLHostField stringValue]]];
+
+ // Trigger KVO update
+ [self setName:[standardNameField stringValue]];
+
+ // If name field is empty enable user@host update
+ if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO;
+ }
+
+ break;
+ case SPSocketConnection:
+
+ nameFieldIsEmpty = (nameFieldIsEmpty || [[socketNameField stringValue] isEqualToString:@""]);
+
+ if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && field == socketUserField)) {
+ [socketNameField setStringValue:[NSString stringWithFormat:@"%@@localhost", [socketUserField stringValue]]];
+
+ // Trigger KVO update
+ [self setName:[socketNameField stringValue]];
+
+ // If name field is empty enable user@host update
+ if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO;
+ }
+
+ break;
+ case SPSSHTunnelConnection:
+
+ nameFieldIsEmpty = (nameFieldIsEmpty || [[sshNameField stringValue] isEqualToString:@""]);
+
+ if (nameFieldIsEmpty || (!favoriteNameFieldWasTouched && (field == sshUserField || field == sshSQLHostField))) {
+ [sshNameField setStringValue:[NSString stringWithFormat:@"%@@%@", [sshUserField stringValue], [sshSQLHostField stringValue]]];
+
+ // Trigger KVO update
+ [self setName:[sshNameField stringValue]];
+
+ // If name field is empty enable user@host update
+ if (nameFieldIsEmpty) favoriteNameFieldWasTouched = NO;
+ }
+
+ break;
+ }
}
- else {
- [(SPTableTextFieldCell *)cell setTextColor:[NSColor grayColor]];
+}
+
+/**
+ * When a host field finishes editing, ensure that it hasn't been set to "localhost"
+ * to ensure that socket connections don't inadvertently occur.
+ */
+- (void)controlTextDidEndEditing:(NSNotification *)notification
+{
+ if ([notification object] == standardSQLHostField || [notification object] == sshSQLHostField) {
+ [self _checkHost];
+ }
+}
+
+/**
+ * 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];
}
- [(SPTableTextFieldCell *)cell setImage:([(SPFavoriteNode *)item nodeIsGroup]) ? nil : [NSImage imageNamed:@"database-small"]];
+ // Proceed with editing
+ return YES;
}
-- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
+#pragma mark -
+#pragma mark Tab bar delegate methods
+
+/**
+ * Trigger a resize action whenever the tab view changes. The connection
+ * detail forms are held within container views, which are of a fixed width;
+ * the tabview and buttons are contained within a resizable view which
+ * is set to dimensions based on the container views, allowing the view
+ * to be sized according to the detail type.
+ */
+- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ NSInteger selectedTabView = [tabView indexOfTabViewItem:tabViewItem];
+
+ // Deselect any selected favorite for manual changes
+ if (!automaticFavoriteSelection) [favoritesOutlineView deselectAll:self];
+ automaticFavoriteSelection = NO;
+
+ 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 _favoriteTypeDidChange];
+}
+
+#pragma mark -
+#pragma mark Scroll view notifications
+
+/**
+ * As the scrollview resizes, keep the details centered within it if
+ * the detail frame is larger than the scrollview size; otherwise, pin
+ * the detail frame to the top of the scrollview.
+ */
+- (void)scrollViewFrameChanged:(NSNotification *)aNotification
{
- return ([item nodeIsGroup]) ? 22 : 17;
+ NSRect scrollViewFrame = [connectionDetailsScrollView frame];
+ NSRect scrollDocumentFrame = [[connectionDetailsScrollView documentView] frame];
+ NSRect connectionDetailsFrame = [connectionResizeContainer frame];
+
+ // Scroll view is smaller than contents - keep positioned at top.
+ if (scrollViewFrame.size.height < connectionDetailsFrame.size.height + 10) {
+ if (connectionDetailsFrame.origin.y != 0) {
+ connectionDetailsFrame.origin.y = 0;
+ [connectionResizeContainer setFrame:connectionDetailsFrame];
+ scrollDocumentFrame.size.height = connectionDetailsFrame.size.height + 10;
+ [[connectionDetailsScrollView documentView] setFrame:scrollDocumentFrame];
+ }
+ }
+ // Otherwise, center
+ else {
+ connectionDetailsFrame.origin.y = (scrollViewFrame.size.height - connectionDetailsFrame.size.height)/3;
+ [connectionResizeContainer setFrame:connectionDetailsFrame];
+ scrollDocumentFrame.size.height = scrollViewFrame.size.height;
+ [[connectionDetailsScrollView documentView] setFrame:scrollDocumentFrame];
+ }
}
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
+#pragma mark -
+#pragma mark Menu Validation
+
+/**
+ * Menu item validation.
+ */
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
- return (![item nodeIsGroup]);
+ SEL action = [menuItem action];
+
+ SPTreeNode *node = [self selectedFavoriteNode];
+
+ if ((action == @selector(sortFavorites:)) || (action == @selector(reverseSortFavorites:))) {
+
+ // 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) ? NSOnState : NSOffState];
+ }
+
+ // Check or uncheck the reverse sort item
+ if (action == @selector(reverseSortFavorites:)) {
+ [menuItem setState:reverseFavoritesSort];
+ }
+ }
+
+ // Remove the selected favorite
+ if (action == @selector(removeNode:)) {
+ return ([favoritesOutlineView numberOfSelectedRows] == 1);
+ }
+
+ // Duplicate and make the selected favorite the default
+ if (action == @selector(duplicateFavorite:)) {
+ return (([favoritesOutlineView numberOfSelectedRows] == 1) && (![node isGroup]));
+ }
+
+ // Make selected favorite the default
+ if (action == @selector(makeSelectedFavoriteDefault:)) {
+ NSInteger favoriteID = [[[self selectedFavorite] objectForKey:SPFavoriteIDKey] integerValue];
+
+ return (([favoritesOutlineView numberOfSelectedRows] == 1) && (![node isGroup]) && (favoriteID != [prefs integerForKey:SPDefaultFavorite]));
+ }
+
+ // Rename selected favorite/group
+ if (action == @selector(renameFavorite:)) {
+ return ([favoritesOutlineView numberOfSelectedRows] == 1);
+ }
+
+ // Favorites export
+ if (action == @selector(exportFavorites:)) {
+
+ NSInteger rows = [favoritesOutlineView numberOfSelectedRows];
+
+ if (rows > 1) {
+ [menuItem setTitle:NSLocalizedString(@"Export Selected...", @"export selected favorites menu item")];
+ }
+ else if (rows == 1) {
+ return (![[self selectedFavoriteNode] isGroup]);
+ }
+ }
+
+ return YES;
}
+#pragma mark -
+#pragma mark Favorites import/export delegate methods
+
+/**
+ * Called by the favorites exporter when the export completes.
+ */
+- (void)favoritesExportCompletedWithError:(NSError *)error
+{
+ if (error) {
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Favorites export error", @"favorites export error message")
+ defaultButton:NSLocalizedString(@"OK", @"OK")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"The following error occurred during the export process:\n\n%@", @"favorites export error informative message"), [error localizedDescription]]];
+
+ [alert beginSheetModalForWindow:[dbDocument parentWindow]
+ modalDelegate:self
+ didEndSelector:NULL
+ contextInfo:NULL];
+ }
+}
/**
- * Prevent editing of outline view rows
+ * Called by the favorites importer when the imported data is available.
*/
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+- (void)favoritesImportData:(NSArray *)data
{
- return NO;
+ // Add each of the imported favorites to the root node
+ for (NSMutableDictionary *favorite in data)
+ {
+ [favoritesController addFavoriteNodeWithData:favorite asChildOfNode:nil];
+ }
+
+ if (currentSortItem > SPFavoritesSortUnsorted) {
+ [self _sortFavorites];
+ }
+
+ [self _reloadFavoritesViewData];
+}
+
+/**
+ * Called by the favorites importer when the import completes.
+ */
+- (void)favoritesImportCompletedWithError:(NSError *)error
+{
+ if (error) {
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Favorites import error", @"favorites import error message")
+ defaultButton:NSLocalizedString(@"OK", @"OK")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"The following error occurred during the import process:\n\n%@", @"favorites import error informative message"), [error localizedDescription]]];
+
+ [alert beginSheetModalForWindow:[dbDocument parentWindow]
+ modalDelegate:self
+ didEndSelector:NULL
+ contextInfo:NULL];
+ }
}
+
@end