aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPNarrowDownCompletion.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPNarrowDownCompletion.m')
-rw-r--r--Source/SPNarrowDownCompletion.m192
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