diff options
author | stuconnolly <stuart02@gmail.com> | 2009-03-26 23:28:27 +0000 |
---|---|---|
committer | stuconnolly <stuart02@gmail.com> | 2009-03-26 23:28:27 +0000 |
commit | 3a7dc0b03bc51f46d762e2bbe6d7afdee59288ef (patch) | |
tree | afdf05045c74e6a7f12590a4005a306a76d221e3 /Source | |
parent | 93dfcc27627fd64c1f6c3124297252298a3f499a (diff) | |
download | sequelpro-3a7dc0b03bc51f46d762e2bbe6d7afdee59288ef.tar.gz sequelpro-3a7dc0b03bc51f46d762e2bbe6d7afdee59288ef.tar.bz2 sequelpro-3a7dc0b03bc51f46d762e2bbe6d7afdee59288ef.zip |
Completely redesigned query console that now uses a table view instead of a text view. This should significantly improve import speed, but most importantly resolves the crashes caused by the drawing that was being performed by the text view. Fixes issue #87 and implements #167.
New console provides the following:
- Live filtering
- Ability to hide message time stamps
- Ability to hide SELECT/SHOW statement messages
- Ability to copy messages to pasteboard, including multiple messages
- Ability to save the current filtered content to a file, with the option to include the message time stamps
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPConsoleMessage.h | 40 | ||||
-rw-r--r-- | Source/SPConsoleMessage.m | 54 | ||||
-rw-r--r-- | Source/SPGrowlController.m | 38 | ||||
-rw-r--r-- | Source/SPQueryConsole.h | 18 | ||||
-rw-r--r-- | Source/SPQueryConsole.m | 436 | ||||
-rw-r--r-- | Source/SPStringAdditions.m | 66 | ||||
-rw-r--r-- | Source/TableContent.h | 6 | ||||
-rw-r--r-- | Source/TableContent.m | 7 | ||||
-rw-r--r-- | Source/TableDocument.h | 5 | ||||
-rw-r--r-- | Source/TableDocument.m | 43 |
10 files changed, 556 insertions, 157 deletions
diff --git a/Source/SPConsoleMessage.h b/Source/SPConsoleMessage.h new file mode 100644 index 00000000..647a50a9 --- /dev/null +++ b/Source/SPConsoleMessage.h @@ -0,0 +1,40 @@ +// +// SPConsoleMessage.h +// sequel-pro +// +// Created by Stuart Connolly (stuconnolly.com) on Mar 12, 2009 +// +// 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 <Cocoa/Cocoa.h> + +@interface SPConsoleMessage : NSObject +{ + BOOL isError; + NSDate *messageDate; + NSString *message; +} + +@property (readwrite, assign) BOOL isError; +@property (readwrite, retain) NSDate *messageDate; +@property (readwrite, retain) NSString *message; + ++ (SPConsoleMessage *)consoleMessageWithMessage:(NSString *)consoleMessage date:(NSDate *)date; + +- (id)initWithMessage:(NSString *)message date:(NSDate *)date; + +@end diff --git a/Source/SPConsoleMessage.m b/Source/SPConsoleMessage.m new file mode 100644 index 00000000..7f7273cc --- /dev/null +++ b/Source/SPConsoleMessage.m @@ -0,0 +1,54 @@ +// +// SPConsoleMessage.m +// sequel-pro +// +// Created by Stuart Connolly (stuconnolly.com) on Mar 12, 2009 +// +// 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 "SPConsoleMessage.h" + +@implementation SPConsoleMessage + +@synthesize isError; +@synthesize messageDate; +@synthesize message; + ++ (SPConsoleMessage *)consoleMessageWithMessage:(NSString *)message date:(NSDate *)date +{ + return [[[SPConsoleMessage alloc] initWithMessage:message date:date] autorelease]; +} + +- (id)initWithMessage:(NSString *)consoleMessage date:(NSDate *)date +{ + if ((self = [super init])) { + [self setMessage:consoleMessage]; + [self setMessageDate:date]; + } + + return self; +} + +- (void)dealloc +{ + [message release], message = nil; + [messageDate release], messageDate = nil; + + [super dealloc]; +} + +@end diff --git a/Source/SPGrowlController.m b/Source/SPGrowlController.m index 3f429067..4583f33e 100644 --- a/Source/SPGrowlController.m +++ b/Source/SPGrowlController.m @@ -26,11 +26,9 @@ static SPGrowlController *sharedGrowlController = nil; @implementation SPGrowlController -// ------------------------------------------------------------------------------- -// sharedGrowlController -// -// Returns the shared Growl controller. -// ------------------------------------------------------------------------------- +/* + * Returns the shared Growl controller. + */ + (SPGrowlController *)sharedGrowlController { @synchronized(self) { @@ -42,9 +40,6 @@ static SPGrowlController *sharedGrowlController = nil; return sharedGrowlController; } -// ------------------------------------------------------------------------------- -// allocWithZone: -// ------------------------------------------------------------------------------- + (id)allocWithZone:(NSZone *)zone { @synchronized(self) { @@ -58,9 +53,6 @@ static SPGrowlController *sharedGrowlController = nil; return nil; // On subsequent allocation attempts return nil } -// ------------------------------------------------------------------------------- -// init -// ------------------------------------------------------------------------------- - (id)init { if (self = [super init]) { @@ -70,10 +62,9 @@ static SPGrowlController *sharedGrowlController = nil; return self; } -// ------------------------------------------------------------------------------- -// The following base protocol methods are implemented to ensure the singleton -// status of this class. -// ------------------------------------------------------------------------------- +/* + * The following base protocol methods are implemented to ensure the singleton status of this class. + */ - (id)copyWithZone:(NSZone *)zone { return self; } @@ -85,11 +76,9 @@ static SPGrowlController *sharedGrowlController = nil; - (void)release { } -// ------------------------------------------------------------------------------- -// notifyWithTitle:description:notificationName: -// -// Posts a Growl notification using the supplied details and default values. -// ------------------------------------------------------------------------------- +/* + * Posts a Growl notification using the supplied details and default values. + */ - (void)notifyWithTitle:(NSString *)title description:(NSString *)description notificationName:(NSString *)name { // Post notification @@ -102,12 +91,9 @@ static SPGrowlController *sharedGrowlController = nil; clickContext:nil]; } -// ------------------------------------------------------------------------------- -// notifyWithTitle:description:notificationName: -// -// Posts a Growl notification using the supplied details and effectively ignoring -// the default values. -// ------------------------------------------------------------------------------- +/* + * Posts a Growl notification using the supplied details and effectively ignoring the default values. + */ - (void)notifyWithTitle:(NSString *)title description:(NSString *)description notificationName:(NSString *)name iconData:(NSData *)data priority:(int)priority isSticky:(BOOL)sticky clickContext:(id)clickContext { // Post notification diff --git a/Source/SPQueryConsole.h b/Source/SPQueryConsole.h index e1072904..65d716d4 100644 --- a/Source/SPQueryConsole.h +++ b/Source/SPQueryConsole.h @@ -24,15 +24,27 @@ @interface SPQueryConsole : NSWindowController { - IBOutlet NSTextView *consoleTextView; + NSFont *consoleFont; + NSMutableArray *messages, *messagesActiveSet, *messagesFilterSet, *messagesSubset; + + IBOutlet NSView *saveLogView; + IBOutlet NSTableView *consoleTableView; + IBOutlet NSSearchField *consoleSearchField; + IBOutlet NSProgressIndicator *progressIndicator; + IBOutlet NSButton *includeTimeStampsButton, *saveConsoleButton, *clearConsoleButton; } +@property (readwrite, retain) NSFont *consoleFont; + ++ (SPQueryConsole *)sharedQueryConsole; + +- (IBAction)copy:(id)sender; - (IBAction)clearConsole:(id)sender; - (IBAction)saveConsoleAs:(id)sender; +- (IBAction)toggleShowTimeStamps:(id)sender; +- (IBAction)toggleShowSelectShowStatements:(id)sender; - (void)showMessageInConsole:(NSString *)message; - (void)showErrorInConsole:(NSString *)error; -- (NSTextView *)consoleTextView; - @end diff --git a/Source/SPQueryConsole.m b/Source/SPQueryConsole.m index 4c171de7..ffae7479 100644 --- a/Source/SPQueryConsole.m +++ b/Source/SPQueryConsole.m @@ -21,45 +21,156 @@ // More info at <http://code.google.com/p/sequel-pro/> #import "SPQueryConsole.h" +#import "SPConsoleMessage.h" + +#define MESSAGE_TRUNCATE_CHARACTER_LENGTH 256 +#define MESSAGE_TIME_STAMP_FORMAT @"%H:%M:%S" #define DEFAULT_CONSOLE_LOG_FILENAME @"untitled" #define DEFAULT_CONSOLE_LOG_FILE_EXTENSION @"log" #define CONSOLE_WINDOW_AUTO_SAVE_NAME @"QueryConsole" +// Table view column identifiers +#define TABLEVIEW_MESSAGE_COLUMN_IDENTIFIER @"message" +#define TABLEVIEW_DATE_COLUMN_IDENTIFIER @"messageDate" + @interface SPQueryConsole (PrivateAPI) -- (void)_appendMessageToConsole:(NSString *)message withColor:(NSColor *)color; +- (NSString *)_getConsoleStringWithTimeStamps:(BOOL)timeStamps; + +- (void)_hideSelectShowStatements:(BOOL)show; +- (void)_filterConsoleUsingSearchString:(NSString *)string; +- (void)_addMessageToConsole:(NSString *)message isError:(BOOL)error; @end +static SPQueryConsole *sharedQueryConsole = nil; + @implementation SPQueryConsole -// ------------------------------------------------------------------------------- -// awakeFromNib -// -// Set the window's auto save name. -// ------------------------------------------------------------------------------- +@synthesize consoleFont; + +/* + * Returns the shared query console. + */ ++ (SPQueryConsole *)sharedQueryConsole +{ + @synchronized(self) { + if (sharedQueryConsole == nil) { + [[self alloc] init]; + } + } + + return sharedQueryConsole; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + @synchronized(self) { + if (sharedQueryConsole == nil) { + sharedQueryConsole = [super allocWithZone:zone]; + + return sharedQueryConsole; + } + } + + return nil; // On subsequent allocation attempts return nil +} + +- (id)init +{ + if ((self = [super initWithWindowNibName:@"Console"])) { + messages = [[NSMutableArray alloc] init]; + messagesSubset = [[NSMutableArray alloc] init]; + messagesFilterSet = [[NSMutableArray alloc] init]; + + // Weak reference + messagesActiveSet = messages; + messagesFilterSet = messagesActiveSet; + } + + return self; +} + +/* + * The following base protocol methods are implemented to ensure the singleton status of this class. + */ + +- (id)copyWithZone:(NSZone *)zone { return self; } + +- (id)retain { return self; } + +- (unsigned)retainCount { return UINT_MAX; } + +- (id)autorelease { return self; } + +- (void)release { } + +/** + * Set the window's auto save name. + */ - (void)awakeFromNib { [self setWindowFrameAutosaveName:CONSOLE_WINDOW_AUTO_SAVE_NAME]; } -// ------------------------------------------------------------------------------- -// clearConsole: -// -// Clears the console by setting its displayed text to an empty string. -// ------------------------------------------------------------------------------- +/** + * Copy implementation for console table view. + */ +- (void)copy:(id)sender +{ + NSResponder *firstResponder = [[self window] firstResponder]; + + if ((firstResponder == consoleTableView) && ([consoleTableView numberOfSelectedRows] > 0)) { + + NSString *string = @""; + NSIndexSet *rows = [consoleTableView selectedRowIndexes]; + + NSUInteger i = [rows firstIndex]; + + while (i != NSNotFound) + { + if (i < [messagesFilterSet count]) { + SPConsoleMessage *message = [messagesFilterSet objectAtIndex:i]; + + NSString *consoleMessage = [message message]; + + // If the timestamp column is not hidden we need to include them in the copy + if (![[consoleTableView tableColumnWithIdentifier:TABLEVIEW_DATE_COLUMN_IDENTIFIER] isHidden]) { + + NSString *dateString = [[message messageDate] descriptionWithCalendarFormat:MESSAGE_TIME_STAMP_FORMAT timeZone:nil locale:nil]; + + consoleMessage = [NSString stringWithFormat:@"/* MySQL %@ */ %@", dateString, consoleMessage]; + } + + string = [string stringByAppendingFormat:@"%@\n", consoleMessage]; + } + + i = [rows indexGreaterThanIndex:i]; + } + + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + + // Copy the string to the pasteboard + [pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil]; + [pasteBoard setString:string forType:NSStringPboardType]; + } +} + +/** + * Clears the console by removing all of its messages. + */ - (IBAction)clearConsole:(id)sender { - [consoleTextView setString:@""]; + [messages removeAllObjects]; + + [consoleTableView reloadData]; } -// ------------------------------------------------------------------------------- -// saveConsoleAs: -// -// Presents the user with a save panel to the save the current console to a log file. -// ------------------------------------------------------------------------------- +/** + * Presents the user with a save panel to the save the current console to a log file. + */ - (IBAction)saveConsoleAs:(id)sender { NSSavePanel *panel = [NSSavePanel savePanel]; @@ -70,6 +181,9 @@ [panel setAllowsOtherFileTypes:YES]; [panel setCanSelectHiddenExtension:YES]; + [panel setAccessoryView:saveLogView]; + + [panel beginSheetForDirectory:nil file:DEFAULT_CONSOLE_LOG_FILENAME modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; [panel beginSheetForDirectory:nil file:DEFAULT_CONSOLE_LOG_FILENAME modalForWindow:[self window] @@ -78,75 +192,273 @@ contextInfo:NULL]; } -// ------------------------------------------------------------------------------- -// showMessageInConsole: -// -// Shows the supplied message in the console. -// ------------------------------------------------------------------------------- -- (void)showMessageInConsole:(NSString *)message +/** + * Toggles the display of the message time stamp column in the table view. + */ +- (IBAction)toggleShowTimeStamps:(id)sender { - [self _appendMessageToConsole:message withColor:[NSColor blackColor]]; + [[consoleTableView tableColumnWithIdentifier:TABLEVIEW_DATE_COLUMN_IDENTIFIER] setHidden:(![sender intValue])]; } -// ------------------------------------------------------------------------------- -// showErrorInConsole: -// -// Shows the supplied error in the console. -// ------------------------------------------------------------------------------- -- (void)showErrorInConsole:(NSString *)error +/** + * Toggles the hiding of messages containing SELECT and SHOW statements + */ +- (IBAction)toggleShowSelectShowStatements:(id)sender { - [self _appendMessageToConsole:error withColor:[NSColor redColor]]; + [self _hideSelectShowStatements:(![sender intValue])]; } -// ------------------------------------------------------------------------------- -// consoleTextView -// -// Return a reference to the console's text view. -// ------------------------------------------------------------------------------- -- (NSTextView *)consoleTextView +/** + * Shows the supplied message in the console. + */ +- (void)showMessageInConsole:(NSString *)message { - return consoleTextView; + [self _addMessageToConsole:message isError:NO]; } -// ------------------------------------------------------------------------------- -// savePanelDidEnd:returnCode:contextInfo: -// -// Called when the NSSavePanel sheet ends. -// ------------------------------------------------------------------------------- +/** + * Shows the supplied error in the console. + */ +- (void)showErrorInConsole:(NSString *)error +{ + [self _addMessageToConsole:error isError:YES]; +} + +/** + * Called when the NSSavePanel sheet ends. Writes the console's current content to the selected file if required. + */ - (void)savePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { if (returnCode == NSOKButton) { - [[[consoleTextView textStorage] string] writeToFile:[sheet filename] atomically:YES encoding:NSUTF8StringEncoding error:NULL]; + [[self _getConsoleStringWithTimeStamps:[includeTimeStampsButton intValue]] writeToFile:[sheet filename] atomically:YES encoding:NSUTF8StringEncoding error:NULL]; } } +#pragma mark - +#pragma mark Tableview delegate methods + +/** + * Table view delegate method. Returns the number of rows in the table veiw. + */ +- (int)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [messagesFilterSet count]; +} + +/** + * Table view delegate method. Returns the specific object for the request column and row. + */ +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSUInteger)row +{ + NSString *returnValue = nil; + + id object = [[messagesFilterSet objectAtIndex:row] valueForKey:[tableColumn identifier]]; + + if ([[tableColumn identifier] isEqualToString:TABLEVIEW_DATE_COLUMN_IDENTIFIER]) { + + NSString *dateString = [(NSDate *)object descriptionWithCalendarFormat:MESSAGE_TIME_STAMP_FORMAT timeZone:nil locale:nil]; + + returnValue = [NSString stringWithFormat:@"/* MySQL %@ */", dateString]; + } + 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 *)[messagesFilterSet 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]; +} + +#pragma mark - +#pragma mark Other + +/** + * Called whenver the test within the search field changes. + */ +- (void)controlTextDidChange:(NSNotification *)notification +{ + id object = [notification object]; + + if ([object isEqualTo:consoleSearchField]) { + [self _filterConsoleUsingSearchString:[[object stringValue] lowercaseString]]; + } +} + +/** + * Menu item validation for console table view contextual menu. + */ +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem +{ + BOOL validate = NO; + + if ([menuItem action] == @selector(copy:)) { + validate = ([consoleTableView numberOfSelectedRows] > 0); + } + + return validate; +} + +/** + * Standard dealloc. + */ +- (void)dealloc +{ + messagesSubset = nil; + + [messages release], messages = nil; + [messagesSubset release], messagesSubset = nil; + [messagesFilterSet release], messagesFilterSet = nil; + + [super dealloc]; +} + @end @implementation SPQueryConsole (PrivateAPI) -// ------------------------------------------------------------------------------- -// _appendMessageToConsole:withColor: -// -// Appeds the supplied string to the query console, coloring the text using the -// supplied color. -// ------------------------------------------------------------------------------- -- (void)_appendMessageToConsole:(NSString *)message withColor:(NSColor *)color +/** + * Creates and returns a string made entirely of all of the console's messages and includes the message + * time stamps if specified. + */ +- (NSString *)_getConsoleStringWithTimeStamps:(BOOL)timeStamps { - int begin, end; + NSMutableString *consoleString = [[[NSMutableString alloc] init] autorelease]; - // Set the selected range of the text view to be the very last character - [consoleTextView setSelectedRange:NSMakeRange([[consoleTextView string] length], 0)]; - begin = [[consoleTextView string] length]; + for (SPConsoleMessage *message in messagesFilterSet) + { + if (timeStamps) { + NSString *dateString = [[message messageDate] descriptionWithCalendarFormat:MESSAGE_TIME_STAMP_FORMAT timeZone:nil locale:nil]; + + [consoleString appendString:[NSString stringWithFormat:@"/* MySQL %@ */ ", dateString]]; + } + + [consoleString appendString:[NSString stringWithFormat:@"%@\n", [message message]]]; + } + + return consoleString; +} + +/** + * Either hides or shows all SELECT and SHOW statements within the console. + */ +- (void)_hideSelectShowStatements:(BOOL)show +{ + if (!show) { + messagesActiveSet = messages; + messagesFilterSet = messagesActiveSet; + + [consoleTableView reloadData]; + + return; + } + + messagesActiveSet = [messages mutableCopy]; + + // Filter out messages that have a prefix of either SELECT or SHOW + for (SPConsoleMessage *message in messages) + { + if ([[message message] hasPrefix:@"SELECT"] || [[message message] hasPrefix:@"SHOW"]) { + [messagesActiveSet removeObject:message]; + } + } + + messagesFilterSet = messagesActiveSet; + + [consoleTableView reloadData]; +} + +/** + * Filters the messages array using the supplued search string. + */ +- (void)_filterConsoleUsingSearchString:(NSString *)searchString +{ + // Display start progress spinner + [progressIndicator setHidden:NO]; + [progressIndicator startAnimation:self]; - // Apped the message to the current text storage using the text view's current typing attributes - [[consoleTextView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:message attributes:[consoleTextView typingAttributes]]]; - end = [[consoleTextView string] length]; + // Don't allow clearing the console while filtering its content + [saveConsoleButton setEnabled:NO]; + [clearConsoleButton setEnabled:NO]; - // Color the text we just added - [consoleTextView setTextColor:color range:NSMakeRange(begin, (end - begin))]; + [saveConsoleButton setTitle:@"Save View As..."]; + + // If there's no search string assign the active messages array back to the message array + if ([searchString length] == 0) { + [messagesFilterSet removeAllObjects]; + + messagesFilterSet = messagesActiveSet; + + [consoleTableView reloadData]; + [consoleTableView scrollRowToVisible:([messagesFilterSet count] - 1)]; + + [saveConsoleButton setEnabled:YES]; + [clearConsoleButton setEnabled:YES]; + + [saveConsoleButton setTitle:@"Save As..."]; + + // Display start progress spinner + [progressIndicator setHidden:YES]; + [progressIndicator stopAnimation:self]; + + return; + } + + // Remove all objects in the subset + [messagesSubset removeAllObjects]; + + // Filter the messages + for (SPConsoleMessage *message in messagesActiveSet) + { + if ([[message message] rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound) { + [messagesSubset addObject:message]; + } + } + + messagesFilterSet = messagesSubset; + + [consoleTableView reloadData]; + [consoleTableView scrollRowToVisible:([messagesFilterSet count] - 1)]; + + if ([messagesFilterSet count] > 0) { + [saveConsoleButton setEnabled:YES]; + } + + // Display start progress spinner + [progressIndicator setHidden:YES]; + [progressIndicator stopAnimation:self]; +} - // Scroll to the text we just added - [consoleTextView scrollRangeToVisible:[consoleTextView selectedRange]]; +/** + * Adds the supplied message to the query console. + */ +- (void)_addMessageToConsole:(NSString *)message isError:(BOOL)error +{ + SPConsoleMessage *consoleMessage = [SPConsoleMessage consoleMessageWithMessage:[[message stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] stringByAppendingString:@";"] date:[NSDate date]]; + + [consoleMessage setIsError:error]; + + [messages addObject:consoleMessage]; + + [consoleTableView reloadData]; + [consoleTableView scrollRowToVisible:([messages count] - 1)]; } @end diff --git a/Source/SPStringAdditions.m b/Source/SPStringAdditions.m index a26a878e..74c98b4f 100644 --- a/Source/SPStringAdditions.m +++ b/Source/SPStringAdditions.m @@ -24,11 +24,9 @@ @implementation NSString (SPStringAdditions) -// ------------------------------------------------------------------------------- -// stringForByteSize: -// -// Returns a human readable version string of the supplied byte size. -// ------------------------------------------------------------------------------- +/* + * Returns a human readable version string of the supplied byte size. + */ + (NSString *)stringForByteSize:(int)byteSize { float size = byteSize; @@ -139,36 +137,36 @@ } #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 - // ------------------------------------------------------------------------------- - // componentsSeparatedByCharactersInSet: - // Credit - Greg Hulands <ghulands@mac.com> - // Needed for 10.4+ compatibility - // ------------------------------------------------------------------------------- - - (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)set // 10.5 adds this to NSString, but we are 10.4+ - { - NSMutableArray *result = [NSMutableArray array]; - NSScanner *scanner = [NSScanner scannerWithString:self]; - NSString *chunk = nil; - - [scanner setCharactersToBeSkipped:nil]; - BOOL sepFound = [scanner scanCharactersFromSet:set intoString:(NSString **)nil]; // skip any preceding separators - - if (sepFound) { // if initial separator, start with empty component - [result addObject:@""]; - } - - while ([scanner scanUpToCharactersFromSet:set intoString:&chunk]) { - [result addObject:chunk]; - sepFound = [scanner scanCharactersFromSet: set intoString: (NSString **) nil]; - } - - if (sepFound) { // if final separator, end with empty component - [result addObject: @""]; - } - - result = [result copy]; - return [result autorelease]; +/* + * componentsSeparatedByCharactersInSet: + * Credit - Greg Hulands <ghulands@mac.com> + * Needed for 10.4+ compatibility + */ +- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)set // 10.5 adds this to NSString, but we are 10.4+ +{ + NSMutableArray *result = [NSMutableArray array]; + NSScanner *scanner = [NSScanner scannerWithString:self]; + NSString *chunk = nil; + + [scanner setCharactersToBeSkipped:nil]; + BOOL sepFound = [scanner scanCharactersFromSet:set intoString:(NSString **)nil]; // skip any preceding separators + + if (sepFound) { // if initial separator, start with empty component + [result addObject:@""]; + } + + while ([scanner scanUpToCharactersFromSet:set intoString:&chunk]) { + [result addObject:chunk]; + sepFound = [scanner scanCharactersFromSet: set intoString: (NSString **) nil]; } + + if (sepFound) { // if final separator, end with empty component + [result addObject: @""]; + } + + result = [result copy]; + return [result autorelease]; +} #endif @end diff --git a/Source/TableContent.h b/Source/TableContent.h index f18659a0..644a6b86 100644 --- a/Source/TableContent.h +++ b/Source/TableContent.h @@ -25,16 +25,14 @@ #import <Cocoa/Cocoa.h> #import <MCPKit_bundled/MCPKit_bundled.h> -#import "CMCopyTable.h" -#import "CMMCPConnection.h" -#import "CMMCPResult.h" + +@class CMMCPConnection, CMMCPResult, CMCopyTable; @interface TableContent : NSObject { IBOutlet id tableDocumentInstance; IBOutlet id tablesListInstance; IBOutlet id tableDataInstance; - IBOutlet id queryConsoleInstance; IBOutlet id tableWindow; IBOutlet CMCopyTable *tableContentView; diff --git a/Source/TableContent.m b/Source/TableContent.m index 134e5234..0a474998 100644 --- a/Source/TableContent.m +++ b/Source/TableContent.m @@ -27,6 +27,9 @@ #import "TableDocument.h" #import "TablesList.h" #import "CMImageView.h" +#import "CMCopyTable.h" +#import "CMMCPConnection.h" +#import "CMMCPResult.h" #import "SPDataCellFormatter.h" #import "SPTableData.h" #import "SPQueryConsole.h" @@ -47,7 +50,7 @@ sortField = nil; areShowingAllRows = false; currentlyEditingRow = -1; - + return self; } @@ -1264,7 +1267,7 @@ isEditingRow = NO; isEditingNewRow = NO; currentlyEditingRow = -1; - [queryConsoleInstance showErrorInConsole:[NSString stringWithFormat:NSLocalizedString(@"/* WARNING %@ No rows have been affected */\n", @"warning shown in the console when no rows have been affected after writing to the db"), currentTime]]; + [[SPQueryConsole sharedQueryConsole] showErrorInConsole:[NSString stringWithFormat:NSLocalizedString(@"/* WARNING %@ No rows have been affected */\n", @"warning shown in the console when no rows have been affected after writing to the db"), currentTime]]; return YES; // On success... diff --git a/Source/TableDocument.h b/Source/TableDocument.h index 7227f0dd..c2d37910 100644 --- a/Source/TableDocument.h +++ b/Source/TableDocument.h @@ -25,8 +25,8 @@ #import <Cocoa/Cocoa.h> #import <MCPKit_bundled/MCPKit_bundled.h> -#import "CMMCPConnection.h" -#import "CMMCPResult.h" + +@class CMMCPConnection, CMMCPResult; /** * The TableDocument class controls the primary database view window. @@ -42,7 +42,6 @@ IBOutlet id tableDumpInstance; IBOutlet id tableDataInstance; IBOutlet id tableStatusInstance; - IBOutlet id queryConsoleInstance; IBOutlet id tableWindow; IBOutlet id connectSheet; diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 2bb95ef4..0be640ec 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -37,6 +37,9 @@ #import "SPSQLParser.h" #import "SPTableData.h" #import "SPStringAdditions.h" +#import "SPQueryConsole.h" +#import "CMMCPConnection.h" +#import "CMMCPResult.h" NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocumentFavoritesControllerSelectionIndexDidChange"; NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFavoritesControllerFavoritesDidChange"; @@ -51,7 +54,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa _encoding = [@"utf8" retain]; chooseDatabaseButton = nil; chooseDatabaseToolbarItem = nil; - + return self; } @@ -600,7 +603,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa */ - (void)toggleConsole:(id)sender { - [[queryConsoleInstance window] setIsVisible:![[queryConsoleInstance window] isVisible]]; + [[[SPQueryConsole sharedQueryConsole] window] setIsVisible:![[[SPQueryConsole sharedQueryConsole] window] isVisible]]; } #pragma mark Encoding Methods @@ -1301,7 +1304,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa //set up tooltip and image [toolbarItem setToolTip:NSLocalizedString(@"Show or hide the console which shows all MySQL commands performed by Sequel Pro", @"tooltip for toolbar item for show/hide console")]; - if ([[queryConsoleInstance window] isVisible]) { + if ([[[SPQueryConsole sharedQueryConsole] window] isVisible]) { [toolbarItem setLabel:NSLocalizedString(@"Hide Console", @"toolbar item for hide console")]; [toolbarItem setImage:[NSImage imageNamed:@"hideconsole"]]; } else { @@ -1321,7 +1324,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa [toolbarItem setToolTip:NSLocalizedString(@"Clear the console which shows all MySQL commands performed by Sequel Pro", @"tooltip for toolbar item for clear console")]; [toolbarItem setImage:[NSImage imageNamed:@"clearconsole"]]; //set up the target action - [toolbarItem setTarget:queryConsoleInstance]; + [toolbarItem setTarget:[SPQueryConsole sharedQueryConsole]]; [toolbarItem setAction:@selector(clearConsole:)]; } else if ([itemIdentifier isEqualToString:@"SwitchToTableStructureToolbarItemIdentifier"]) { @@ -1425,7 +1428,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa - (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem; { if ([[toolbarItem itemIdentifier] isEqualToString:@"ToggleConsoleIdentifier"]) { - if ([[queryConsoleInstance window] isVisible]) { + if ([[[SPQueryConsole sharedQueryConsole] window] isVisible]) { [toolbarItem setLabel:@"Hide Console"]; [toolbarItem setImage:[NSImage imageNamed:@"hideconsole"]]; } else { @@ -1447,11 +1450,11 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa return @"DBView"; } -- (void)windowControllerDidLoadNib:(NSWindowController *) aController -/* - code that need to be executed once the windowController has loaded the document's window - sets upt the interface (small fonts) +/** + * Code that need to be executed once the windowController has loaded the document's window + * sets upt the interface (small fonts). */ +- (void)windowControllerDidLoadNib:(NSWindowController *) aController { [aController setShouldCascadeWindows:YES]; [super windowControllerDidLoadNib:aController]; @@ -1459,8 +1462,6 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa NSEnumerator *theCols = [[variablesTableView tableColumns] objectEnumerator]; NSTableColumn *theCol; - // [tableWindow makeKeyAndOrderFront:self]; - prefs = [[NSUserDefaults standardUserDefaults] retain]; //register for notifications @@ -1473,14 +1474,14 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa //set up interface if ( [prefs boolForKey:@"useMonospacedFonts"] ) { - [[queryConsoleInstance consoleTextView] setFont:[NSFont fontWithName:@"Monaco" size:[NSFont smallSystemFontSize]]]; + [[SPQueryConsole sharedQueryConsole] setConsoleFont:[NSFont fontWithName:@"Monaco" size:[NSFont smallSystemFontSize]]]; [syntaxViewContent setFont:[NSFont fontWithName:@"Monaco" size:[NSFont smallSystemFontSize]]]; while ( (theCol = [theCols nextObject]) ) { [[theCol dataCell] setFont:[NSFont fontWithName:@"Monaco" size:10]]; } } else { - [[queryConsoleInstance consoleTextView] setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; + [[SPQueryConsole sharedQueryConsole] setConsoleFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [syntaxViewContent setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; while ( (theCol = [theCols nextObject]) ) { [[theCol dataCell] setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; @@ -1503,11 +1504,10 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa [self setPrintInfo:[NSPrintInfo sharedPrintInfo]]; if ([mySQLConnection isConnected]) [self closeConnection]; - if ([[queryConsoleInstance window] isVisible]) [self toggleConsole:self]; + if ([[[SPQueryConsole sharedQueryConsole] window] isVisible]) [self toggleConsole:self]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } - //NSWindow delegate methods - (BOOL)windowShouldClose:(id)sender /* @@ -1527,22 +1527,19 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa * Invoked when framework will perform a query */ - (void)willQueryString:(NSString *)query -{ - NSString *currentTime = [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil]; - - [queryConsoleInstance showMessageInConsole:[NSString stringWithFormat:@"/* MySQL %@ */ %@;\n", currentTime, query]]; +{ + [[SPQueryConsole sharedQueryConsole] showMessageInConsole:query]; } /** * Invoked when query gave an error */ - (void)queryGaveError:(NSString *)error -{ - NSString *currentTime = [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil]; - - [queryConsoleInstance showErrorInConsole:[NSString stringWithFormat:@"/* ERROR %@ */ %@;\n", currentTime, error]]; +{ + [[SPQueryConsole sharedQueryConsole] showErrorInConsole:error]; } +#pragma mark - #pragma mark Connection sheet delegate methods /** |