diff options
Diffstat (limited to 'Source/SPNarrowDownCompletion.m')
-rw-r--r-- | Source/SPNarrowDownCompletion.m | 192 |
1 files changed, 138 insertions, 54 deletions
diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m index e635958f..3bef11c8 100644 --- a/Source/SPNarrowDownCompletion.m +++ b/Source/SPNarrowDownCompletion.m @@ -61,6 +61,7 @@ - (BOOL)SP_NarrowDownCompletion_canHandleEvent:(NSEvent*)anEvent { + NSInteger visibleRows = (NSInteger)floor(NSHeight([self visibleRect]) / ([self rowHeight]+[self intercellSpacing].height)) - 1; struct { unichar key; NSInteger rows; } const key_movements[] = @@ -74,9 +75,8 @@ }; unichar keyCode = 0; - if([anEvent type] == NSScrollWheel) - keyCode = [anEvent deltaY] >= 0.0 ? NSUpArrowFunctionKey : NSDownArrowFunctionKey; - else if([anEvent type] == NSKeyDown && [[anEvent characters] length] == 1) + + if([anEvent type] == NSKeyDown && [[anEvent characters] length] == 1) keyCode = [[anEvent characters] characterAtIndex:0]; @@ -85,9 +85,14 @@ if(keyCode == key_movements[i].key) { NSInteger row = MAX(0, MIN([self selectedRow] + key_movements[i].rows, [self numberOfRows]-1)); - [self selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO]; - [self scrollRowToVisible:row]; + if(row == 0 && ![[[self delegate] tableView:self selectionIndexesForProposedSelection:[NSIndexSet indexSetWithIndex:row]] containsIndex:0]) { + if(visibleRows > 1) + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:row+1] byExtendingSelection:NO]; + } else { + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO]; + } + [self scrollRowToVisible:row]; return YES; } } @@ -107,7 +112,7 @@ maxWindowWidth = 450; - if(self = [super initWithContentRect:NSMakeRect(0,0,maxWindowWidth,0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]) + if(self = [super initWithContentRect:NSMakeRect(0,0,maxWindowWidth,0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]) { mutablePrefix = [NSMutableString new]; textualInputCharacters = [[NSMutableCharacterSet alphanumericCharacterSet] retain]; @@ -115,18 +120,23 @@ filtered = nil; spaceCounter = 0; currentSyncImage = 0; + staticPrefix = nil; + suggestions = nil; + commonPrefixWasInsertedByAutoComplete = NO; prefs = [NSUserDefaults standardUserDefaults]; + originalFilterString = [[NSMutableString alloc] init]; + [originalFilterString setString:@""]; tableFont = [NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] dataForKey:SPCustomQueryEditorFont]]; [self setupInterface]; syncArrowImages = [[NSArray alloc] initWithObjects: - [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_01" ofType:@"tiff"]], - [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_02" ofType:@"tiff"]], - [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_03" ofType:@"tiff"]], - [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_04" ofType:@"tiff"]], - [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_05" ofType:@"tiff"]], - [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_06" ofType:@"tiff"]], + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_01" ofType:@"tiff"]] autorelease], + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_02" ofType:@"tiff"]] autorelease], + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_03" ofType:@"tiff"]] autorelease], + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_04" ofType:@"tiff"]] autorelease], + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_05" ofType:@"tiff"]] autorelease], + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sync_arrows_06" ofType:@"tiff"]] autorelease], nil]; } @@ -135,15 +145,17 @@ - (void)dealloc { + [NSObject cancelPreviousPerformRequestsWithTarget:self]; if(stateTimer != nil) { [stateTimer invalidate]; [stateTimer release]; } stateTimer = nil; - [staticPrefix release]; + if (staticPrefix) [staticPrefix release]; [mutablePrefix release]; [textualInputCharacters release]; - + [originalFilterString release]; + if (syncArrowImages) [syncArrowImages release]; if(suggestions) [suggestions release]; if (filtered) [filtered release]; @@ -151,11 +163,21 @@ [super dealloc]; } +- (void)close +{ + closeMe = YES; + [theView setCompletionIsOpen:NO]; + [super close]; +} + - (void)updateSyncArrowStatus { + // update sync arrow image currentSyncImage++; - timeCounter++; if(currentSyncImage >= [syncArrowImages count]) currentSyncImage = 0; + + // check if connection is still querying the db structure + timeCounter++; if(timeCounter > 20) { timeCounter = 0; if(![[theView valueForKeyPath:@"mySQLConnection"] isQueryingDatabaseStructure]) { @@ -165,7 +187,7 @@ [stateTimer release]; stateTimer = nil; if(syncArrowImages) [syncArrowImages release]; - [self performSelectorOnMainThread:@selector(reInvokeCompletion) withObject:nil waitUntilDone:NO]; + [self performSelectorOnMainThread:@selector(reInvokeCompletion) withObject:nil waitUntilDone:YES]; closeMe = YES; return; } @@ -178,9 +200,14 @@ - (void)reInvokeCompletion { + if(stateTimer) { + [stateTimer invalidate]; + [stateTimer release]; + stateTimer = nil; + } [theView setCompletionIsOpen:NO]; - [theView doCompletionByUsingSpellChecker:dictMode fuzzyMode:fuzzyMode autoCompleteMode:NO]; [self close]; + [theView performSelector:@selector(refreshCompletion) withObject:nil afterDelay:0.0]; } - (id)initWithItems:(NSArray*)someSuggestions alreadyTyped:(NSString*)aUserString staticPrefix:(NSString*)aStaticPrefix @@ -199,6 +226,10 @@ [mutablePrefix appendString:aUserString]; autoCompletionMode = autoComplete; + + if(autoCompletionMode) + [originalFilterString appendString:aUserString]; + oneColumnMode = oneColumn; isQueryingDatabaseStructure = isQueryingDBStructure; @@ -230,6 +261,8 @@ theView = aView; dictMode = mode; + timeCounter = 0; + suggestions = [someSuggestions retain]; if(dictMode || oneColumnMode) { @@ -306,13 +339,11 @@ theTableView = [[[NSTableView alloc] initWithFrame:NSZeroRect] autorelease]; [theTableView setFocusRingType:NSFocusRingTypeNone]; - [theTableView setAllowsEmptySelection:NO]; + [theTableView setAllowsEmptySelection:YES]; [theTableView setHeaderView:nil]; - [theTableView setDelegate:self]; NSTableColumn *column0 = [[[NSTableColumn alloc] initWithIdentifier:@"image"] autorelease]; - [column0 setDataCell:[NSImageCell new]]; - // [column0 setEditable:NO]; + [column0 setDataCell:[[NSImageCell new] autorelease]]; [theTableView addTableColumn:column0]; [column0 setMinWidth:0]; [column0 setWidth:20]; @@ -339,9 +370,11 @@ [column4 setWidth:95]; [theTableView setDataSource:self]; + [theTableView setDelegate:self]; [scrollView setDocumentView:theTableView]; [self setContentView:scrollView]; + } // ======================== @@ -354,10 +387,10 @@ - (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(id)aCell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex mouseLocation:(NSPoint)mouseLocation { - if(isQueryingDatabaseStructure) rowIndex--; - if([[aTableColumn identifier] isEqualToString:@"image"]) { - if(rowIndex == -1) return NSLocalizedString(@"fetching database structure in progress", @"fetching database structure in progress"); + if(isQueryingDatabaseStructure && rowIndex == 0) + return NSLocalizedString(@"fetching database structure in progress", @"fetching database structure in progress"); + if(!dictMode) { NSString *imageName = [[filtered objectAtIndex:rowIndex] objectForKey:@"image"]; if([imageName hasPrefix:@"dummy"]) @@ -377,10 +410,14 @@ } return @""; } else if([[aTableColumn identifier] isEqualToString:@"name"]) { - if(rowIndex == -1) return NSLocalizedString(@"fetching database structure in progress", @"fetching database structure in progress"); + if(isQueryingDatabaseStructure && rowIndex == 0) + return NSLocalizedString(@"fetching database structure in progress", @"fetching database structure in progress"); + return [[filtered objectAtIndex:rowIndex] objectForKey:@"display"]; } else if ([[aTableColumn identifier] isEqualToString:@"list"] || [[aTableColumn identifier] isEqualToString:@"type"]) { - if(rowIndex == -1) return NSLocalizedString(@"fetching database structure data in progress", @"fetching database structure data in progress"); + if(isQueryingDatabaseStructure && rowIndex == 0) + return NSLocalizedString(@"fetching database structure data in progress", @"fetching database structure data in progress"); + if(dictMode) { return @""; } else { @@ -399,7 +436,9 @@ } } else if ([[aTableColumn identifier] isEqualToString:@"path"]) { - if(rowIndex == -1) return NSLocalizedString(@"fetching database structure in progress", @"fetching database structure in progress"); + if(isQueryingDatabaseStructure && rowIndex == 0) + return NSLocalizedString(@"fetching database structure in progress", @"fetching database structure in progress"); + if(dictMode) { return @""; } else { @@ -419,25 +458,22 @@ return @""; } -- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex +- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes { - if(rowIndex == 0 && isQueryingDatabaseStructure) - return NO; + if(isQueryingDatabaseStructure && [proposedSelectionIndexes containsIndex:0]) + return [tableView selectedRowIndexes]; - return YES; + return proposedSelectionIndexes; } - - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { NSImage* image = nil; NSString* imageName = nil; - if(isQueryingDatabaseStructure) rowIndex--; - if([[aTableColumn identifier] isEqualToString:@"image"]) { if(!dictMode) { - if(rowIndex == -1) { + if(isQueryingDatabaseStructure && rowIndex == 0) { return [syncArrowImages objectAtIndex:currentSyncImage]; } else { imageName = [[filtered objectAtIndex:rowIndex] objectForKey:@"image"]; @@ -450,11 +486,14 @@ } else if([[aTableColumn identifier] isEqualToString:@"name"]) { [[aTableColumn dataCell] setFont:[NSFont systemFontOfSize:12]]; - if(rowIndex == -1) return @"fetching structure…"; + + if(isQueryingDatabaseStructure && rowIndex == 0) + return @"fetching structure…"; + return [[filtered objectAtIndex:rowIndex] objectForKey:@"display"]; } else if ([[aTableColumn identifier] isEqualToString:@"list"]) { - if(rowIndex == -1) { + if(isQueryingDatabaseStructure && rowIndex == 0) { NSPopUpButtonCell *b = [[NSPopUpButtonCell new] autorelease]; [b setPullsDown:NO]; [b setArrowPosition:NSPopUpNoArrow]; @@ -491,7 +530,7 @@ } } else if([[aTableColumn identifier] isEqualToString:@"type"]) { - if(rowIndex == -1) { + if(isQueryingDatabaseStructure && rowIndex == 0) { return @""; } if(dictMode) { @@ -506,7 +545,7 @@ } } else if ([[aTableColumn identifier] isEqualToString:@"path"]) { - if(rowIndex == -1) { + if(isQueryingDatabaseStructure && rowIndex == 0) { NSPopUpButtonCell *b = [[NSPopUpButtonCell new] autorelease]; [b setPullsDown:NO]; [b setArrowPosition:NSPopUpNoArrow]; @@ -570,6 +609,7 @@ { NSMutableArray* newFiltered = [[NSMutableArray alloc] initWithCapacity:5]; + if([mutablePrefix length] > 0) { if(dictMode) { @@ -653,6 +693,11 @@ return; } + + // if fetching db structure add dummy row for displaying that info on top of the list + if(isQueryingDatabaseStructure) + [newFiltered insertObject:[NSDictionary dictionaryWithObjectsAndKeys:@"dummy", @"display", @"", @"noCompletion", nil] atIndex:0]; + NSPoint old = NSMakePoint([self frame].origin.x, [self frame].origin.y + [self frame].size.height); NSInteger displayedRows = [newFiltered count] < SPNarrowDownCompletionMaxRows ? [newFiltered count] : SPNarrowDownCompletionMaxRows; @@ -676,6 +721,7 @@ if(!dictMode) [self checkSpaceForAllowedCharacter]; [theTableView reloadData]; + [theTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:(isQueryingDatabaseStructure)?1:0] byExtendingSelection:NO]; } // ========================= @@ -724,6 +770,9 @@ if(!event) continue; + // Exit if closeMe has been set in the meantime + if(closeMe) return; + NSEventType t = [event type]; if([theTableView SP_NarrowDownCompletion_canHandleEvent:event]) { @@ -738,6 +787,16 @@ // e.g. for US keyboard "⌥u a" to insert ä if (([event modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask)) == NSAlternateKeyMask || [[event characters] length] == 0) { + if(autoCompletionMode) { + if(commonPrefixWasInsertedByAutoComplete) { + [theView setSelectedRange:theCharRange]; + [theView insertText:originalFilterString]; + [theView setCompletionIsOpen:NO]; + [self close]; + [NSApp sendEvent:event]; + break; + } + } [NSApp sendEvent: event]; if(commaInsertionMode) @@ -760,6 +819,15 @@ [theTableView setBackgroundColor:[NSColor colorWithCalibratedRed:0.9f green:0.9f blue:0.9f alpha:1.0f]]; [self filter]; } else { + if(autoCompletionMode) { + if(commonPrefixWasInsertedByAutoComplete) { + [theView setSelectedRange:theCharRange]; + [theView insertText:originalFilterString]; + } + [theView setCompletionIsOpen:NO]; + [self close]; + break; + } if(cursorMovedLeft) [theView performSelector:@selector(moveRight:)]; break; } @@ -770,6 +838,14 @@ } else if(key == NSBackspaceCharacter || key == NSDeleteCharacter) { + if(autoCompletionMode) { + if(commonPrefixWasInsertedByAutoComplete) { + [theView setSelectedRange:theCharRange]; + [theView insertText:originalFilterString]; + } + [NSApp sendEvent:event]; + break; + } [NSApp sendEvent:event]; if([mutablePrefix length] == 0 || commaInsertionMode) break; @@ -782,6 +858,18 @@ } else if([textualInputCharacters characterIsMember:key]) { + + if(autoCompletionMode) { + [theView setCompletionIsOpen:NO]; + [self close]; + if(commonPrefixWasInsertedByAutoComplete) { + [theView setSelectedRange:theCharRange]; + [theView insertText:originalFilterString]; + } + [NSApp sendEvent:event]; + return; + } + [NSApp sendEvent:event]; if(commaInsertionMode) @@ -808,11 +896,18 @@ if(([event clickCount] == 2)) { [self completeAndInsertSnippet]; } else { - [NSApp sendEvent:event]; if(!NSPointInRect([NSEvent mouseLocation], [self frame])) { + if(autoCompletionMode) { + if(commonPrefixWasInsertedByAutoComplete) { + [theView setSelectedRange:theCharRange]; + [theView insertText:originalFilterString]; + } + } if(cursorMovedLeft) [theView performSelector:@selector(moveRight:)]; + [NSApp sendEvent:event]; break; } + [NSApp sendEvent:event]; } } else @@ -860,6 +955,7 @@ theCharRange.length += [toInsert length]; theParseRange.length += [toInsert length]; [theView insertText:[toInsert lowercaseString]]; + commonPrefixWasInsertedByAutoComplete = YES; [self checkSpaceForAllowedCharacter]; } } @@ -895,17 +991,7 @@ { if([theTableView selectedRow] == -1) return; - NSDictionary* selectedItem; - NSInteger selectedRowNumber = [theTableView selectedRow]; - if(isQueryingDatabaseStructure) { - if(selectedRowNumber < 1) { - closeMe = YES; - return; - } - selectedItem = [filtered objectAtIndex:selectedRowNumber-1]; - } else { - selectedItem = [filtered objectAtIndex:selectedRowNumber]; - } + NSDictionary *selectedItem = [filtered objectAtIndex:[theTableView selectedRow]]; if([selectedItem objectForKey:@"noCompletion"]) { closeMe = YES; @@ -919,9 +1005,7 @@ if([selectedItem objectForKey:@"isRef"] && ([[NSApp currentEvent] modifierFlags] & (NSShiftKeyMask)) && [[selectedItem objectForKey:@"path"] length]) { - // NSString *path = [NSString stringWithFormat:@"%@.%@", - // [[[selectedItem objectForKey:@"path"] componentsSeparatedByString:SPUniqueSchemaDelimiter] componentsJoinedByPeriodAndBacktickQuotedAndIgnoreFirst], - // [candidateMatch backtickQuotedString]]; + NSString *path = [[[selectedItem objectForKey:@"path"] componentsSeparatedByString:SPUniqueSchemaDelimiter] componentsJoinedByPeriodAndBacktickQuotedAndIgnoreFirst]; // Check if path's db name is the current selected db name |