aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPContentFilterManager.m1
-rw-r--r--Source/SPCustomQuery.m1
-rw-r--r--Source/SPDatabaseDocument.m1
-rw-r--r--Source/SPNarrowDownCompletion.m1
-rw-r--r--Source/SPQueryConsoleDataSource.h30
-rw-r--r--Source/SPQueryConsoleDataSource.m89
-rw-r--r--Source/SPQueryController.h39
-rw-r--r--Source/SPQueryController.m680
-rw-r--r--Source/SPQueryControllerInitializer.h32
-rw-r--r--Source/SPQueryControllerInitializer.m135
-rw-r--r--Source/SPQueryDocumentsController.h56
-rw-r--r--Source/SPQueryDocumentsController.m407
-rw-r--r--Source/SPQueryFavoriteManager.m1
-rw-r--r--Source/SPTableContent.m1
-rw-r--r--Source/SPTextView.m1
15 files changed, 855 insertions, 620 deletions
diff --git a/Source/SPContentFilterManager.m b/Source/SPContentFilterManager.m
index 529ba8b5..0d4b7c18 100644
--- a/Source/SPContentFilterManager.m
+++ b/Source/SPContentFilterManager.m
@@ -27,6 +27,7 @@
#import "ImageAndTextCell.h"
#import "RegexKitLite.h"
#import "SPQueryController.h"
+#import "SPQueryDocumentsController.h"
#import "SPTableContent.h"
#import "SPConnectionController.h"
#ifndef SP_REFACTOR /* headers */
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index 80b69358..c10d62d3 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -39,6 +39,7 @@
#import "SPQueryFavoriteManager.h"
#endif
#import "SPQueryController.h"
+#import "SPQueryDocumentsController.h"
#import "SPEncodingPopupAccessory.h"
#import "SPDataStorage.h"
#import "SPAlertSheets.h"
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index 85dc0615..52858787 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -48,6 +48,7 @@ enum {
#import "SPExportController.h"
#endif
#import "SPQueryController.h"
+#import "SPQueryDocumentsController.h"
#ifndef SP_REFACTOR /* headers */
#import "SPWindowController.h"
#endif
diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m
index 226becf6..9079954d 100644
--- a/Source/SPNarrowDownCompletion.m
+++ b/Source/SPNarrowDownCompletion.m
@@ -34,6 +34,7 @@
#import "SPQueryController.h"
#import "RegexKitLite.h"
#import "SPTextView.h"
+#import "SPQueryDocumentsController.h"
#pragma mark -
#pragma mark attribute definition
diff --git a/Source/SPQueryConsoleDataSource.h b/Source/SPQueryConsoleDataSource.h
new file mode 100644
index 00000000..229e3b9d
--- /dev/null
+++ b/Source/SPQueryConsoleDataSource.h
@@ -0,0 +1,30 @@
+//
+// $Id$
+//
+// SPQueryConsoleDataSource.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 30, 2011
+// Copyright (c) 2011 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPQueryController.h"
+
+@interface SPQueryController (SPQueryConsoleDataSource)
+
+@end
diff --git a/Source/SPQueryConsoleDataSource.m b/Source/SPQueryConsoleDataSource.m
new file mode 100644
index 00000000..29a8dc7a
--- /dev/null
+++ b/Source/SPQueryConsoleDataSource.m
@@ -0,0 +1,89 @@
+//
+// $Id$
+//
+// SPQueryConsoleDataSource.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 30, 2011
+// Copyright (c) 2011 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPQueryConsoleDataSource.h"
+#import "SPConsoleMessage.h"
+
+static NSUInteger SPMessageTruncateCharacterLength = 256;
+
+@implementation SPQueryController (SPQueryConsoleDataSource)
+
+/**
+ * Table view delegate method. Returns the number of rows in the table veiw.
+ */
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+#ifndef SP_REFACTOR
+ return [messagesVisibleSet count];
+#else
+ return 0;
+#endif
+}
+
+/**
+ * Table view delegate method. Returns the specific object for the request column and row.
+ */
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+#ifndef SP_REFACTOR
+ NSString *returnValue = nil;
+
+ id object = [[messagesVisibleSet objectAtIndex:row] valueForKey:[tableColumn identifier]];
+
+ if ([[tableColumn identifier] isEqualToString:SPTableViewDateColumnID]) {
+
+ returnValue = [dateFormatter stringFromDate:(NSDate *)object];
+ }
+ else {
+ if ([(NSString *)object length] > SPMessageTruncateCharacterLength) {
+ object = [NSString stringWithFormat:@"%@...", [object substringToIndex:SPMessageTruncateCharacterLength]];
+ }
+
+ returnValue = object;
+ }
+
+ NSMutableDictionary *stringAtributes = nil;
+
+ if (consoleFont) {
+ stringAtributes = [NSMutableDictionary dictionaryWithObject:consoleFont forKey:NSFontAttributeName];
+ }
+
+ // If this is an error message give it a red colour
+ if ([(SPConsoleMessage *)[messagesVisibleSet objectAtIndex:row] isError]) {
+ if (stringAtributes) {
+ [stringAtributes setObject:[NSColor redColor] forKey:NSForegroundColorAttributeName];
+ }
+ else {
+ stringAtributes = [NSMutableDictionary dictionaryWithObject:[NSColor redColor] forKey:NSForegroundColorAttributeName];
+ }
+ }
+
+ return [[[NSAttributedString alloc] initWithString:returnValue attributes:stringAtributes] autorelease];
+#else
+ return nil;
+#endif
+}
+
+@end
diff --git a/Source/SPQueryController.h b/Source/SPQueryController.h
index fdbddb70..8ac4570d 100644
--- a/Source/SPQueryController.h
+++ b/Source/SPQueryController.h
@@ -23,10 +23,17 @@
//
// More info at <http://code.google.com/p/sequel-pro/>
+#ifndef SP_REFACTOR
+static NSString *SPQueryConsoleWindowAutoSaveName = @"QueryConsole";
+
+// Table view column identifier constants
+static NSString *SPTableViewDateColumnID = @"messageDate";
+static NSString *SPTableViewConnectionColumnID = @"messageConnection";
+#endif
+
@interface SPQueryController : NSWindowController
{
#ifndef SP_REFACTOR /* ivars */
- // QueryConsoleController
IBOutlet NSView *saveLogView;
IBOutlet NSTableView *consoleTableView;
IBOutlet NSSearchField *consoleSearchField;
@@ -64,14 +71,11 @@
}
#ifndef SP_REFACTOR
-
@property (readwrite, retain) NSFont *consoleFont;
-
#endif
+ (SPQueryController *)sharedQueryController;
-// QueryConsoleController
- (IBAction)copy:(id)sender;
- (IBAction)clearConsole:(id)sender;
- (IBAction)saveConsoleAs:(id)sender;
@@ -90,31 +94,4 @@
- (NSUInteger)consoleMessageCount;
-// Completion List Controller
-- (NSArray*)functionList;
-- (NSArray*)keywordList;
-- (NSString*)argumentSnippetForFunction:(NSString*)func;
-
-// DocumentsController
-- (NSURL *)registerDocumentWithFileURL:(NSURL *)fileURL andContextInfo:(NSMutableDictionary *)contextInfo;
-- (void)removeRegisteredDocumentWithFileURL:(NSURL *)fileURL;
-
-- (void)addFavorite:(NSDictionary *)favorite forFileURL:(NSURL *)fileURL;
-- (void)replaceFavoritesByArray:(NSArray *)favoritesArray forFileURL:(NSURL *)fileURL;
-- (void)removeFavoriteAtIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL;
-- (void)insertFavorite:(NSDictionary *)favorite atIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL;
-
-- (void)addHistory:(NSString *)history forFileURL:(NSURL *)fileURL;
-- (void)replaceHistoryByArray:(NSArray *)historyArray forFileURL:(NSURL *)fileURL;
-
-- (void)replaceContentFilterByArray:(NSArray *)contentFilterArray ofType:(NSString *)filterType forFileURL:(NSURL *)fileURL;
-
-- (NSMutableArray *)favoritesForFileURL:(NSURL *)fileURL;
-- (NSMutableArray *)historyForFileURL:(NSURL *)fileURL;
-- (NSArray *)historyMenuItemsForFileURL:(NSURL *)fileURL;
-- (NSUInteger)numberOfHistoryItemsForFileURL:(NSURL *)fileURL;
-- (NSMutableDictionary *)contentFilterForFileURL:(NSURL *)fileURL;
-
-- (NSArray *)queryFavoritesForFileURL:(NSURL *)fileURL andTabTrigger:(NSString *)tabTrigger includeGlobals:(BOOL)includeGlobals;
-
@end
diff --git a/Source/SPQueryController.m b/Source/SPQueryController.m
index 08678f83..46c9da3d 100644
--- a/Source/SPQueryController.m
+++ b/Source/SPQueryController.m
@@ -26,18 +26,11 @@
#import "SPQueryController.h"
#import "SPConsoleMessage.h"
#import "SPCustomQuery.h"
+#import "SPQueryControllerInitializer.h"
#import "pthread.h"
-#define MESSAGE_TRUNCATE_CHARACTER_LENGTH 256
-
-#ifndef SP_REFACTOR
-// Table view column identifier constants
-static NSString *SPTableViewDateColumnID = @"messageDate";
-static NSString *SPTableViewConnectionColumnID = @"messageConnection";
-#endif
-
-@interface SPQueryController (PrivateAPI)
+@interface SPQueryController ()
- (void)_updateFilterState;
- (BOOL)_messageMatchesCurrentFilters:(NSString *)message;
@@ -51,9 +44,7 @@ static SPQueryController *sharedQueryController = nil;
@implementation SPQueryController
#ifndef SP_REFACTOR
-
@synthesize consoleFont;
-
#endif
/**
@@ -75,8 +66,9 @@ static SPQueryController *sharedQueryController = nil;
@synchronized(self) {
return [[self sharedQueryController] retain];
}
+
#ifdef SP_REFACTOR
- return nil; // only here to stop clang's "can reach end of non-void function"
+ return nil; // only here to stop clang's 'can reach end of non-void function'
#endif
}
@@ -111,41 +103,11 @@ static SPQueryController *sharedQueryController = nil;
pthread_mutex_init(&consoleLock, NULL);
#endif
- NSError *readError = nil;
- NSString *convError = nil;
- NSPropertyListFormat format;
- NSDictionary *completionPlist;
- NSData *completionTokensData = [NSData dataWithContentsOfFile:[NSBundle pathForResource:@"CompletionTokens.plist" ofType:nil inDirectory:[[NSBundle mainBundle] bundlePath]]
- options:NSMappedRead error:&readError];
-
-
- completionPlist = [NSDictionary dictionaryWithDictionary:[NSPropertyListSerialization propertyListFromData:completionTokensData
- mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&convError]];
-
- if(completionPlist == nil || readError != nil || convError != nil) {
- NSLog(@"Error while reading “CompletionTokens.plist”:\n%@\n%@", [readError localizedDescription], convError);
- NSBeep();
- } else {
- if([completionPlist objectForKey:@"core_keywords"]) {
- completionKeywordList = [[NSArray arrayWithArray:[completionPlist objectForKey:@"core_keywords"]] retain];
- } else {
- NSLog(@"No “core_keywords” array found.");
- NSBeep();
- }
- if([completionPlist objectForKey:@"core_builtin_functions"]) {
- completionFunctionList = [[NSArray arrayWithArray:[completionPlist objectForKey:@"core_builtin_functions"]] retain];
- } else {
- NSLog(@"No “core_builtin_functions” array found.");
- NSBeep();
- }
- if([completionPlist objectForKey:@"function_argument_snippets"]) {
- functionArgumentSnippets = [[NSDictionary dictionaryWithDictionary:[completionPlist objectForKey:@"function_argument_snippets"]] retain];
- } else {
- NSLog(@"No “function_argument_snippets” dictionary found.");
- NSBeep();
- }
+ NSError *error = [self loadCompletionLists];
+
+ if (error) {
+ NSLog(@"Error loading completion tokens data: %@", [error localizedDescription]);
}
-
}
return self;
@@ -165,48 +127,6 @@ static SPQueryController *sharedQueryController = nil;
- (void)release { }
-/**
- * Set the window's auto save name and initialise display
- */
-- (void)awakeFromNib
-{
-#ifndef SP_REFACTOR /* init ivars */
- prefs = [NSUserDefaults standardUserDefaults];
-
- [self setWindowFrameAutosaveName:@"QueryConsole"];
-
- // Show/hide table columns
- [[consoleTableView tableColumnWithIdentifier:SPTableViewDateColumnID] setHidden:![prefs boolForKey:SPConsoleShowTimestamps]];
- [[consoleTableView tableColumnWithIdentifier:SPTableViewConnectionColumnID] setHidden:![prefs boolForKey:SPConsoleShowConnections]];
-
- showSelectStatementsAreDisabled = ![prefs boolForKey:SPConsoleShowSelectsAndShows];
- showHelpStatementsAreDisabled = ![prefs boolForKey:SPConsoleShowHelps];
-
- [self _updateFilterState];
-
- [loggingDisabledTextField setStringValue:([prefs boolForKey:SPConsoleEnableLogging]) ? @"" : NSLocalizedString(@"Query logging is currently disabled", @"query logging disabled label")];
-
- // Setup data formatter
- dateFormatter = [[NSDateFormatter alloc] init];
-
- [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
-
- [dateFormatter setDateStyle:NSDateFormatterNoStyle];
- [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
-
- // Set the process table view's vertical gridlines if required
- [consoleTableView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone];
-
- // Set the strutcture and index view's font
- BOOL useMonospacedFont = [prefs boolForKey:SPUseMonospacedFonts];
-
- for (NSTableColumn *column in [consoleTableView tableColumns])
- {
- [[column dataCell] setFont:(useMonospacedFont) ? [NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]] : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- }
-#endif
-}
-
#pragma mark -
#pragma mark QueryConsoleController
@@ -288,7 +208,7 @@ static SPQueryController *sharedQueryController = nil;
[panel setAccessoryView:saveLogView];
- [panel beginSheetForDirectory:nil file:NSLocalizedString(@"ConsoleLog",@"Console : Save as : Initial filename") modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
+ [panel beginSheetForDirectory:nil file:NSLocalizedString(@"ConsoleLog", @"Console : Save as : Initial filename") modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
#endif
}
@@ -383,65 +303,6 @@ static SPQueryController *sharedQueryController = nil;
}
#pragma mark -
-#pragma mark Tableview delegate methods
-
-/**
- * Table view delegate method. Returns the number of rows in the table veiw.
- */
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
-{
-#ifndef SP_REFACTOR
- return [messagesVisibleSet count];
-#else
- return 0;
-#endif
-}
-
-/**
- * Table view delegate method. Returns the specific object for the request column and row.
- */
-- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
-{
-#ifndef SP_REFACTOR
- NSString *returnValue = nil;
-
- id object = [[messagesVisibleSet objectAtIndex:row] valueForKey:[tableColumn identifier]];
-
- if ([[tableColumn identifier] isEqualToString:SPTableViewDateColumnID]) {
-
- returnValue = [dateFormatter stringFromDate:(NSDate *)object];
- }
- else {
- if ([(NSString *)object length] > MESSAGE_TRUNCATE_CHARACTER_LENGTH) {
- object = [NSString stringWithFormat:@"%@...", [object substringToIndex:MESSAGE_TRUNCATE_CHARACTER_LENGTH]];
- }
-
- returnValue = object;
- }
-
- NSMutableDictionary *stringAtributes = nil;
-
- if (consoleFont) {
- stringAtributes = [NSMutableDictionary dictionaryWithObject:consoleFont forKey:NSFontAttributeName];
- }
-
- // If this is an error message give it a red colour
- if ([(SPConsoleMessage *)[messagesVisibleSet objectAtIndex:row] isError]) {
- if (stringAtributes) {
- [stringAtributes setObject:[NSColor redColor] forKey:NSForegroundColorAttributeName];
- }
- else {
- stringAtributes = [NSMutableDictionary dictionaryWithObject:[NSColor redColor] forKey:NSForegroundColorAttributeName];
- }
- }
-
- return [[[NSAttributedString alloc] initWithString:returnValue attributes:stringAtributes] autorelease];
-#else
- return nil;
-#endif
-}
-
-#pragma mark -
#pragma mark Other
/**
@@ -450,13 +311,12 @@ static SPQueryController *sharedQueryController = nil;
- (void)controlTextDidChange:(NSNotification *)notification
{
#ifndef SP_REFACTOR
- id object = [notification object];
-
- if ([object isEqualTo:consoleSearchField]) {
+ if ([[notification object] isEqualTo:consoleSearchField]) {
// Store the state of the text filter and the current filter string for later quick reference
- [activeFilterString setString:[[object stringValue] lowercaseString]];
- filterIsActive = [activeFilterString length]?YES:NO;
+ [activeFilterString setString:[[[notification object] stringValue] lowercaseString]];
+
+ filterIsActive = [activeFilterString length] > 0;
[self _updateFilterState];
}
@@ -471,7 +331,7 @@ static SPQueryController *sharedQueryController = nil;
#ifndef SP_REFACTOR
// Show/hide logging disabled label
if ([keyPath isEqualToString:SPConsoleEnableLogging]) {
- [loggingDisabledTextField setStringValue:([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) ? @"" : @"Query logging is currently disabled"];
+ [loggingDisabledTextField setStringValue:([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) ? @"" : NSLocalizedString(@"Query logging is currently disabled", @"query logging currently disabled label")];
}
// Display table veiew vertical gridlines preference changed
else if ([keyPath isEqualToString:SPDisplayTableViewVerticalGridlines]) {
@@ -511,7 +371,7 @@ static SPQueryController *sharedQueryController = nil;
return [[self window] validateMenuItem:menuItem];
}
-- (BOOL) allowConsoleUpdate
+- (BOOL)allowConsoleUpdate
{
#ifndef SP_REFACTOR
return allowConsoleUpdate;
@@ -520,10 +380,11 @@ static SPQueryController *sharedQueryController = nil;
#endif
}
-- (void) setAllowConsoleUpdate:(BOOL)allowUpdate
+- (void)setAllowConsoleUpdate:(BOOL)allowUpdate
{
#ifndef SP_REFACTOR
allowConsoleUpdate = allowUpdate;
+
if (allowUpdate && [[self window] isVisible]) [self updateEntries];
#endif
}
@@ -544,459 +405,73 @@ static SPQueryController *sharedQueryController = nil;
*/
- (NSString *)windowFrameAutosaveName
{
- return @"QueryConsole";
-}
-
-#pragma mark -
-#pragma mark Completion List Controller
-
-/**
- * Return an array of all pre-defined SQL functions for completion.
- */
-- (NSArray*)functionList
-{
- if(completionFunctionList != nil && [completionFunctionList count])
- return completionFunctionList;
- return [NSArray array];
-}
-
-/**
- * Return an array of all pre-defined SQL keywords for completion.
- */
-- (NSArray*)keywordList
-{
- if(completionKeywordList != nil && [completionKeywordList count])
- return completionKeywordList;
- return [NSArray array];
+ return SPQueryConsoleWindowAutoSaveName;
}
/**
- * Return the parameter list as snippet of the passed SQL functions for completion.
- *
- * @param func The name of the function whose parameter list is asked for
- */
-- (NSString*)argumentSnippetForFunction:(NSString*)func
-{
- if(functionArgumentSnippets && [functionArgumentSnippets objectForKey:[func uppercaseString]])
- return [functionArgumentSnippets objectForKey:[func uppercaseString]];
- return @"";
-}
-
-#pragma mark -
-#pragma mark DocumentsController
-
-- (NSURL *)registerDocumentWithFileURL:(NSURL *)fileURL andContextInfo:(NSMutableDictionary *)contextInfo
-{
-#ifndef SP_REFACTOR
- // Register a new untiled document and return its URL
- if(fileURL == nil) {
- NSURL *new = [NSURL URLWithString:[[NSString stringWithFormat:NSLocalizedString(@"Untitled %ld",@"Title of a new Sequel Pro Document"), (unsigned long)untitledDocumentCounter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
- untitledDocumentCounter++;
-
- if(![favoritesContainer objectForKey:[new absoluteString]]) {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [favoritesContainer setObject:arr forKey:[new absoluteString]];
- [arr release];
- }
-
- // Set the global history coming from the Prefs as default if available
- if(![historyContainer objectForKey:[new absoluteString]]) {
- if([prefs objectForKey:SPQueryHistory]) {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [arr addObjectsFromArray:[prefs objectForKey:SPQueryHistory]];
- [historyContainer setObject:arr forKey:[new absoluteString]];
- [arr release];
- } else {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [historyContainer setObject:[NSMutableArray array] forKey:[new absoluteString]];
- [arr release];
- }
- }
-
- // Set the doc-based content filters
- if(![contentFilterContainer objectForKey:[new absoluteString]]) {
- [contentFilterContainer setObject:[NSMutableDictionary dictionary] forKey:[new absoluteString]];
- }
-
- return new;
-
- }
-
- // Register a spf file to manage all query favorites and query history items
- // file path based (incl. Untitled docs) in a dictionary whereby the key represents the file URL as string.
- if(![favoritesContainer objectForKey:[fileURL absoluteString]]) {
- if(contextInfo != nil && [contextInfo objectForKey:SPQueryFavorites] && [[contextInfo objectForKey:SPQueryFavorites] count]) {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [arr addObjectsFromArray:[contextInfo objectForKey:SPQueryFavorites]];
- [favoritesContainer setObject:arr forKey:[fileURL absoluteString]];
- [arr release];
- } else {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [favoritesContainer setObject:arr forKey:[fileURL absoluteString]];
- [arr release];
- }
- }
-
- if(![historyContainer objectForKey:[fileURL absoluteString]]) {
- if(contextInfo != nil && [contextInfo objectForKey:SPQueryHistory] && [[contextInfo objectForKey:SPQueryHistory] count]) {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [arr addObjectsFromArray:[contextInfo objectForKey:SPQueryHistory]];
- [historyContainer setObject:arr forKey:[fileURL absoluteString]];
- [arr release];
- } else {
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- [historyContainer setObject:arr forKey:[fileURL absoluteString]];
- [arr release];
- }
- }
-
- if(![contentFilterContainer objectForKey:[fileURL absoluteString]]) {
- if(contextInfo != nil && [contextInfo objectForKey:SPContentFilters]) {
- [contentFilterContainer setObject:[contextInfo objectForKey:SPContentFilters] forKey:[fileURL absoluteString]];
- } else {
- NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
- [contentFilterContainer setObject:dict forKey:[fileURL absoluteString]];
- [dict release];
- }
- }
-
- return fileURL;
-#else
- return nil;
-#endif
-}
-
-- (void)removeRegisteredDocumentWithFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- // Check for multiple instance of the same document.
- // Remove it if only one instance was registerd.
- NSArray *allDocs = [[NSApp delegate] orderedDocuments];
- NSMutableArray *allURLs = [NSMutableArray array];
- for(id doc in allDocs) {
- if (![doc fileURL]) continue;
- if([allURLs containsObject:[doc fileURL]])
- return;
- else
- [allURLs addObject:[doc fileURL]];
- }
-
- if([favoritesContainer objectForKey:[fileURL absoluteString]])
- [favoritesContainer removeObjectForKey:[fileURL absoluteString]];
- if([historyContainer objectForKey:[fileURL absoluteString]])
- [historyContainer removeObjectForKey:[fileURL absoluteString]];
- if([contentFilterContainer objectForKey:[fileURL absoluteString]])
- [contentFilterContainer removeObjectForKey:[fileURL absoluteString]];
-#endif
-}
-
-- (void)replaceContentFilterByArray:(NSArray *)contentFilterArray ofType:(NSString *)filterType forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([contentFilterContainer objectForKey:[fileURL absoluteString]]) {
- NSMutableDictionary *c = [[NSMutableDictionary alloc] init];
- [c setDictionary:[contentFilterContainer objectForKey:[fileURL absoluteString]]];
- [c setObject:contentFilterArray forKey:filterType];
- [contentFilterContainer setObject:c forKey:[fileURL absoluteString]];
- [c release];
- }
-#endif
-}
-
-- (void)replaceFavoritesByArray:(NSArray *)favoritesArray forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([favoritesContainer objectForKey:[fileURL absoluteString]])
- [favoritesContainer setObject:favoritesArray forKey:[fileURL absoluteString]];
-#endif
-}
-
-- (void)replaceHistoryByArray:(NSArray *)historyArray forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([historyContainer objectForKey:[fileURL absoluteString]])
- [historyContainer setObject:historyArray forKey:[fileURL absoluteString]];
-
- // Inform all opened documents to update the history list
- for(id doc in [[NSApp delegate] orderedDocuments])
- if([[doc valueForKeyPath:@"customQueryInstance"] respondsToSelector:@selector(historyItemsHaveBeenUpdated:)])
- [[doc valueForKeyPath:@"customQueryInstance"] performSelectorOnMainThread:@selector(historyItemsHaveBeenUpdated:) withObject:self waitUntilDone:NO];
-
- // User did choose to clear the global history list
- if(![fileURL isFileURL] && ![historyArray count])
- [prefs setObject:historyArray forKey:SPQueryHistory];
-#endif
-}
-
-- (void)addFavorite:(NSDictionary *)favorite forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([favoritesContainer objectForKey:[fileURL absoluteString]])
- [[favoritesContainer objectForKey:[fileURL absoluteString]] addObject:favorite];
-#endif
-}
-
-- (void)addHistory:(NSString *)history forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- NSUInteger maxHistoryItems = [[prefs objectForKey:SPCustomQueryMaxHistoryItems] integerValue];
-
- // Save each history item due to its document source
- if([historyContainer objectForKey:[fileURL absoluteString]]) {
-
- // Remove all duplicates by using a NSPopUpButton
- NSPopUpButton *uniquifier = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0,0,0,0) pullsDown:YES];
- [uniquifier addItemsWithTitles:[historyContainer objectForKey:[fileURL absoluteString]]];
- [uniquifier insertItemWithTitle:history atIndex:0];
-
- while ( (NSUInteger)[uniquifier numberOfItems] > maxHistoryItems )
- [uniquifier removeItemAtIndex:[uniquifier numberOfItems]-1];
-
- [self replaceHistoryByArray:[uniquifier itemTitles] forFileURL:fileURL];
- [uniquifier release];
- }
-
- // Save history items coming from each Untitled document in the global Preferences successively
- // regardingless of the source document.
- if(![fileURL isFileURL]) {
-
- // Remove all duplicates by using a NSPopUpButton
- NSPopUpButton *uniquifier = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0,0,0,0) pullsDown:YES];
- [uniquifier addItemsWithTitles:[prefs objectForKey:SPQueryHistory]];
- [uniquifier insertItemWithTitle:history atIndex:0];
-
- while ( (NSUInteger)[uniquifier numberOfItems] > maxHistoryItems )
- [uniquifier removeItemAtIndex:[uniquifier numberOfItems]-1];
-
- [prefs setObject:[uniquifier itemTitles] forKey:SPQueryHistory];
- [uniquifier release];
- }
-#endif
-}
-
-- (NSMutableArray *)favoritesForFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([favoritesContainer objectForKey:[fileURL absoluteString]])
- return [favoritesContainer objectForKey:[fileURL absoluteString]];
-#endif
-
- return [NSMutableArray array];
-}
-
-- (NSMutableArray *)historyForFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([historyContainer objectForKey:[fileURL absoluteString]])
- return [historyContainer objectForKey:[fileURL absoluteString]];
-#endif
-
- return [NSMutableArray array];
-}
-
-- (NSArray *)historyMenuItemsForFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([historyContainer objectForKey:[fileURL absoluteString]]) {
- NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:[[historyContainer objectForKey:[fileURL absoluteString]] count]];
- NSMenuItem *historyMenuItem;
- for(NSString* history in [historyContainer objectForKey:[fileURL absoluteString]]) {
- historyMenuItem = [[[NSMenuItem alloc] initWithTitle:([history length] > 64) ? [NSString stringWithFormat:@"%@…", [history substringToIndex:63]] : history
- action:NULL
- keyEquivalent:@""] autorelease];
- [historyMenuItem setToolTip:([history length] > 256) ? [NSString stringWithFormat:@"%@…", [history substringToIndex:255]] : history];
- [returnArray addObject:historyMenuItem];
- }
-
- return returnArray;
- }
-#endif
-
- return [NSArray array];
-}
-
-/**
- * Return the number of history items for the passed file URL
- *
- * @param fileURL The NSURL of the current active SPDatabaseDocument
- *
- */
-- (NSUInteger)numberOfHistoryItemsForFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([historyContainer objectForKey:[fileURL absoluteString]])
- return [[historyContainer objectForKey:[fileURL absoluteString]] count];
- else
-#endif
- return 0;
-}
-
-/**
- * Return a mutable dictionary of all content filters for the passed file URL.
- * If no content filters were found it returns an empty mutable dictionary.
- *
- * @param fileURL The NSURL of the current active SPDatabaseDocument
- *
- */
-- (NSMutableDictionary *)contentFilterForFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- if([contentFilterContainer objectForKey:[fileURL absoluteString]])
- return [contentFilterContainer objectForKey:[fileURL absoluteString]];
-#endif
-
- return [NSMutableDictionary dictionary];
-}
-
-- (NSArray *)queryFavoritesForFileURL:(NSURL *)fileURL andTabTrigger:(NSString *)tabTrigger includeGlobals:(BOOL)includeGlobals
-{
- if(![tabTrigger length]) return [NSArray array];
-
- NSMutableArray *result = [[NSMutableArray alloc] init];
- for(id fav in [self favoritesForFileURL:fileURL]) {
- if([fav objectForKey:@"tabtrigger"] && [[fav objectForKey:@"tabtrigger"] isEqualToString:tabTrigger])
- [result addObject:fav];
- }
-
-#ifndef SP_REFACTOR
- if(includeGlobals && [prefs objectForKey:SPQueryFavorites]) {
- for(id fav in [prefs objectForKey:SPQueryFavorites]) {
- if([fav objectForKey:@"tabtrigger"] && [[fav objectForKey:@"tabtrigger"] isEqualToString:tabTrigger]) {
- [result addObject:fav];
- break;
- }
- }
- }
-#endif
-
- return [result autorelease];
-}
-
-/**
- * Remove a Query Favorite the passed file URL
- *
- * @param index The index of the to be removed favorite
- *
- * @param fileURL The NSURL of the current active SPDatabaseDocument
- *
- */
-- (void)removeFavoriteAtIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- [[favoritesContainer objectForKey:[fileURL absoluteString]] removeObjectAtIndex:index];
-#endif
-}
-
-- (void)insertFavorite:(NSDictionary *)favorite atIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL
-{
-#ifndef SP_REFACTOR
- [[favoritesContainer objectForKey:[fileURL absoluteString]] insertObject:favorite atIndex:index];
-#endif
-}
-
-#pragma mark -
-
-/**
- * Dealloc.
- */
-- (void)dealloc
-{
-#ifndef SP_REFACTOR
- messagesVisibleSet = nil;
-#endif
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
-#ifndef SP_REFACTOR
- [dateFormatter release], dateFormatter = nil;
-
- [messagesFullSet release], messagesFullSet = nil;
- [messagesFilteredSet release], messagesFilteredSet = nil;
- [activeFilterString release], activeFilterString = nil;
-
- [favoritesContainer release], favoritesContainer = nil;
- [historyContainer release], historyContainer = nil;
- [contentFilterContainer release], contentFilterContainer = nil;
-#endif
-
- if(completionKeywordList) [completionKeywordList release];
- if(completionFunctionList) [completionFunctionList release];
- if(functionArgumentSnippets) [functionArgumentSnippets release];
-
-#ifndef SP_REFACTOR
- pthread_mutex_destroy(&consoleLock);
-#endif
-
- [super dealloc];
-}
-
-@end
-
-@implementation SPQueryController (PrivateAPI)
-
-/**
* Updates the filtered result set based on any filter string and whether or not
* all SELECT nd SHOW statements should be shown within the console.
*/
- (void)_updateFilterState
{
#ifndef SP_REFACTOR
-
// Display start progress spinner
[progressIndicator setHidden:NO];
[progressIndicator startAnimation:self];
-
+
// Don't allow clearing the console while filtering its content
[saveConsoleButton setEnabled:NO];
[clearConsoleButton setEnabled:NO];
-
+
[messagesFilteredSet removeAllObjects];
-
+
// If filtering is disabled and all show/selects are shown, empty the filtered
// result set and set the full set to visible.
if (!filterIsActive && !showSelectStatementsAreDisabled && !showHelpStatementsAreDisabled) {
messagesVisibleSet = messagesFullSet;
-
+
[consoleTableView reloadData];
[consoleTableView scrollRowToVisible:([messagesVisibleSet count] - 1)];
-
+
[saveConsoleButton setEnabled:YES];
[clearConsoleButton setEnabled:YES];
-
+
[saveConsoleButton setTitle:NSLocalizedString(@"Save As...", @"save as button title")];
-
+
// Hide progress spinner
[progressIndicator setHidden:YES];
[progressIndicator stopAnimation:self];
+
return;
}
-
+
// Cache frequently used selector, avoiding dynamic binding overhead
IMP messageMatchesFilters = [self methodForSelector:@selector(_messageMatchesCurrentFilters:)];
-
+
// Loop through all the messages in the full set to determine which should be
// added to the filtered set.
for (SPConsoleMessage *message in messagesFullSet) {
-
+
// Add a reference to the message to the filtered set if filters are active and the
// current message matches them
if ((messageMatchesFilters)(self, @selector(_messageMatchesCurrentFilters:), [message message])) {
[messagesFilteredSet addObject:message];
}
}
-
+
// Ensure that the filtered set is marked as the currently visible set.
messagesVisibleSet = messagesFilteredSet;
-
+
[consoleTableView reloadData];
[consoleTableView scrollRowToVisible:([messagesVisibleSet count] - 1)];
-
+
if ([messagesVisibleSet count] > 0) {
[saveConsoleButton setEnabled:YES];
[clearConsoleButton setEnabled:YES];
}
-
+
[saveConsoleButton setTitle:NSLocalizedString(@"Save View As...", @"save view as button title")];
-
+
// Hide progress spinner
[progressIndicator setHidden:YES];
[progressIndicator stopAnimation:self];
@@ -1010,32 +485,27 @@ static SPQueryController *sharedQueryController = nil;
- (BOOL)_messageMatchesCurrentFilters:(NSString *)message
{
BOOL messageMatchesCurrentFilters = YES;
-
+
#ifndef SP_REFACTOR
// Check whether to hide the message based on the current filter text, if any
- if (filterIsActive
- && [message rangeOfString:activeFilterString options:NSCaseInsensitiveSearch].location == NSNotFound)
- {
+ if (filterIsActive && [message rangeOfString:activeFilterString options:NSCaseInsensitiveSearch].location == NSNotFound) {
messageMatchesCurrentFilters = NO;
}
-
+
// If hiding SELECTs and SHOWs is toggled to on, check whether the message is a SELECT or SHOW
- if (messageMatchesCurrentFilters
- && showSelectStatementsAreDisabled
- && ([[message uppercaseString] hasPrefix:@"SELECT"] || [[message uppercaseString] hasPrefix:@"SHOW"]))
+ if (messageMatchesCurrentFilters &&
+ showSelectStatementsAreDisabled &&
+ ([[message uppercaseString] hasPrefix:@"SELECT"] || [[message uppercaseString] hasPrefix:@"SHOW"]))
{
messageMatchesCurrentFilters = NO;
}
-
+
// If hiding HELP is toggled to on, check whether the message is a HELP
- if (messageMatchesCurrentFilters
- && showHelpStatementsAreDisabled
- && ([[message uppercaseString] hasPrefix:@"HELP"]))
- {
+ if (messageMatchesCurrentFilters && showHelpStatementsAreDisabled && ([[message uppercaseString] hasPrefix:@"HELP"])) {
messageMatchesCurrentFilters = NO;
}
#endif
-
+
return messageMatchesCurrentFilters;
}
@@ -1046,30 +516,29 @@ static SPQueryController *sharedQueryController = nil;
- (NSString *)_getConsoleStringWithTimeStamps:(BOOL)timeStamps connections:(BOOL)connections
{
NSMutableString *consoleString = [NSMutableString string];
-
+
#ifndef SP_REFACTOR
for (SPConsoleMessage *message in messagesVisibleSet)
{
// As we are going to save the messages as an SQL file we need to comment
// the timestamps and connections if included.
if (timeStamps || connections) [consoleString appendString:@"/* "];
-
+
// If the timestamp column is not hidden we need to include them in the copy
if (timeStamps)
[consoleString appendFormat:@"%@ ", [dateFormatter stringFromDate:[message messageDate]]];
-
+
// If the connection column is not hidden we need to include them in the copy
if (connections)
[consoleString appendFormat:@"%@ ", [message messageConnection]];
-
+
// Close the comment
if (timeStamps || connections) [consoleString appendString:@"*/ "];
-
+
[consoleString appendFormat:@"%@\n", [message message]];
-
}
#endif
-
+
return consoleString;
}
@@ -1080,20 +549,18 @@ static SPQueryController *sharedQueryController = nil;
{
#ifndef SP_REFACTOR
NSString *messageTemp = [[message stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
-
+
// Only append a semi-colon (;) if the supplied message is not an error
- if (!error) {
- messageTemp = [messageTemp stringByAppendingString:@";"];
- }
-
+ if (!error) messageTemp = [messageTemp stringByAppendingString:@";"];
+
SPConsoleMessage *consoleMessage = [SPConsoleMessage consoleMessageWithMessage:messageTemp date:[NSDate date] connection:connection];
-
+
[consoleMessage setIsError:error];
-
+
pthread_mutex_lock(&consoleLock);
[messagesFullSet addObject:consoleMessage];
-
+
// If filtering is active, determine whether to add a reference to the filtered set
if ((showSelectStatementsAreDisabled || showHelpStatementsAreDisabled || filterIsActive)
&& [self _messageMatchesCurrentFilters:[consoleMessage message]])
@@ -1102,7 +569,7 @@ static SPQueryController *sharedQueryController = nil;
[saveConsoleButton setEnabled:YES];
[clearConsoleButton setEnabled:YES];
}
-
+
// Reload the table and scroll to the new message if it's visible (for speed)
if (allowConsoleUpdate && [[self window] isVisible]) {
[consoleTableView noteNumberOfRowsChanged];
@@ -1114,4 +581,39 @@ static SPQueryController *sharedQueryController = nil;
#endif
}
+#pragma mark -
+
+/**
+ * Dealloc.
+ */
+- (void)dealloc
+{
+#ifndef SP_REFACTOR
+ messagesVisibleSet = nil;
+#endif
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+#ifndef SP_REFACTOR
+ [dateFormatter release], dateFormatter = nil;
+
+ [messagesFullSet release], messagesFullSet = nil;
+ [messagesFilteredSet release], messagesFilteredSet = nil;
+ [activeFilterString release], activeFilterString = nil;
+
+ [favoritesContainer release], favoritesContainer = nil;
+ [historyContainer release], historyContainer = nil;
+ [contentFilterContainer release], contentFilterContainer = nil;
+#endif
+
+ if (completionKeywordList) [completionKeywordList release], completionKeywordList = nil;
+ if (completionFunctionList) [completionFunctionList release], completionFunctionList = nil;
+ if (functionArgumentSnippets) [functionArgumentSnippets release], functionArgumentSnippets = nil;
+
+#ifndef SP_REFACTOR
+ pthread_mutex_destroy(&consoleLock);
+#endif
+
+ [super dealloc];
+}
+
@end
diff --git a/Source/SPQueryControllerInitializer.h b/Source/SPQueryControllerInitializer.h
new file mode 100644
index 00000000..2bee90af
--- /dev/null
+++ b/Source/SPQueryControllerInitializer.h
@@ -0,0 +1,32 @@
+//
+// $Id$
+//
+// SPQueryControllerInitializer.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 1, 2011
+// Copyright (c) 2011 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPQueryController.h"
+
+@interface SPQueryController (SPQueryControllerInitializer)
+
+- (NSError *)loadCompletionLists;
+
+@end
diff --git a/Source/SPQueryControllerInitializer.m b/Source/SPQueryControllerInitializer.m
new file mode 100644
index 00000000..2d43898e
--- /dev/null
+++ b/Source/SPQueryControllerInitializer.m
@@ -0,0 +1,135 @@
+//
+// $Id$
+//
+// SPQueryControllerInitializer.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 1, 2011
+// Copyright (c) 2011 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPQueryControllerInitializer.h"
+
+static NSString *SPCompletionTokensFilename = @"CompletionTokens.plist";
+
+static NSString *SPCompletionTokensKeywordsKey = @"core_keywords";
+static NSString *SPCompletionTokensFunctionsKey = @"core_builtin_functions";
+static NSString *SPCompletionTokensSnippetsKey = @"function_argument_snippets";
+
+@interface SPQueryController ()
+
+- (void)_updateFilterState;
+
+@end
+
+@implementation SPQueryController (SPQueryControllerInitializer)
+
+/**
+ * Set the window's auto save name and initialise display
+ */
+- (void)awakeFromNib
+{
+#ifndef SP_REFACTOR /* init ivars */
+ prefs = [NSUserDefaults standardUserDefaults];
+
+ [self setWindowFrameAutosaveName:SPQueryConsoleWindowAutoSaveName];
+
+ // Show/hide table columns
+ [[consoleTableView tableColumnWithIdentifier:SPTableViewDateColumnID] setHidden:![prefs boolForKey:SPConsoleShowTimestamps]];
+ [[consoleTableView tableColumnWithIdentifier:SPTableViewConnectionColumnID] setHidden:![prefs boolForKey:SPConsoleShowConnections]];
+
+ showSelectStatementsAreDisabled = ![prefs boolForKey:SPConsoleShowSelectsAndShows];
+ showHelpStatementsAreDisabled = ![prefs boolForKey:SPConsoleShowHelps];
+
+ [self _updateFilterState];
+
+ [loggingDisabledTextField setStringValue:([prefs boolForKey:SPConsoleEnableLogging]) ? @"" : NSLocalizedString(@"Query logging is currently disabled", @"query logging disabled label")];
+
+ // Setup data formatter
+ dateFormatter = [[NSDateFormatter alloc] init];
+
+ [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
+
+ [dateFormatter setDateStyle:NSDateFormatterNoStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
+
+ // Set the process table view's vertical gridlines if required
+ [consoleTableView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone];
+
+ // Set the strutcture and index view's font
+ BOOL useMonospacedFont = [prefs boolForKey:SPUseMonospacedFonts];
+
+ for (NSTableColumn *column in [consoleTableView tableColumns])
+ {
+ [[column dataCell] setFont:(useMonospacedFont) ? [NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]] : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ }
+#endif
+}
+
+/**
+ * Loads the query controller's completion tokens data.
+ */
+- (NSError *)loadCompletionLists
+{
+ NSError *readError = nil;
+ NSString *convError = nil;
+ NSString *errorDescription = nil;
+
+ NSPropertyListFormat format;
+ NSData *completionTokensData = [NSData dataWithContentsOfFile:
+ [NSBundle pathForResource:SPCompletionTokensFilename
+ ofType:nil
+ inDirectory:[[NSBundle mainBundle] bundlePath]]
+ options:NSMappedRead error:&readError];
+
+ NSDictionary *completionPlist = [NSDictionary dictionaryWithDictionary:
+ [NSPropertyListSerialization propertyListFromData:completionTokensData
+ mutabilityOption:NSPropertyListMutableContainersAndLeaves
+ format:&format
+ errorDescription:&convError]];
+
+ if (completionPlist == nil || readError != nil || convError != nil) {
+ errorDescription = [NSString stringWithFormat:@"Error reading '%@': %@, %@", SPCompletionTokensFilename, [readError localizedDescription], convError];
+ }
+ else {
+ if ([completionPlist objectForKey:SPCompletionTokensKeywordsKey]) {
+ completionKeywordList = [[NSArray arrayWithArray:[completionPlist objectForKey:SPCompletionTokensKeywordsKey]] retain];
+ }
+ else {
+ errorDescription = [NSString stringWithFormat:@"No '%@' array found.", SPCompletionTokensKeywordsKey];
+ }
+
+ if ([completionPlist objectForKey:SPCompletionTokensFunctionsKey]) {
+ completionFunctionList = [[NSArray arrayWithArray:[completionPlist objectForKey:SPCompletionTokensFunctionsKey]] retain];
+ }
+ else {
+ errorDescription = [NSString stringWithFormat:@"No '%@' array found.", SPCompletionTokensFunctionsKey];
+ }
+
+ if ([completionPlist objectForKey:SPCompletionTokensSnippetsKey]) {
+ functionArgumentSnippets = [[NSDictionary dictionaryWithDictionary:[completionPlist objectForKey:SPCompletionTokensSnippetsKey]] retain];
+ }
+ else {
+ errorDescription = [NSString stringWithFormat:@"No '%@' dictionary found.", SPCompletionTokensSnippetsKey];
+ }
+ }
+
+ return errorDescription ? [NSError errorWithDomain:NSCocoaErrorDomain code:1 userInfo:[NSDictionary dictionaryWithObject:errorDescription forKey:NSLocalizedDescriptionKey]] : nil;
+}
+
+@end
diff --git a/Source/SPQueryDocumentsController.h b/Source/SPQueryDocumentsController.h
new file mode 100644
index 00000000..2d109b27
--- /dev/null
+++ b/Source/SPQueryDocumentsController.h
@@ -0,0 +1,56 @@
+//
+// $Id$
+//
+// SPQueryDocumentsController.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 30, 2011
+// Copyright (c) 2011 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPQueryController.h"
+
+@interface SPQueryController (SPQueryDocumentsController)
+
+- (NSURL *)registerDocumentWithFileURL:(NSURL *)fileURL andContextInfo:(NSMutableDictionary *)contextInfo;
+- (void)removeRegisteredDocumentWithFileURL:(NSURL *)fileURL;
+
+- (void)addFavorite:(NSDictionary *)favorite forFileURL:(NSURL *)fileURL;
+- (void)replaceFavoritesByArray:(NSArray *)favoritesArray forFileURL:(NSURL *)fileURL;
+- (void)removeFavoriteAtIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL;
+- (void)insertFavorite:(NSDictionary *)favorite atIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL;
+
+- (void)addHistory:(NSString *)history forFileURL:(NSURL *)fileURL;
+- (void)replaceHistoryByArray:(NSArray *)historyArray forFileURL:(NSURL *)fileURL;
+
+- (void)replaceContentFilterByArray:(NSArray *)contentFilterArray ofType:(NSString *)filterType forFileURL:(NSURL *)fileURL;
+
+- (NSMutableArray *)favoritesForFileURL:(NSURL *)fileURL;
+- (NSMutableArray *)historyForFileURL:(NSURL *)fileURL;
+- (NSArray *)historyMenuItemsForFileURL:(NSURL *)fileURL;
+- (NSUInteger)numberOfHistoryItemsForFileURL:(NSURL *)fileURL;
+- (NSMutableDictionary *)contentFilterForFileURL:(NSURL *)fileURL;
+
+- (NSArray *)queryFavoritesForFileURL:(NSURL *)fileURL andTabTrigger:(NSString *)tabTrigger includeGlobals:(BOOL)includeGlobals;
+
+// Completion list controller
+- (NSArray*)functionList;
+- (NSArray*)keywordList;
+- (NSString*)argumentSnippetForFunction:(NSString*)func;
+
+@end
diff --git a/Source/SPQueryDocumentsController.m b/Source/SPQueryDocumentsController.m
new file mode 100644
index 00000000..b4c3df22
--- /dev/null
+++ b/Source/SPQueryDocumentsController.m
@@ -0,0 +1,407 @@
+//
+// $Id$
+//
+// SPQueryDocumentsController.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 30, 2011
+// Copyright (c) 2011 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPQueryDocumentsController.h"
+
+@implementation SPQueryController (SPQueryDocumentsController)
+
+- (NSURL *)registerDocumentWithFileURL:(NSURL *)fileURL andContextInfo:(NSMutableDictionary *)contextInfo
+{
+#ifndef SP_REFACTOR
+ // Register a new untiled document and return its URL
+ if (fileURL == nil) {
+ NSURL *new = [NSURL URLWithString:[[NSString stringWithFormat:NSLocalizedString(@"Untitled %ld",@"Title of a new Sequel Pro Document"), (unsigned long)untitledDocumentCounter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ untitledDocumentCounter++;
+
+ if (![favoritesContainer objectForKey:[new absoluteString]]) {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [favoritesContainer setObject:arr forKey:[new absoluteString]];
+ [arr release];
+ }
+
+ // Set the global history coming from the Prefs as default if available
+ if (![historyContainer objectForKey:[new absoluteString]]) {
+ if ([prefs objectForKey:SPQueryHistory]) {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [arr addObjectsFromArray:[prefs objectForKey:SPQueryHistory]];
+ [historyContainer setObject:arr forKey:[new absoluteString]];
+ [arr release];
+ }
+ else {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [historyContainer setObject:[NSMutableArray array] forKey:[new absoluteString]];
+ [arr release];
+ }
+ }
+
+ // Set the doc-based content filters
+ if (![contentFilterContainer objectForKey:[new absoluteString]]) {
+ [contentFilterContainer setObject:[NSMutableDictionary dictionary] forKey:[new absoluteString]];
+ }
+
+ return new;
+ }
+
+ // Register a spf file to manage all query favorites and query history items
+ // file path based (incl. Untitled docs) in a dictionary whereby the key represents the file URL as string.
+ if (![favoritesContainer objectForKey:[fileURL absoluteString]]) {
+ if (contextInfo != nil && [contextInfo objectForKey:SPQueryFavorites] && [[contextInfo objectForKey:SPQueryFavorites] count]) {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [arr addObjectsFromArray:[contextInfo objectForKey:SPQueryFavorites]];
+ [favoritesContainer setObject:arr forKey:[fileURL absoluteString]];
+ [arr release];
+ }
+ else {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [favoritesContainer setObject:arr forKey:[fileURL absoluteString]];
+ [arr release];
+ }
+ }
+
+ if (![historyContainer objectForKey:[fileURL absoluteString]]) {
+ if (contextInfo != nil && [contextInfo objectForKey:SPQueryHistory] && [[contextInfo objectForKey:SPQueryHistory] count]) {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [arr addObjectsFromArray:[contextInfo objectForKey:SPQueryHistory]];
+ [historyContainer setObject:arr forKey:[fileURL absoluteString]];
+ [arr release];
+ }
+ else {
+ NSMutableArray *arr = [[NSMutableArray alloc] init];
+ [historyContainer setObject:arr forKey:[fileURL absoluteString]];
+ [arr release];
+ }
+ }
+
+ if (![contentFilterContainer objectForKey:[fileURL absoluteString]]) {
+ if (contextInfo != nil && [contextInfo objectForKey:SPContentFilters]) {
+ [contentFilterContainer setObject:[contextInfo objectForKey:SPContentFilters] forKey:[fileURL absoluteString]];
+ }
+ else {
+ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+ [contentFilterContainer setObject:dict forKey:[fileURL absoluteString]];
+ [dict release];
+ }
+ }
+
+ return fileURL;
+#else
+ return nil;
+#endif
+}
+
+- (void)removeRegisteredDocumentWithFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ // Check for multiple instance of the same document.
+ // Remove it if only one instance was registerd.
+ NSArray *allDocs = [[NSApp delegate] orderedDocuments];
+ NSMutableArray *allURLs = [NSMutableArray array];
+
+ for (id doc in allDocs)
+ {
+ if (![doc fileURL]) continue;
+
+ if ([allURLs containsObject:[doc fileURL]]) {
+ return;
+ }
+ else {
+ [allURLs addObject:[doc fileURL]];
+ }
+ }
+
+ if ([favoritesContainer objectForKey:[fileURL absoluteString]]) {
+ [favoritesContainer removeObjectForKey:[fileURL absoluteString]];
+ }
+
+ if ([historyContainer objectForKey:[fileURL absoluteString]]) {
+ [historyContainer removeObjectForKey:[fileURL absoluteString]];
+ }
+
+ if ([contentFilterContainer objectForKey:[fileURL absoluteString]]) {
+ [contentFilterContainer removeObjectForKey:[fileURL absoluteString]];
+ }
+#endif
+}
+
+- (void)replaceContentFilterByArray:(NSArray *)contentFilterArray ofType:(NSString *)filterType forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([contentFilterContainer objectForKey:[fileURL absoluteString]]) {
+ NSMutableDictionary *c = [[NSMutableDictionary alloc] init];
+ [c setDictionary:[contentFilterContainer objectForKey:[fileURL absoluteString]]];
+ [c setObject:contentFilterArray forKey:filterType];
+ [contentFilterContainer setObject:c forKey:[fileURL absoluteString]];
+ [c release];
+ }
+#endif
+}
+
+- (void)replaceFavoritesByArray:(NSArray *)favoritesArray forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([favoritesContainer objectForKey:[fileURL absoluteString]]) {
+ [favoritesContainer setObject:favoritesArray forKey:[fileURL absoluteString]];
+ }
+#endif
+}
+
+/**
+ * Remove a Query Favorite the passed file URL
+ *
+ * @param index The index of the to be removed favorite
+ *
+ * @param fileURL The NSURL of the current active SPDatabaseDocument
+ */
+- (void)removeFavoriteAtIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ [[favoritesContainer objectForKey:[fileURL absoluteString]] removeObjectAtIndex:index];
+#endif
+}
+
+- (void)insertFavorite:(NSDictionary *)favorite atIndex:(NSUInteger)index forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ [[favoritesContainer objectForKey:[fileURL absoluteString]] insertObject:favorite atIndex:index];
+#endif
+}
+
+- (void)replaceHistoryByArray:(NSArray *)historyArray forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([historyContainer objectForKey:[fileURL absoluteString]]) {
+ [historyContainer setObject:historyArray forKey:[fileURL absoluteString]];
+ }
+
+ // Inform all opened documents to update the history list
+ for (id doc in [[NSApp delegate] orderedDocuments])
+ {
+ if([[doc valueForKeyPath:@"customQueryInstance"] respondsToSelector:@selector(historyItemsHaveBeenUpdated:)]) {
+ [[doc valueForKeyPath:@"customQueryInstance"] performSelectorOnMainThread:@selector(historyItemsHaveBeenUpdated:) withObject:self waitUntilDone:NO];
+ }
+ }
+
+ // User did choose to clear the global history list
+ if (![fileURL isFileURL] && ![historyArray count]) {
+ [prefs setObject:historyArray forKey:SPQueryHistory];
+ }
+#endif
+}
+
+- (void)addFavorite:(NSDictionary *)favorite forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([favoritesContainer objectForKey:[fileURL absoluteString]]) {
+ [[favoritesContainer objectForKey:[fileURL absoluteString]] addObject:favorite];
+ }
+#endif
+}
+
+- (void)addHistory:(NSString *)history forFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ NSUInteger maxHistoryItems = [[prefs objectForKey:SPCustomQueryMaxHistoryItems] integerValue];
+
+ // Save each history item due to its document source
+ if ([historyContainer objectForKey:[fileURL absoluteString]]) {
+
+ // Remove all duplicates by using a NSPopUpButton
+ NSPopUpButton *uniquifier = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0,0,0,0) pullsDown:YES];
+
+ [uniquifier addItemsWithTitles:[historyContainer objectForKey:[fileURL absoluteString]]];
+ [uniquifier insertItemWithTitle:history atIndex:0];
+
+ while ((NSUInteger)[uniquifier numberOfItems] > maxHistoryItems)
+ {
+ [uniquifier removeItemAtIndex:[uniquifier numberOfItems]-1];
+ }
+
+ [self replaceHistoryByArray:[uniquifier itemTitles] forFileURL:fileURL];
+ [uniquifier release];
+ }
+
+ // Save history items coming from each Untitled document in the global Preferences successively
+ // regardingless of the source document.
+ if (![fileURL isFileURL]) {
+
+ // Remove all duplicates by using a NSPopUpButton
+ NSPopUpButton *uniquifier = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0,0,0,0) pullsDown:YES];
+ [uniquifier addItemsWithTitles:[prefs objectForKey:SPQueryHistory]];
+ [uniquifier insertItemWithTitle:history atIndex:0];
+
+ while ((NSUInteger)[uniquifier numberOfItems] > maxHistoryItems)
+ {
+ [uniquifier removeItemAtIndex:[uniquifier numberOfItems] - 1];
+ }
+
+ [prefs setObject:[uniquifier itemTitles] forKey:SPQueryHistory];
+ [uniquifier release];
+ }
+#endif
+}
+
+- (NSMutableArray *)favoritesForFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([favoritesContainer objectForKey:[fileURL absoluteString]]) {
+ return [favoritesContainer objectForKey:[fileURL absoluteString]];
+ }
+#endif
+
+ return [NSMutableArray array];
+}
+
+- (NSMutableArray *)historyForFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([historyContainer objectForKey:[fileURL absoluteString]]) {
+ return [historyContainer objectForKey:[fileURL absoluteString]];
+ }
+#endif
+
+ return [NSMutableArray array];
+}
+
+- (NSArray *)historyMenuItemsForFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([historyContainer objectForKey:[fileURL absoluteString]]) {
+ NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:[[historyContainer objectForKey:[fileURL absoluteString]] count]];
+ NSMenuItem *historyMenuItem;
+
+ for (NSString* history in [historyContainer objectForKey:[fileURL absoluteString]])
+ {
+ historyMenuItem = [[[NSMenuItem alloc] initWithTitle:([history length] > 64) ? [NSString stringWithFormat:@"%@…", [history substringToIndex:63]] : history
+ action:NULL
+ keyEquivalent:@""] autorelease];
+
+ [historyMenuItem setToolTip:([history length] > 256) ? [NSString stringWithFormat:@"%@…", [history substringToIndex:255]] : history];
+ [returnArray addObject:historyMenuItem];
+ }
+
+ return returnArray;
+ }
+#endif
+
+ return [NSArray array];
+}
+
+/**
+ * Return the number of history items for the passed file URL
+ *
+ * @param fileURL The NSURL of the current active SPDatabaseDocument
+ *
+ */
+- (NSUInteger)numberOfHistoryItemsForFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([historyContainer objectForKey:[fileURL absoluteString]]) {
+ return [[historyContainer objectForKey:[fileURL absoluteString]] count];
+ }
+ else {
+ return 0;
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * Return a mutable dictionary of all content filters for the passed file URL.
+ * If no content filters were found it returns an empty mutable dictionary.
+ *
+ * @param fileURL The NSURL of the current active SPDatabaseDocument
+ *
+ */
+- (NSMutableDictionary *)contentFilterForFileURL:(NSURL *)fileURL
+{
+#ifndef SP_REFACTOR
+ if ([contentFilterContainer objectForKey:[fileURL absoluteString]]) {
+ return [contentFilterContainer objectForKey:[fileURL absoluteString]];
+ }
+#endif
+
+ return [NSMutableDictionary dictionary];
+}
+
+- (NSArray *)queryFavoritesForFileURL:(NSURL *)fileURL andTabTrigger:(NSString *)tabTrigger includeGlobals:(BOOL)includeGlobals
+{
+ if (![tabTrigger length]) return [NSArray array];
+
+ NSMutableArray *result = [[NSMutableArray alloc] init];
+
+ for (id fav in [self favoritesForFileURL:fileURL])
+ {
+ if ([fav objectForKey:@"tabtrigger"] && [[fav objectForKey:@"tabtrigger"] isEqualToString:tabTrigger]) {
+ [result addObject:fav];
+ }
+ }
+
+#ifndef SP_REFACTOR
+ if (includeGlobals && [prefs objectForKey:SPQueryFavorites]) {
+
+ for (id fav in [prefs objectForKey:SPQueryFavorites])
+ {
+ if ([fav objectForKey:@"tabtrigger"] && [[fav objectForKey:@"tabtrigger"] isEqualToString:tabTrigger]) {
+ [result addObject:fav];
+ break;
+ }
+ }
+ }
+#endif
+
+ return [result autorelease];
+}
+
+#pragma mark -
+#pragma mark Completion list controller
+
+/**
+ * Return an array of all pre-defined SQL functions for completion.
+ */
+- (NSArray*)functionList
+{
+ return (completionFunctionList != nil && [completionFunctionList count]) ? completionFunctionList : [NSArray array];
+}
+
+/**
+ * Return an array of all pre-defined SQL keywords for completion.
+ */
+- (NSArray*)keywordList
+{
+ return (completionKeywordList != nil && [completionKeywordList count]) ? completionKeywordList : [NSArray array];
+}
+
+/**
+ * Return the parameter list as snippet of the passed SQL functions for completion.
+ *
+ * @param func The name of the function whose parameter list is asked for
+ */
+- (NSString*)argumentSnippetForFunction:(NSString*)func
+{
+ return (functionArgumentSnippets && [functionArgumentSnippets objectForKey:[func uppercaseString]]) ? [functionArgumentSnippets objectForKey:[func uppercaseString]] : @"";
+}
+
+@end
diff --git a/Source/SPQueryFavoriteManager.m b/Source/SPQueryFavoriteManager.m
index 7fe5797f..90575e33 100644
--- a/Source/SPQueryFavoriteManager.m
+++ b/Source/SPQueryFavoriteManager.m
@@ -27,6 +27,7 @@
#import "ImageAndTextCell.h"
#import "SPEncodingPopupAccessory.h"
#import "SPQueryController.h"
+#import "SPQueryDocumentsController.h"
#import "SPConnectionController.h"
#import "RegexKitLite.h"
#import "SPTextView.h"
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 7304f53e..aef067a6 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -35,6 +35,7 @@
#import "SPDataCellFormatter.h"
#import "SPTableData.h"
#import "SPQueryController.h"
+#import "SPQueryDocumentsController.h"
#import "SPTextAndLinkCell.h"
#ifndef SP_REFACTOR
#import "QLPreviewPanel.h"
diff --git a/Source/SPTextView.m b/Source/SPTextView.m
index 5edad98f..83a1eb22 100644
--- a/Source/SPTextView.m
+++ b/Source/SPTextView.m
@@ -27,6 +27,7 @@
#import "SPDatabaseDocument.h"
#import "SPNarrowDownCompletion.h"
#import "SPQueryController.h"
+#import "SPQueryDocumentsController.h"
#import "SPTooltip.h"
#import "SPTablesList.h"
#import "SPNavigatorController.h"