From b5cabd449156acaf18815759ee4cc5383e8fa4f6 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Sun, 21 Mar 2010 22:17:50 +0000 Subject: =?UTF-8?q?=E2=80=A2=20Navigator=20-=20added=20'sync'=20mode=20-?= =?UTF-8?q?=20the=20navigator=20follows=20the=20active=20window=20db/table?= =?UTF-8?q?=20selection=20if=20navigator=20has=20not=20multiple=20selected?= =?UTF-8?q?=20items=20-=20added=20drag=20support=20of=20selected=20items?= =?UTF-8?q?=20--=20as=20comma=20separated=20and=20backtick=20quoted=20stri?= =?UTF-8?q?ng=20for=20external=20apps=20--=20as=20array=20of=20schema=20pa?= =?UTF-8?q?ths=20for=20SP=20=E2=80=A2=20CMTextView=20-=20added=20drop=20su?= =?UTF-8?q?pport=20for=20selected=20items=20coming=20from=20the=20Navigato?= =?UTF-8?q?r=20-=20insert=20them=20as=20comma=20list=20relative=20to=20cur?= =?UTF-8?q?rent=20selected=20db/table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Interfaces/English.lproj/Navigator.xib | 94 +++++++++++++++++++--- Source/CMTextView.m | 38 +++++++++ Source/SPNavigatorController.h | 4 + Source/SPNavigatorController.m | 137 ++++++++++++++++++++++++++++++++- Source/TableDocument.m | 30 ++++++++ Source/TablesList.m | 15 ++++ 6 files changed, 307 insertions(+), 11 deletions(-) diff --git a/Interfaces/English.lproj/Navigator.xib b/Interfaces/English.lproj/Navigator.xib index d4dd1904..974f8160 100644 --- a/Interfaces/English.lproj/Navigator.xib +++ b/Interfaces/English.lproj/Navigator.xib @@ -21,7 +21,7 @@ YES - + YES @@ -57,7 +57,7 @@ NSPanel {3.40282e+38, 3.40282e+38} - {150, 200} + {200, 200} 256 @@ -66,7 +66,7 @@ 270 - {{20, 336}, {241, 19}} + {{20, 336}, {174, 19}} 2 YES @@ -240,6 +240,7 @@ 3 YES + YES @@ -266,6 +267,7 @@ 3 YES + YES @@ -290,7 +292,7 @@ 14 - 1379926016 + 1514143744 SPNavigatorSchema1 @@ -435,6 +437,7 @@ 3 YES + YES @@ -461,6 +464,7 @@ 3 YES + YES @@ -477,7 +481,7 @@ 14 - 1379926016 + 1514143744 SPNavigatorSchema2 @@ -623,7 +627,7 @@ YES - 256 + 272 YES @@ -1061,13 +1065,37 @@ 75 + + + 265 + {{309, 337}, {42, 17}} + + YES + + 67239424 + 134348800 + sync + + LucidaGrande-Bold + 12 + 16 + + + -1228128001 + 402653357 + + s + 400 + 75 + + {395, 359} 2 {{0, 0}, {1280, 778}} - {150, 222} + {200, 222} {3.40282e+38, 3.40282e+38} @@ -1219,6 +1247,22 @@ 107 + + + syncButton + + + + 110 + + + + syncButtonAction: + + + + 111 + @@ -1265,6 +1309,7 @@ + @@ -1619,6 +1664,20 @@ + + 108 + + + YES + + + + + + 109 + + + @@ -1628,6 +1687,9 @@ -1.IBPluginDependency -2.IBPluginDependency -3.IBPluginDependency + 108.IBAttributePlaceholdersKey + 108.IBPluginDependency + 109.IBPluginDependency 13.IBPluginDependency 14.IBPluginDependency 15.IBPluginDependency @@ -1695,6 +1757,16 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Synchronize connection window selection with Navigator (⌥⌘S) + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.brandonwalkin.BWToolkit com.brandonwalkin.BWToolkit com.brandonwalkin.BWToolkit @@ -1716,7 +1788,7 @@ {{72, 342}, {395, 359}} - {150, 200} + {200, 200} ImageAndTextCell com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -1781,7 +1853,7 @@ - 107 + 111 @@ -1804,6 +1876,7 @@ filterTree: outlineViewAction: reloadAllStructures: + syncButtonAction: updateEntries: @@ -1812,6 +1885,7 @@ id id id + id @@ -1824,6 +1898,7 @@ outlineSchema2 quickAccessTable searchField + syncButton YES @@ -1833,6 +1908,7 @@ id id id + id diff --git a/Source/CMTextView.m b/Source/CMTextView.m index 6d6befc8..2a5c43c7 100644 --- a/Source/CMTextView.m +++ b/Source/CMTextView.m @@ -3056,6 +3056,44 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) } return YES; } + + // Insert selected items coming from the Navigator + if ( [[pboard types] containsObject:@"SPDragFromNavigatorPboardType"] ) { + NSPoint draggingLocation = [sender draggingLocation]; + draggingLocation = [self convertPoint:draggingLocation fromView:nil]; + NSUInteger characterIndex = [self characterIndexOfPoint:draggingLocation]; + [self setSelectedRange:NSMakeRange(characterIndex,0)]; + + NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:[pboard dataForType:@"SPDragFromNavigatorPboardType"]] autorelease]; + NSArray *draggedItems = [[NSArray alloc] initWithArray:(NSArray *)[unarchiver decodeObjectForKey:@"itemdata"]]; + [unarchiver finishDecoding]; + + NSMutableString *dragString = [NSMutableString string]; + NSMutableString *aPath = [NSMutableString string]; + + NSString *currentDb = nil; + NSString *currentTable = nil; + + if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"selectedDatabase"] != nil) + currentDb = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"]; + if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"tableName"] != nil) + currentTable = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"tableName"]; + + if(!currentDb) currentDb = @""; + if(!currentTable) currentTable = @""; + + for(NSString* item in draggedItems) { + if([dragString length]) [dragString appendString:@", "]; + [aPath setString:item]; + // Insert path relative to the current selected db and table if any + [aPath replaceOccurrencesOfRegex:[NSString stringWithFormat:@"^%@%@", currentDb, SPUniqueSchemaDelimiter] withString:@""]; + [aPath replaceOccurrencesOfRegex:[NSString stringWithFormat:@"^%@%@", currentTable, SPUniqueSchemaDelimiter] withString:@""]; + [dragString appendString:[[aPath componentsSeparatedByString:SPUniqueSchemaDelimiter] componentsJoinedByPeriodAndBacktickQuoted]]; + } + [self breakUndoCoalescing]; + [self insertText:dragString]; + return YES; + } return [super performDragOperation:sender]; } diff --git a/Source/SPNavigatorController.h b/Source/SPNavigatorController.h index c0789c4f..6895a9f2 100644 --- a/Source/SPNavigatorController.h +++ b/Source/SPNavigatorController.h @@ -34,6 +34,7 @@ IBOutlet id infoTable; IBOutlet id quickAccessTable; IBOutlet id searchField; + IBOutlet id syncButton; NSUserDefaults *prefs; @@ -56,10 +57,13 @@ - (IBAction)updateEntries:(id)sender; - (IBAction)reloadAllStructures:(id)sender; - (IBAction)filterTree:(id)sender; +- (IBAction)syncButtonAction:(id)sender; - (NSString*)tableInfoLabelForIndex:(NSInteger)index; - (void)restoreSelectedItems; - (void)setIgnoreUpdate:(BOOL)flag; +- (void)selectPath:(NSString*)schemaPath; +- (BOOL)syncMode; @end diff --git a/Source/SPNavigatorController.m b/Source/SPNavigatorController.m index 050df716..56c51438 100644 --- a/Source/SPNavigatorController.m +++ b/Source/SPNavigatorController.m @@ -27,10 +27,13 @@ #import "SPOutlineView.h" #import "SPConstants.h" #import "ImageAndTextCell.h" - +#import "TableDocument.h" +#import "SPArrayAdditions.h" static SPNavigatorController *sharedNavigatorController = nil; +#define DragFromNavigatorPboardType @"SPDragFromNavigatorPboardType" + @implementation SPNavigatorController @@ -66,6 +69,7 @@ static SPNavigatorController *sharedNavigatorController = nil; selectedKey1 = @""; selectedKey2 = @""; ignoreUpdate = NO; + [syncButton setState:NSOffState]; } return self; @@ -101,6 +105,12 @@ static SPNavigatorController *sharedNavigatorController = nil; prefs = [NSUserDefaults standardUserDefaults]; [self setWindowFrameAutosaveName:@"SPNavigator"]; + [outlineSchema1 registerForDraggedTypes:[NSArray arrayWithObjects:DragFromNavigatorPboardType, NSStringPboardType, nil]]; + [outlineSchema1 setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; + [outlineSchema1 setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO]; + [outlineSchema2 registerForDraggedTypes:[NSArray arrayWithObjects:DragFromNavigatorPboardType, NSStringPboardType, nil]]; + [outlineSchema2 setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; + [outlineSchema2 setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO]; } @@ -109,6 +119,13 @@ static SPNavigatorController *sharedNavigatorController = nil; return @"SPNavigator"; } +- (BOOL)syncMode +{ + if([[self window] isVisible]) + return ([syncButton state] == NSOffState || [outlineSchema2 numberOfSelectedRows] > 1) ? NO : YES; + return NO; +} + - (void)restoreExpandStatus { @@ -159,6 +176,45 @@ static SPNavigatorController *sharedNavigatorController = nil; } +- (void)selectPath:(NSString*)schemaPath +{ + if(schemaPath && [schemaPath length]) { + + // Do not change the selection if a field of schemaPath's table is already selected + [self saveSelectedItems]; + if([selectedKey2 length] && [selectedKey2 hasPrefix:[NSString stringWithFormat:@"%@%@", schemaPath, SPUniqueSchemaDelimiter]]) + return; + + id item = schemaData; + NSArray *pathArray = [schemaPath componentsSeparatedByString:SPUniqueSchemaDelimiter]; + NSMutableString *aKey = [NSMutableString string]; + [outlineSchema2 collapseItem:[item objectForKey:[pathArray objectAtIndex:0]] collapseChildren:YES]; + for(NSInteger i=0; i < [pathArray count]; i++) { + [aKey appendString:[pathArray objectAtIndex:i]]; + if(![item objectForKey:aKey]) break; + item = [item objectForKey:aKey]; + [outlineSchema2 expandItem:item]; + [aKey appendString:SPUniqueSchemaDelimiter]; + } + if(item != nil) { + NSInteger itemIndex = [outlineSchema2 rowForItem:item]; + if (itemIndex >= 0) { + [outlineSchema2 selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] byExtendingSelection:NO]; + [outlineSchema2 scrollRowToVisible:[outlineSchema2 selectedRow]]; + id item = [outlineSchema2 itemAtRow:[outlineSchema2 selectedRow]]; + // Try to scroll the view that all children of schemaPath are visible if possible + NSInteger cnt = [item count]+1; + NSRange r = [outlineSchema2 rowsInRect:[outlineSchema2 visibleRect]]; + NSInteger offset = (cnt > r.length) ? (r.length-2) : cnt; + offset += [outlineSchema2 selectedRow]; + if(offset >= [outlineSchema2 numberOfRows]) + offset = [outlineSchema2 numberOfRows] - 1; + [outlineSchema2 scrollRowToVisible:offset]; + } + } + } +} + - (void)restoreSelectedItems { @@ -282,6 +338,7 @@ static SPNavigatorController *sharedNavigatorController = nil; selectedKey2 = @""; selectionViewPort1 = NSZeroRect; selectionViewPort2 = NSZeroRect; + [syncButton setState:NSOffState]; if ([[[NSDocumentController sharedDocumentController] documents] count]) { for(id doc in [[NSDocumentController sharedDocumentController] documents]) { @@ -302,6 +359,26 @@ static SPNavigatorController *sharedNavigatorController = nil; NSString *pattern = [searchField stringValue]; } +- (IBAction)syncButtonAction:(id)sender +{ + if([syncButton state] == NSOnState) { + if ([[[NSDocumentController sharedDocumentController] documents] count]) { + TableDocument *doc = [[NSDocumentController sharedDocumentController] currentDocument]; + NSMutableString *key = [NSMutableString string]; + [key setString:[doc connectionID]]; + if([doc database] && [(NSString*)[doc database] length]){ + [key appendString:SPUniqueSchemaDelimiter]; + [key appendString:[doc database]]; + } + if([doc table] && [(NSString*)[doc table] length]){ + [key appendString:SPUniqueSchemaDelimiter]; + [key appendString:[doc table]]; + } + [self selectPath:key]; + } + } +} + #pragma mark - #pragma mark outline delegates @@ -507,6 +584,28 @@ static SPNavigatorController *sharedNavigatorController = nil; return YES; } +- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + if([outlineView levelForItem:item] == 0) return NO; + + id parentObject = [outlineView parentForItem:item] ? [outlineView parentForItem:item] : schemaData; + id parentKeys = [parentObject allKeysForObject:item]; + if(parentKeys && [parentKeys count] == 1) { + NSArray *pathArray = [[[parentKeys objectAtIndex:0] description] componentsSeparatedByString:SPUniqueSchemaDelimiter]; + if([pathArray count] > 1) { + TableDocument *doc = [[NSDocumentController sharedDocumentController] currentDocument]; + if([[doc connectionID] isEqualToString:[pathArray objectAtIndex:0]]) { + if(![[doc database] isEqualToString:[pathArray objectAtIndex:1]]) { + // todo + } + } + } + } + + + return NO; +} + - (void)outlineViewSelectionDidChange:(NSNotification *)aNotification { id ov = [aNotification object]; @@ -524,7 +623,7 @@ static SPNavigatorController *sharedNavigatorController = nil; [infoTable setRowHeight:18.0]; NSInteger i = 0; for(id item in selectedItem) { - if([item isKindOfClass:[NSString class]] && [item length]) { + if([item isKindOfClass:[NSString class]] && [(NSString*)item length]) { [infoArray addObject:[NSString stringWithFormat:@"%@: %@", [self tableInfoLabelForIndex:i], [item stringByReplacingOccurrencesOfString:@"," withString:@", "]]]; } i++; @@ -534,6 +633,40 @@ static SPNavigatorController *sharedNavigatorController = nil; [infoTable reloadData]; } +- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard +{ + // Provide data for our custom type, and simple NSStrings. + [pboard declareTypes:[NSArray arrayWithObjects:DragFromNavigatorPboardType, NSStringPboardType, nil] owner:self]; + + // Collect the actual schema paths without leading connection ID + NSMutableArray *draggedItems = [NSMutableArray array]; + for(id item in items) { + id parentObject = [outlineView parentForItem:item] ? [outlineView parentForItem:item] : schemaData; + id parentKeys = [parentObject allKeysForObject:item]; + if(parentKeys && [parentKeys count] == 1) + [draggedItems addObject:[[[parentKeys objectAtIndex:0] description] stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"^.*?%@", SPUniqueSchemaDelimiter] withString:@""]]; + } + + // Drag the array with schema paths + NSMutableData *arraydata = [[[NSMutableData alloc] init] autorelease]; + NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:arraydata] autorelease]; + [archiver encodeObject:draggedItems forKey:@"itemdata"]; + [archiver finishEncoding]; + [pboard setData:arraydata forType:DragFromNavigatorPboardType]; + + // For external destinations provide a comma separated string + NSMutableString *dragString = [NSMutableString string]; + for(id item in draggedItems) { + if([dragString length]) [dragString appendString:@", "]; + [dragString appendString:[[item componentsSeparatedByString:SPUniqueSchemaDelimiter] componentsJoinedByPeriodAndBacktickQuotedAndIgnoreFirst]]; + } + + if(![dragString length]) return NO; + + [pboard setString:dragString forType:NSStringPboardType]; + return YES; +} + #pragma mark - #pragma mark table delegates diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 36291911..763a444b 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -743,6 +743,7 @@ break; } } + } /** @@ -857,6 +858,17 @@ // Do not update the navigator since nothing is changed [[SPNavigatorController sharedNavigatorController] setIgnoreUpdate:YES]; + // If Navigator runs in syncMode let it follow the selection + if([[SPNavigatorController sharedNavigatorController] syncMode]) { + NSMutableString *schemaPath = [NSMutableString string]; + [schemaPath setString:[self connectionID]]; + if([chooseDatabaseButton titleOfSelectedItem] && [[chooseDatabaseButton titleOfSelectedItem] length]) { + [schemaPath appendString:SPUniqueSchemaDelimiter]; + [schemaPath appendString:[chooseDatabaseButton titleOfSelectedItem]]; + } + [[SPNavigatorController sharedNavigatorController] selectPath:schemaPath]; + } + // Start a task [self startTaskWithDescription:[NSString stringWithFormat:NSLocalizedString(@"Loading database '%@'...", @"Loading database task string"), [chooseDatabaseButton titleOfSelectedItem]]]; if ([NSThread isMainThread]) { @@ -3692,6 +3704,24 @@ return YES; } +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + // Synchronize Navigator with current active document if Navigator runs in syncMode + if([[SPNavigatorController sharedNavigatorController] syncMode] && [self connectionID] && ![[self connectionID] isEqualToString:@"_"]) { + NSMutableString *schemaPath = [NSMutableString string]; + [schemaPath setString:[self connectionID]]; + if([self database] && [[self database] length]) { + [schemaPath appendString:SPUniqueSchemaDelimiter]; + [schemaPath appendString:[self database]]; + if([self table] && [[self table] length]) { + [schemaPath appendString:SPUniqueSchemaDelimiter]; + [schemaPath appendString:[self table]]; + } + } + [[SPNavigatorController sharedNavigatorController] selectPath:schemaPath]; + } +} + /** * Invoked when the document window is resized */ diff --git a/Source/TablesList.m b/Source/TablesList.m index 74f4a390..6de845f3 100644 --- a/Source/TablesList.m +++ b/Source/TablesList.m @@ -39,6 +39,7 @@ #import "NSNotificationAdditions.h" #import "SPConstants.h" #import "SPAlertSheets.h" +#import "SPNavigatorController.h" @interface TablesList (PrivateAPI) @@ -1420,6 +1421,20 @@ if ([tablesListView numberOfSelectedRows] == 1 && [(NSString *)[filteredTables objectAtIndex:[tablesListView selectedRow]] length]) tableName = [filteredTables objectAtIndex:[tablesListView selectedRow]]; [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), tableName]]; + + if([[SPNavigatorController sharedNavigatorController] syncMode]) { + NSMutableString *schemaPath = [NSMutableString string]; + [schemaPath setString:[tableDocumentInstance connectionID]]; + if([tableDocumentInstance database] && [[tableDocumentInstance database] length]) { + [schemaPath appendString:SPUniqueSchemaDelimiter]; + [schemaPath appendString:[tableDocumentInstance database]]; + if(tableName && [tableName length]) { + [schemaPath appendString:SPUniqueSchemaDelimiter]; + [schemaPath appendString:tableName]; + } + } + [[SPNavigatorController sharedNavigatorController] selectPath:schemaPath]; + } } /** -- cgit v1.2.3